You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/RC/ResourceCompiler/ListFile.cpp

309 lines
8.8 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompiler_precompiled.h"
#include "ListFile.h"
#include "StringHelpers.h"
#include "TempFilePakExtraction.h"
#include "PathHelpers.h"
#include "IPakSystem.h"
#include "IResCompiler.h"
#include "IRCLog.h"
//////////////////////////////////////////////////////////////////////////
CListFile::CListFile(IResourceCompiler* pRC)
: m_pRC(pRC)
{
}
//////////////////////////////////////////////////////////////////////////
bool CListFile::Process(
const string& listFile,
const string& formatList,
const string& wildcardList,
const string& defaultFolder,
std::vector< std::pair<string, string> >& outFiles)
{
std::vector<string> wildcards;
StringHelpers::Split(wildcardList, ";", false, wildcards);
for (size_t i = 0; i < wildcards.size(); ++i)
{
wildcards[i] = PathHelpers::ToPlatformPath(wildcards[i]);
}
std::vector<string> formats;
StringHelpers::Split(formatList, ";", false, formats);
for (size_t i = 0; i < formats.size(); ++i)
{
formats[i] = PathHelpers::ToPlatformPath(formats[i]);
}
if (formats.empty())
{
formats.push_back("{0}");
}
if (!listFile.empty() && listFile[0] == '@')
{
int splitter = listFile.find_first_of("|;,");
if (splitter < 0)
{
return false;
}
string zipFilename = listFile.substr(1, splitter - 1);
string listFilename = listFile.substr(splitter + 1);
zipFilename.Trim();
listFilename.Trim();
ParseListFileInZip(zipFilename, listFilename, formats, wildcards, defaultFolder, outFiles);
return true;
}
// Parse List File.
std::vector<string> lines;
if (!ReadLines(listFile, lines))
{
return false;
}
for (size_t i = 0; i < lines.size(); ++i)
{
string line = lines[i];
// Line can either contain filename, folder & filename
// or a zip file + list file (ex: @Levels\AlienVessel\Level.pak|resourcelist.txt)
if (line[0] == '@')
{
// the line starts with '@' character, this means a zip file
line = line.substr(1); // erase @ character
const size_t splitter = line.find_first_of("|;,");
if (splitter == line.npos)
{
continue;
}
string zipFilename = line.substr(0, splitter);
string listFilename = line.substr(splitter + 1);
zipFilename.Trim();
listFilename.Trim();
ParseListFileInZip(zipFilename, listFilename, formats, wildcards, defaultFolder, outFiles);
}
else
{
if (!ProcessLine(line, formats, wildcards, defaultFolder, outFiles))
{
return false;
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void CListFile::ParseListFileInZip(
const string& zipFilename,
const string& listFilename,
const std::vector<string>& formats,
const std::vector<string>& wildcards,
const string& defaultFolder,
std::vector< std::pair<string, string> >& outFiles)
{
// Open zip file
IPakSystem* const pPakSystem = m_pRC->GetPakSystem();
const char* const pTempPath = m_pRC->GetTmpPath();
const string sFileInPak = string("@") + zipFilename + "|" + listFilename;
TempFilePakExtraction fileProxy(sFileInPak.c_str(), pTempPath, pPakSystem);
// Parse List File.
std::vector<string> lines;
if (!ReadLines(fileProxy.GetTempName(), lines))
{
RCLogWarning("List file %s not found in zip file %s", listFilename.c_str(), zipFilename.c_str());
return;
}
for (size_t i = 0; i < lines.size(); ++i)
{
if (!ProcessLine(lines[i], formats, wildcards, defaultFolder, outFiles))
{
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
bool CListFile::ProcessLine(
const string& line,
const std::vector<string>& formats,
const std::vector<string>& wildcards,
const string& defaultFolder,
std::vector< std::pair<string, string> >& outFiles)
{
string folderName;
string fileName;
{
// Line can either contain filename (in quotes or without them) or folder & filename (both in quotes).
const char* p0 = strchr(line.c_str(), '\"');
const char* p1 = (p0 ? strchr(p0 + 1, '\"') : 0);
const char* p2 = (p1 ? strchr(p1 + 1, '\"') : 0);
const char* p3 = (p2 ? strchr(p2 + 1, '\"') : 0);
if (p0 == 0)
{
// single filename without quotes
folderName = defaultFolder;
fileName = line;
}
else if (p1 && (p2 == 0))
{
// single filename in quotes
folderName = defaultFolder;
fileName = string(p0 + 1, p1);
}
else if (p3)
{
// folder & filename in quotes
folderName = string(p0 + 1, p1);
fileName = string(p2 + 1, p3);
}
else
{
RCLogError("Bad syntax of a row in list file");
return false;
}
}
if (fileName.empty())
{
RCLogError("Filename is empty in a row of list file");
return false;
}
fileName = PathHelpers::ToPlatformPath(fileName);
folderName = PathHelpers::ToPlatformPath(folderName);
std::vector<string> tokens;
{
bool bMatchFound = false;
for (size_t i = 0; i < wildcards.size(); ++i)
{
if (StringHelpers::MatchesWildcardsIgnoreCase(fileName, wildcards[i]))
{
if (!StringHelpers::MatchesWildcardsIgnoreCaseExt(fileName, wildcards[i], tokens))
{
RCLogError("Unexpected failure in %s", __FUNCTION__);
return false;
}
bMatchFound = true;
break;
}
}
if (!bMatchFound)
{
return true;
}
}
for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
{
string str = formats[formatIndex];
size_t scanFromPos = 0;
for (;; )
{
const size_t startPos = str.find('{', scanFromPos);
if (startPos == str.npos)
{
break;
}
const size_t endPos = str.find('}', startPos + 1);
if (endPos == str.npos)
{
break;
}
const string indexStr = str.substr(startPos + 1, endPos - startPos - 1);
bool bBadSyntax = indexStr.empty();
for (size_t i = 0; i < indexStr.length(); ++i)
{
if (!isdigit(indexStr[i]))
{
bBadSyntax = true;
}
}
if (bBadSyntax)
{
RCLogError("Syntax error in element {%s} in input string %s", indexStr.c_str(), formats[formatIndex].c_str());
return false;
}
const int index = atoi(indexStr.c_str());
if ((index < 0) || (index > tokens.size()))
{
RCLogError("Bad index specified in {%s} in input string %s", indexStr.c_str(), formats[formatIndex].c_str());
return false;
}
const string& replaceWith = (index == 0) ? fileName : tokens[index - 1];
str = str.replace(startPos, endPos - startPos + 1, replaceWith);
scanFromPos = startPos + replaceWith.size();
}
outFiles.push_back(std::pair<string, string>(folderName, str));
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CListFile::ReadLines(
const string& listFile,
std::vector<string>& lines)
{
FILE* f = nullptr;
azfopen(&f, listFile, "rt");
if (!f)
{
return false;
}
char line[2048];
while (fgets(line, sizeof(line), f) != NULL)
{
if (line[0])
{
string strLine = line;
strLine.Trim();
if (!strLine.empty())
{
lines.push_back(strLine);
}
}
}
fclose(f);
return true;
}