/* * 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 "stdafx.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; }