Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,114 @@
/*
* 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.
*
*/
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ASSETFILEINFO_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ASSETFILEINFO_H
#pragma once
#include <cstring> // memset()
#include "SimpleString.h"
class CAssetFileInfo
{
public:
enum
{
kMaxCgfLods = 6
};
enum EType
{
eUnknown,
eTexture,
eCGF,
eCHR,
eCAF,
eLUA
};
struct TextureInfo
{
int w;
int h;
bool bAlpha;
SimpleString format;
SimpleString type;
int nNumMips;
int nDepth;
int nSides;
};
struct GeometryInfo
{
int nVertices;
int nIndices;
int nIndicesPerLod[kMaxCgfLods];
int nMeshSizePerLod[kMaxCgfLods];
int nMeshSize;
int nPhysProxySize;
int nPhysTriCount;
int nPhysProxyCount;
int nLods;
int nSubMeshCount;
int nJoints;
bool bSplitLods;
};
struct SourceControl
{
bool bValid;
SimpleString user;
SimpleString user_email;
SimpleString user_fullname;
SimpleString workspace;
SimpleString depotFile;
SimpleString changeDescription;
int change;
int revision;
int time;
};
public:
EType m_type;
int64 m_SrcFileSize;
int64 m_DstFileSize;
SimpleString m_sInfo; // separated list of properties (used for excel export)
SimpleString m_sSourceFilename;
SimpleString m_sDestFilename;
SimpleString m_sPreset;
SimpleString m_sErrorLog;
bool m_bSuccess;
bool m_bGetSourceControlInfo;
bool m_bReferencedInLevels;
TextureInfo m_textureInfo;
GeometryInfo m_geomInfo;
SourceControl m_sc;
public:
CAssetFileInfo()
{
memset(this, 0, sizeof(*this));
m_type = eUnknown;
m_bSuccess = true;
m_bGetSourceControlInfo = true;
}
template <class T>
void SafeStrCopy(T& to, const char* from)
{
to = from;
}
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ASSETFILEINFO_H
@@ -0,0 +1,95 @@
#
# 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.
#
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
ly_add_target(
NAME ResourceCompiler.Static STATIC
NAMESPACE Legacy
FILES_CMAKE
resourcecompiler_static_files.cmake
Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PUBLIC
PCH
.
..
BUILD_DEPENDENCIES
PUBLIC
3rdParty::Qt::Widgets
Legacy::CryCommonTools
Legacy::CryCommon
Legacy::CryCommonTools
Legacy::CryXML
AZ::AzToolsFramework
RUNTIME_DEPENDENCIES
Legacy::CryXML
)
ly_add_target(
NAME RC EXECUTABLE
NAMESPACE Legacy
OUTPUT_NAME rc
FILES_CMAKE
resourcecompiler_files.cmake
Platform/Common/${PAL_TRAIT_COMPILER_ID}/rc_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PRIVATE
Platform/${PAL_PLATFORM_NAME}
PUBLIC
.
BUILD_DEPENDENCIES
PRIVATE
Legacy::ResourceCompiler.Static
)
ly_add_source_properties(
SOURCES ResourceCompiler.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES ${LY_PAL_TOOLS_DEFINES}
)
set(file_targets RC)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME RC.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Legacy
FILES_CMAKE
resourcecompiler_test_files.cmake
Platform/Common/${PAL_TRAIT_COMPILER_ID}/rc_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
Legacy::ResourceCompiler.Static
AZ::AzFrameworkTestShared
)
ly_add_googletest(
NAME Legacy::RC.Tests
)
list(APPEND file_targets RC.Tests)
endif()
ly_add_target_files(
TARGETS
${file_targets}
FILES
${CMAKE_CURRENT_SOURCE_DIR}/../Config/rc/xmlfilter.txt
${CMAKE_CURRENT_SOURCE_DIR}/../Config/rc/rc.ini
)
+341
View File
@@ -0,0 +1,341 @@
/*
* 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 "CfgFile.h"
#include "Config.h"
#include "DebugLog.h"
#include "IRCLog.h"
//#define Log DebugLog
#define Log while (false)
CfgFile::CfgFile()
{
// Create empty section.
Section section;
section.name = "";
m_sections.push_back(section);
m_modified = false;
}
CfgFile::~CfgFile()
{
}
void CfgFile::Release()
{
delete this;
}
// Load configuration file.
bool CfgFile::Load(const string& fileName)
{
m_fileName = fileName;
m_modified = false;
FILE* file = nullptr;
azfopen(&file, fileName.c_str(), "rb");
if (!file)
{
RCLog("Can't open \"%s\"", fileName.c_str());
return false;
}
fseek(file, 0, SEEK_END);
int size = ftell(file);
fseek(file, 0, SEEK_SET);
// Read whole file to memory.
char* s = (char*)malloc(size + 1);
memset(s, 0, size + 1);
fread(s, 1, size, file);
LoadFromBuffer(s);
free(s);
fclose(file);
return true;
}
// Save configuration file, with the stored name in m_fileName
bool CfgFile::Save()
{
FILE* file = nullptr;
azfopen(&file, m_fileName.c_str(), "wb");
if (!file)
{
return(false);
}
// Loop on sections.
for (std::vector<Section>::iterator si = m_sections.begin(); si != m_sections.end(); si++)
{
Section& sec = *si;
if (sec.name != "")
{
fprintf(file, "[%s]\r\n", sec.name.c_str()); // section
}
for (std::list<Entry>::iterator it = sec.entries.begin(); it != sec.entries.end(); ++it)
{
if ((*it).key == "")
{
fprintf(file, "%s\r\n", (*it).value.c_str()); // comment
}
else
{
fprintf(file, "%s=%s\r\n", (*it).key.c_str(), (*it).value.c_str()); // key=value
}
}
}
fclose(file);
return(true);
}
void CfgFile::UpdateOrCreateEntry(const char* inszSection, const char* inszKey, const char* inszValue)
{
const int sectionIndex = FindSection(inszSection);
Section* const sec = &m_sections[(sectionIndex < 0) ? 0 : sectionIndex];
for (std::list<Entry>::iterator it = sec->entries.begin(); it != sec->entries.end(); ++it)
{
if (azstricmp(it->key.c_str(), inszKey) == 0) // Key found
{
if (!it->IsComment()) // update key
{
if (it->value == inszValue)
{
return;
}
it->value = inszValue;
m_modified = true;
return;
}
}
}
// Create new key
Entry entry;
entry.key = inszKey;
entry.value = inszValue;
sec->entries.push_back(entry);
m_modified = true;
}
void CfgFile::RemoveEntry(const char* inszSection, const char* inszKey)
{
const int sectionIndex = FindSection(inszSection);
Section* const sec = &m_sections[(sectionIndex < 0) ? 0 : sectionIndex];
for (std::list<Entry>::iterator it = sec->entries.begin(); it != sec->entries.end(); ++it)
{
if (azstricmp(it->key.c_str(), inszKey) == 0)
{
if (!it->IsComment())
{
sec->entries.erase(it);
return;
}
}
}
}
void CfgFile::LoadFromBuffer(const char* buf)
{
// Read entries from config string buffer.
Section* curr_section = &m_sections.front(); // Empty section.
while (*buf != '\0')
{
size_t count = 0;
// Find the first line terminator
while (buf[count] != '\0' && buf[count] != '\r' && buf[count] != '\n')
{
count++;
}
Entry entry;
entry.value = string(buf, count);
// Move buffer forward and skip any trailing line endings
buf += count;
while (*buf != '\0' && (*buf == '\r' || *buf == '\n'))
{
buf++;
}
Log("Parsing line: \"%s\"", entry.value.c_str());
bool isComment = entry.IsComment();
if (!isComment)
{
entry.value.Trim();
}
if (isComment || entry.value.empty())
{
Log(isComment ? "It's a comment" : "It's empty");
// Add this comment to current section.
curr_section->entries.push_back(entry);
continue;
}
// First check if the line is a section to avoid equal signs in the section name to cause incorrect parsing
if (entry.value[0] == '[' && entry.value[entry.value.size() - 1] == ']')
{
Section section;
section.name = entry.value.Mid(1, entry.value.size() - 2); // Remove braces.
Log("Section! name: %s", section.name.c_str());
m_sections.push_back(section);
// Set current section.
curr_section = &m_sections.back();
}
else
{
size_t splitter = entry.value.find('=');
if (splitter != string::npos)
{
Log("found splitter at %d", splitter);
entry.key = entry.value.Mid(0, splitter); // Before splitter is key name.
entry.value = entry.value.Mid(splitter + 1); // Everything after splitter is value string.
entry.key.Trim();
entry.value.Trim();
Log("Key: %s, Value: %s", entry.key.c_str(), entry.value.c_str());
// Add this entry to current section.
curr_section->entries.push_back(entry);
}
else
{
// Nameless value
curr_section->entries.push_back(entry);
}
}
}
}
void CfgFile::CopySectionKeysToConfig(const EConfigPriority ePri, int sectionIndex, const char* keySuffixes, IConfigSink* config) const
{
if (sectionIndex < 0 || sectionIndex >= m_sections.size())
{
return;
}
std::vector<string> suffixes;
if (keySuffixes)
{
StringHelpers::SplitByAnyOf(keySuffixes, ", ", false, suffixes);
}
const Section* const sec = &m_sections[sectionIndex];
for (std::list<Entry>::const_iterator it = sec->entries.begin(); it != sec->entries.end(); ++it)
{
const Entry& e = (*it);
if (e.IsComment())
{
continue;
}
const size_t delimiterPos = e.key.find(':');
if (delimiterPos == string::npos)
{
// The key has no suffix. Add key & value without any checks.
config->SetKeyValue(ePri, e.key.c_str(), e.value.c_str());
}
else
{
// The key has a suffix.
if (keySuffixes == 0)
{
// keySuffixes == 0 means that we must copy all keys, does not matter if they have
// suffix or not. Suffix (if exists) is preserved as part of the name of the key.
config->SetKeyValue(ePri, e.key.c_str(), e.value.c_str());
}
else
{
for (size_t i = 0; i < suffixes.size(); ++i)
{
if (azstricmp(suffixes[i].c_str(), e.key.c_str() + delimiterPos + 1) == 0)
{
// The key's suffix is same as a suffix in keySuffixes. We add key (without suffix!) and value.
config->SetKeyValue(ePri, e.key.substr(0, delimiterPos).c_str(), e.value.c_str());
break;
}
}
}
}
}
}
const char* CfgFile::GetSectionName(int sectionIndex) const
{
if ((sectionIndex < 0) || ((size_t)sectionIndex >= m_sections.size()))
{
return 0;
}
return(m_sections[sectionIndex].name.c_str());
}
int CfgFile::FindSection(const char* sectionName) const
{
for (size_t i = 0, count = m_sections.size(); i < count; ++i)
{
if (azstricmp(m_sections[i].name.c_str(), sectionName) == 0)
{
return (int)i;
}
}
return -1;
}
bool CfgFile::Entry::IsComment() const
{
const char* pBegin = value.c_str();
while (pBegin[0] == ' ' || pBegin[0] == '\t')
{
++pBegin;
}
// "//" comment
if (pBegin[0] == '/' && pBegin[1] == '/')
{
return true;
}
// ";" comment
if (pBegin[0] == ';')
{
return true;
}
// empty line (treat it as comment)
if (pBegin[0] == 0)
{
return true;
}
return false;
}
+71
View File
@@ -0,0 +1,71 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CFGFILE_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CFGFILE_H
#pragma once
#include "ICfgFile.h" // ICfgFile
#include <list>
enum EConfigPriority : uint32_t;
class Config;
/** Configuration file class.
Uses format similar to windows .ini files.
*/
class CfgFile
: public ICfgFile
{
public:
CfgFile();
virtual ~CfgFile();
//////////////////////////////////////////////////////////////////////////
// interface ICfgFile
virtual void Release();
virtual bool Load(const string& fileName);
virtual bool Save(void);
virtual void UpdateOrCreateEntry(const char* inszSection, const char* inszKey, const char* inszValue);
virtual void RemoveEntry(const char* inszSection, const char* inszKey);
virtual void CopySectionKeysToConfig(EConfigPriority ePri, int sectionIndex, const char* keySuffixes, IConfigSink* config) const;
virtual const char* GetSectionName(int sectionIndex) const;
virtual int FindSection(const char* sectionName) const;
//////////////////////////////////////////////////////////////////////////
private:
void LoadFromBuffer(const char* buf);
private:
// Config file entry structure, filled by readSection method.
struct Entry
{
string key; //!< keys (for comments this is "")
string value; //!< values and comments (with leading ; or //)
bool IsComment() const;
};
struct Section
{
string name; //!< Section name. The first one has the name "" and is used if no section was specified.
std::list<Entry> entries; //!< List of entries.
};
string m_fileName; //!< Configuration file name.
int m_modified; //!< Set to true if config file been modified.
std::vector<Section> m_sections; //!< List of sections in config file. (the first one has the name "" and is used if no section was specified)
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CFGFILE_H
@@ -0,0 +1,95 @@
/*
* 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 "CmdLine.h"
#include "Config.h"
//////////////////////////////////////////////////////////////////////////
static void AddParameterToConfig(Config* config, const char* parameter)
{
// Split on key/value pair
const string p = parameter;
const size_t splitterPos = p.find('=');
if (splitterPos != string::npos)
{
const string key = p.substr(0, splitterPos);
const string value = p.substr(splitterPos + 1);
if (!key.empty())
{
config->SetKeyValue(eCP_PriorityCmdline, key.c_str(), value.c_str());
}
}
else
{
config->SetKeyValue(eCP_PriorityCmdline, p.c_str(), "");
}
}
//////////////////////////////////////////////////////////////////////////
//Return true if the parameter is a file spec
/////////////////////////////////////////////////////////////////////////
static bool isValidFileSpecCheck(const string& path)
{
if (path[0] == '-')
{
return false;
}
//Since Macs can have '/' in the file paths check for '='
//to confirm that it is a file spec and not a config argument.
if (path[0] == '/')
{
const size_t equalPos = path.find('=');
if (equalPos != string::npos)
{
return false;
}
else
{
//You can have a config argument that does not have a '='. Use
//extension path to determine if it is a file spec.
return PathHelpers::FindExtension(path) != "";
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void CmdLine::Parse(const std::vector<string>& args, Config* config, string& fileSpec)
{
assert(config);
fileSpec.clear();
for (int i = 1; i < (int)args.size(); ++i)
{
const char* const parameter = args[i].c_str();
bool isValidFileSpec = isValidFileSpecCheck(string(parameter));
if (isValidFileSpec)
{
if (fileSpec.empty())
{
fileSpec = parameter;
}
}
else
{
AddParameterToConfig(config, parameter + 1);
}
}
}
+26
View File
@@ -0,0 +1,26 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CMDLINE_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CMDLINE_H
#pragma once
class Config;
// Command line parser
namespace CmdLine
{
void Parse(const std::vector<string>& args, Config* config, string& fileSpec);
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CMDLINE_H
+300
View File
@@ -0,0 +1,300 @@
/*
* 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 "Config.h"
#include "PropertyVars.h"
#include "StringHelpers.h"
#include "IRCLog.h"
//////////////////////////////////////////////////////////////////////////
Config::Config()
: m_pConfigKeyRegistry(0)
{
}
//////////////////////////////////////////////////////////////////////////
Config::~Config()
{
}
//////////////////////////////////////////////////////////////////////////
void Config::GetUnknownKeys(std::vector<string>& unknownKeys) const
{
unknownKeys.clear();
if (!m_pConfigKeyRegistry)
{
return;
}
const Map::const_iterator end = m_map.end();
for (Map::const_iterator it = m_map.begin(); it != end; ++it)
{
const char* const keyName = it->first.m_sKeyName.c_str();
if (!m_pConfigKeyRegistry->HasKeyRegistered(keyName))
{
unknownKeys.push_back(keyName);
}
}
}
//////////////////////////////////////////////////////////////////////////
void Config::SetConfigKeyRegistry(IConfigKeyRegistry* pConfigKeyRegistry)
{
m_pConfigKeyRegistry = pConfigKeyRegistry;
}
//////////////////////////////////////////////////////////////////////////
IConfigKeyRegistry* Config::GetConfigKeyRegistry() const
{
return m_pConfigKeyRegistry;
}
//////////////////////////////////////////////////////////////////////////
int Config::GetSum(const char* key) const
{
if (m_pConfigKeyRegistry)
{
m_pConfigKeyRegistry->VerifyKeyRegistration(key);
}
MapKey mapKey;
mapKey.m_sKeyName = key;
mapKey.m_eKeyPri = eCP_PriorityHighest;
const Map::const_iterator lowerBound = m_map.lower_bound(mapKey);
mapKey.m_eKeyPri = eCP_PriorityLowest;
const Map::const_iterator upperBound = m_map.upper_bound(mapKey);
int ret = 0;
for (Map::const_iterator it = lowerBound; it != upperBound; ++it)
{
const MapKey& foundMapKey = it->first;
if (!StringHelpers::EqualsIgnoreCase(foundMapKey.m_sKeyName, mapKey.m_sKeyName))
{
RCLogError("Unexpected failure in %s", __FUNCTION__);
break;
}
int localvalue;
if (azsscanf(it->second.c_str(), "%d", &localvalue) == 1)
{
ret += localvalue;
}
}
return ret;
}
//////////////////////////////////////////////////////////////////////////
bool Config::GetKeyValue(const char* const key, const char*& value, const int ePriMask) const
{
if (m_pConfigKeyRegistry)
{
m_pConfigKeyRegistry->VerifyKeyRegistration(key);
}
MapKey mapKey;
mapKey.m_sKeyName = key;
mapKey.m_eKeyPri = eCP_PriorityHighest;
const Map::const_iterator lowerBound = m_map.lower_bound(mapKey);
mapKey.m_eKeyPri = eCP_PriorityLowest;
const Map::const_iterator upperBound = m_map.upper_bound(mapKey);
for (Map::const_iterator it = lowerBound; it != upperBound; ++it)
{
const MapKey& foundMapKey = it->first;
if (ePriMask & foundMapKey.m_eKeyPri)
{
if (!StringHelpers::EqualsIgnoreCase(foundMapKey.m_sKeyName, mapKey.m_sKeyName))
{
RCLogError("Unexpected failure in %s", __FUNCTION__);
break;
}
value = it->second.c_str();
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void Config::AddConfig(const IConfig* inpConfig)
{
if (!inpConfig)
{
return;
}
const Config* const pConfig = inpConfig->GetInternalRepresentation();
if (!pConfig)
{
assert(0);
return;
}
const Map::const_iterator end = pConfig->m_map.end();
for (Map::const_iterator it = pConfig->m_map.begin(); it != end; ++it)
{
const MapKey& mapKey = it->first;
const string value = it->second;
SetKeyValue(mapKey.m_eKeyPri, mapKey.m_sKeyName.c_str(), value.c_str());
}
}
//////////////////////////////////////////////////////////////////////////
const Config* Config::GetInternalRepresentation() const
{
return this;
}
//////////////////////////////////////////////////////////////////////////
bool Config::HasKeyRegistered(const char* szKey) const
{
assert(szKey);
return m_pConfigKeyRegistry ? m_pConfigKeyRegistry->HasKeyRegistered(szKey) : false;
}
//////////////////////////////////////////////////////////////////////////
bool Config::HasKeyMatchingWildcards(const char* wildcards) const
{
if (!wildcards || !wildcards[0])
{
return false;
}
const string strWildcards(wildcards);
const Map::const_iterator end = m_map.end();
for (Map::const_iterator it = m_map.begin(); it != end; ++it)
{
if (StringHelpers::MatchesWildcardsIgnoreCase(it->first.m_sKeyName, strWildcards))
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void Config::Clear()
{
m_map.clear();
}
//////////////////////////////////////////////////////////////////////////
uint32 Config::ClearPriorityUsage(const int ePriMask)
{
uint32 dwRet = 0;
Map::const_iterator it = m_map.begin();
while (it != m_map.end())
{
Map::const_iterator itNext = it;
++itNext;
const MapKey& mapKey = it->first;
if (mapKey.m_eKeyPri & ePriMask)
{
m_map.erase(mapKey);
++dwRet;
}
it = itNext;
}
return dwRet;
}
//////////////////////////////////////////////////////////////////////////
uint32 Config::CountPriorityUsage(const int ePriMask) const
{
uint32 dwRet = 0;
const Map::const_iterator end = m_map.end();
for (Map::const_iterator it = m_map.begin(); it != end; ++it)
{
const MapKey& mapKey = it->first;
if (mapKey.m_eKeyPri == ePriMask)
{
++dwRet;
}
}
return dwRet;
}
//////////////////////////////////////////////////////////////////////////
void Config::SetKeyValue(const EConfigPriority ePri, const char* key, const char* value)
{
assert(Util::isPowerOfTwo(ePri));
if (!key || !key[0])
{
return;
}
MapKey mapKey;
mapKey.m_sKeyName = key;
mapKey.m_eKeyPri = ePri;
if (value == 0)
{
m_map.erase(mapKey);
}
else
{
m_map[mapKey] = value;
}
}
//////////////////////////////////////////////////////////////////////////
void Config::CopyToConfig(const EConfigPriority ePri, IConfigSink* pDestConfig) const
{
assert(Util::isPowerOfTwo(ePri));
const Map::const_iterator end = m_map.end();
for (Map::const_iterator it = m_map.begin(); it != end; ++it)
{
const MapKey& mapKey = it->first;
if (mapKey.m_eKeyPri == ePri)
{
pDestConfig->SetKeyValue(ePri, mapKey.m_sKeyName, it->second);
}
}
}
//////////////////////////////////////////////////////////////////////////
void Config::CopyToPropertyVars(CPropertyVars& properties) const
{
const Map::const_iterator end = m_map.end();
for (Map::const_iterator it = m_map.begin(); it != end; ++it)
{
const MapKey& mapKey = it->first;
properties.SetProperty(mapKey.m_sKeyName, it->second);
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CONFIG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CONFIG_H
#pragma once
#include "IConfig.h"
#include "StlUtils.h"
#include "StringHelpers.h"
class CPropertyVars;
/** Implementation of IConfig interface.
*/
class Config
: public IConfig
{
public:
Config();
virtual ~Config();
void SetConfigKeyRegistry(IConfigKeyRegistry* pConfigKeyRegistry);
IConfigKeyRegistry* GetConfigKeyRegistry() const;
// interface IConfigSink ------------------------------------------
virtual void SetKeyValue(EConfigPriority ePri, const char* key, const char* value);
// interface IConfig ----------------------------------------------
virtual void Release() { delete this; };
virtual const Config* GetInternalRepresentation() const;
virtual bool HasKeyRegistered(const char* key) const;
virtual bool HasKeyMatchingWildcards(const char* wildcards) const;
virtual bool GetKeyValue(const char* key, const char*& value, int ePriMask) const;
virtual int GetSum(const char* key) const;
virtual void GetUnknownKeys(std::vector<string>& unknownKeys) const;
virtual void AddConfig(const IConfig* inpConfig);
virtual void Clear();
virtual uint32 ClearPriorityUsage(int ePriMask);
virtual uint32 CountPriorityUsage(int ePriMask) const;
virtual void CopyToConfig(EConfigPriority ePri, IConfigSink* pDestConfig) const;
virtual void CopyToPropertyVars(CPropertyVars& properties) const;
private: // ---------------------------------------------------------------------
struct MapKey
{
string m_sKeyName;
EConfigPriority m_eKeyPri;
bool operator<(const MapKey& b) const
{
// sort by m_sKeyName
const int cmp = StringHelpers::CompareIgnoreCase(m_sKeyName, b.m_sKeyName);
if (cmp != 0)
{
return (cmp < 0);
}
// sort by m_eKeyPri (higher priority goes first)
return (m_eKeyPri > b.m_eKeyPri);
}
};
typedef std::map<MapKey, string> Map;
Map m_map;
IConfigKeyRegistry* m_pConfigKeyRegistry; // used to verify key registration
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CONFIG_H
@@ -0,0 +1,135 @@
/*
* 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.
#pragma once
#include "PathHelpers.h"
#include "string.h"
#include "IMultiplatformConfig.h"
#include "IResCompiler.h"
class IConfig;
// IConvertContext is a description of what and how should be processed by compiler
struct IConvertContext
{
virtual void SetConvertorExtension(const char* convertorExtension) = 0;
virtual void SetSourceFolder(const char* sourceFolder) = 0;
virtual void SetSourceFileNameOnly(const char* sourceFileNameOnly) = 0;
virtual void SetOutputFolder(const char* sOutputFolder) = 0;
virtual void SetRC(IResourceCompiler* pRC) = 0;
virtual void SetMultiplatformConfig(IMultiplatformConfig* pMultiConfig) = 0;
virtual void SetPlatformIndex(int platformIndex) = 0;
virtual void SetForceRecompiling(bool bForceRecompiling) = 0;
virtual void CopyTo(IConvertContext* context) = 0;
};
struct ConvertContext
: public IConvertContext
{
//////////////////////////////////////////////////////////////////////////
// Interface IConvertContext
virtual void SetConvertorExtension(const char* convertorExtension)
{
this->m_convertorExtension = convertorExtension;
}
virtual void SetSourceFolder(const char* sourceFolder)
{
this->m_sourceFolder = sourceFolder;
}
virtual void SetSourceFileNameOnly(const char* sourceFileNameOnly)
{
this->m_sourceFileNameOnly = sourceFileNameOnly;
}
virtual void SetOutputFolder(const char* sOutputFolder)
{
this->m_outputFolder = sOutputFolder;
}
virtual void SetRC(IResourceCompiler* pRC)
{
this->m_pRC = pRC;
}
virtual void SetMultiplatformConfig(IMultiplatformConfig* pMultiConfig)
{
this->m_multiConfig = pMultiConfig;
this->m_config = &pMultiConfig->getConfig();
this->m_platform = pMultiConfig->getActivePlatform();
}
virtual void SetPlatformIndex(int platformIndex)
{
this->m_platform = platformIndex;
m_multiConfig->setActivePlatform(platformIndex);
}
virtual void SetForceRecompiling(bool bForceRecompiling)
{
this->m_bForceRecompiling = bForceRecompiling;
}
virtual void CopyTo(IConvertContext* context)
{
context->SetConvertorExtension(m_convertorExtension);
context->SetSourceFolder(m_sourceFolder);
context->SetSourceFileNameOnly(m_sourceFileNameOnly);
context->SetOutputFolder(m_outputFolder);
context->SetRC(m_pRC);
context->SetMultiplatformConfig(m_multiConfig);
context->SetForceRecompiling(m_bForceRecompiling);
}
//////////////////////////////////////////////////////////////////////////
const string GetSourcePath() const
{
return PathHelpers::Join(m_sourceFolder, m_sourceFileNameOnly).c_str();
}
const string& GetOutputFolder() const
{
return m_outputFolder;
}
public:
// Convertor will assume that the source file has content matching this extension
// (the sourceFileNameOnly can have a different extension, say 'tmp').
string m_convertorExtension;
// Source file's folder.
string m_sourceFolder;
// Source file that needs to be converted, for example "test.tif".
// Contains filename only, the folder is stored in sourceFolder.
string m_sourceFileNameOnly;
// Pointer to resource compiler interface.
IResourceCompiler* m_pRC;
// Configuration settings.
IMultiplatformConfig* m_multiConfig;
// Platform to which file must be processed.
int m_platform;
// Platform's config.
const IConfig* m_config;
// true if compiler is requested to skip up-to-date checks
bool m_bForceRecompiling;
private:
// Output folder.
string m_outputFolder;
};
+37
View File
@@ -0,0 +1,37 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_DEBUGLOG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_DEBUGLOG_H
#pragma once
inline void DebugLog (const char* szFormat, ...)
{
FILE* f = nullptr;
azfopen(&f, "Rc.Debug.log", "wa");
if (!f)
{
return;
}
va_list args;
va_start (args, szFormat);
vfprintf (f, szFormat, args);
fprintf (f, "\n");
vprintf (szFormat, args);
printf ("\n");
va_end(args);
fclose (f);
}
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_DEBUGLOG_H
@@ -0,0 +1,218 @@
/*
* 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 "DependencyList.h"
#include "IRCLog.h"
#include "PathHelpers.h"
#include "StringHelpers.h"
#include <stdio.h> // FILE
CDependencyList::CDependencyList()
: m_bDuplicatesWereRemoved(true)
{
}
CDependencyList::CDependencyList(const CDependencyList& obj)
{
m_files = obj.m_files;
m_bDuplicatesWereRemoved = obj.m_bDuplicatesWereRemoved;
}
string CDependencyList::NormalizeFilename(const char* filename)
{
return PathHelpers::ToDosPath(PathHelpers::GetAbsoluteAsciiPath(string(filename)));
}
void CDependencyList::Add(const char* sInputFilename, const char* sOutputFilename)
{
SFile f;
f.inputFile = sInputFilename[0] ? NormalizeFilename(sInputFilename) : string();
f.outputFile = sOutputFilename[0] ? NormalizeFilename(sOutputFilename) : string();
m_files.push_back(f);
m_bDuplicatesWereRemoved = false;
}
void CDependencyList::RemoveDuplicates()
{
if (m_bDuplicatesWereRemoved)
{
return;
}
m_bDuplicatesWereRemoved = true;
if (m_files.size() <= 1)
{
return;
}
struct CompareLess
{
bool operator()(const SFile& left, const SFile& right) const
{
const int res = StringHelpers::Compare(left.inputFile, right.inputFile);
if (res != 0)
{
return res < 0;
}
return (StringHelpers::Compare(left.outputFile, right.outputFile) < 0);
}
};
struct CompareEqual
{
bool operator()(const SFile& left, const SFile& right) const
{
return
StringHelpers::Equals(left.inputFile, right.inputFile) &&
StringHelpers::Equals(left.outputFile, right.outputFile);
}
};
std::sort(m_files.begin(), m_files.end(), CompareLess());
std::vector<SFile>::iterator end = std::unique(m_files.begin(), m_files.end(), CompareEqual());
if (end != m_files.end())
{
m_files.erase(end, m_files.end());
}
}
void CDependencyList::RemoveInputFiles(const std::vector<string>& inputFilesToRemove)
{
if (m_files.empty())
{
return;
}
struct CompareLess
{
bool operator()(const SFile& left, const SFile& right) const
{
return (left.inputFile < right.inputFile);
}
};
std::sort(m_files.begin(), m_files.end(), CompareLess());
bool bDeleted = false;
const size_t count = inputFilesToRemove.size();
for (size_t i = 0; i < count; ++i)
{
SFile searchFile;
searchFile.inputFile = NormalizeFilename(inputFilesToRemove[i].c_str());
std::vector<SFile>::iterator it = std::lower_bound(m_files.begin(), m_files.end(), searchFile, CompareLess());
while (it != m_files.end())
{
if (!StringHelpers::Equals(it->inputFile, searchFile.inputFile))
{
break;
}
// Mark the entry for deleting
it->outputFile.clear();
++it;
bDeleted = true;
}
}
// Delete marked entries
if (bDeleted)
{
struct MatchEmptyOutputFile
{
bool operator()(const SFile& file) const
{
return file.outputFile.empty();
}
};
m_files.erase(std::remove_if(m_files.begin(), m_files.end(), MatchEmptyOutputFile()), m_files.end());
}
}
void CDependencyList::Save(const char* filename) const
{
FILE* file = nullptr;
azfopen(&file, filename, "wt");
if (!file)
{
RCLogError("Cannot write filelist '%s'", filename);
return;
}
for (size_t i = 0; i < m_files.size(); ++i)
{
fprintf(file, "%s=%s\n", m_files[i].inputFile.c_str(), m_files[i].outputFile.c_str());
}
fclose(file);
}
void CDependencyList::SaveOutputOnly(const char* filename) const
{
FILE* file = nullptr;
azfopen(&file, filename, "wt");
if (!file)
{
RCLogError("Cannot write filelist (output files only) '%s'", filename);
return;
}
for (size_t i = 0; i < m_files.size(); ++i)
{
fprintf(file, "%s\n", m_files[i].outputFile.c_str());
}
fclose(file);
}
void CDependencyList::Load(const char* filename)
{
FILE* file = nullptr;
azfopen(&file, filename, "rt");
if (!file)
{
RCLogError("Cannot read filelist '%s' (probably the file does not exist)", filename);
return;
}
char linebuf[MAX_PATH * 4];
while (!feof(file))
{
char* const line = fgets(linebuf, sizeof(linebuf), file);
if (line && line[0])
{
char* const pos = strchr(line, '=');
if (pos)
{
*pos = 0;
const string sIn = string(line).Trim();
const string sOut = string(pos + 1).Trim();
if (!sIn.empty() && !sOut.empty())
{
Add(sIn.c_str(), sOut.c_str());
}
}
}
}
fclose(file);
}
@@ -0,0 +1,62 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_DEPENDENCYLIST_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_DEPENDENCYLIST_H
#pragma once
//////////////////////////////////////////////////////////////////////////
class CDependencyList
{
public:
struct SFile
{
string inputFile;
string outputFile;
};
private:
std::vector<SFile> m_files;
bool m_bDuplicatesWereRemoved;
public:
CDependencyList();
CDependencyList(const CDependencyList& obj);
static string NormalizeFilename(const char* filename);
size_t GetCount() const
{
return m_files.size();
}
const SFile& GetElement(size_t index) const
{
return m_files[index];
}
void Add(const char* inputFilename, const char* outputFilename);
void RemoveDuplicates();
void RemoveInputFiles(const std::vector<string>& inputFilesToRemove);
void Save(const char* filename) const;
void SaveOutputOnly(const char* filename) const;
void Load(const char* filename);
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_DEPENDENCYLIST_H
@@ -0,0 +1,346 @@
/*
* 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.
// Description : Implementation of the CryEngine Unit Testing framework
#include "ResourceCompiler_precompiled.h"
#include "ExcelExport.h"
#include "ICryXML.h"
#include "IXMLSerializer.h"
#include "IRCLog.h"
#include "CryPath.h"
#include <CryLibrary.h>
#include "ResourceCompiler.h"
//////////////////////////////////////////////////////////////////////////
string CExcelExportBase::GetXmlHeader() const
{
return "<?xml version=\"1.0\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n";
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::InitExcelWorkbook(XmlNodeRef Workbook)
{
m_Workbook = Workbook;
m_Workbook->setTag("Workbook");
m_Workbook->setAttr("xmlns", "urn:schemas-microsoft-com:office:spreadsheet");
XmlNodeRef ExcelWorkbook = Workbook->newChild("ExcelWorkbook");
ExcelWorkbook->setAttr("xmlns", "urn:schemas-microsoft-com:office:excel");
XmlNodeRef Styles = m_Workbook->newChild("Styles");
{
// Style s25
// Bold header, With Background Color.
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s25");
XmlNodeRef StyleFont = Style->newChild("Font");
StyleFont->setAttr("x:CharSet", "204");
StyleFont->setAttr("x:Family", "Swiss");
StyleFont->setAttr("ss:Bold", "1");
XmlNodeRef StyleInterior = Style->newChild("Interior");
StyleInterior->setAttr("ss:Color", "#00FF00");
StyleInterior->setAttr("ss:Pattern", "Solid");
XmlNodeRef NumberFormat = Style->newChild("NumberFormat");
NumberFormat->setAttr("ss:Format", "#,##0");
}
{
// Style s26
// Bold/Centered header.
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s26");
XmlNodeRef StyleFont = Style->newChild("Font");
StyleFont->setAttr("x:CharSet", "204");
StyleFont->setAttr("x:Family", "Swiss");
StyleFont->setAttr("ss:Bold", "1");
XmlNodeRef StyleInterior = Style->newChild("Interior");
StyleInterior->setAttr("ss:Color", "#FFFF99");
StyleInterior->setAttr("ss:Pattern", "Solid");
XmlNodeRef Alignment = Style->newChild("Alignment");
Alignment->setAttr("ss:Horizontal", "Center");
Alignment->setAttr("ss:Vertical", "Bottom");
}
{
// Style s27
// Bold Highlighted Cell, With Red Background Color, white Text, Centered.
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s27");
XmlNodeRef StyleFont = Style->newChild("Font");
StyleFont->setAttr("x:CharSet", "204");
StyleFont->setAttr("x:Family", "Swiss");
StyleFont->setAttr("ss:Bold", "1");
StyleFont->setAttr("ss:Color", "#FFFFFF");
XmlNodeRef StyleInterior = Style->newChild("Interior");
StyleInterior->setAttr("ss:Color", "#FF0000");
StyleInterior->setAttr("ss:Pattern", "Solid");
XmlNodeRef Alignment = Style->newChild("Alignment");
Alignment->setAttr("ss:Horizontal", "Center");
Alignment->setAttr("ss:Vertical", "Bottom");
}
{
// Style s28
// Bold Highlighted Cell, With Red Background Color, white Text.
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s28");
XmlNodeRef StyleFont = Style->newChild("Font");
StyleFont->setAttr("x:CharSet", "204");
StyleFont->setAttr("x:Family", "Swiss");
StyleFont->setAttr("ss:Bold", "1");
StyleFont->setAttr("ss:Color", "#FFFFFF");
XmlNodeRef StyleInterior = Style->newChild("Interior");
StyleInterior->setAttr("ss:Color", "#FF0000");
StyleInterior->setAttr("ss:Pattern", "Solid");
}
{
// Style s20
// Centered
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s20");
XmlNodeRef Alignment = Style->newChild("Alignment");
Alignment->setAttr("ss:Horizontal", "Center");
Alignment->setAttr("ss:Vertical", "Bottom");
}
{
// Style s21
// Bold
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s21");
XmlNodeRef StyleFont = Style->newChild("Font");
StyleFont->setAttr("x:CharSet", "204");
StyleFont->setAttr("x:Family", "Swiss");
StyleFont->setAttr("ss:Bold", "1");
}
{
// Style s22
// Centered, Integer Number format
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s22");
XmlNodeRef Alignment = Style->newChild("Alignment");
Alignment->setAttr("ss:Horizontal", "Center");
Alignment->setAttr("ss:Vertical", "Bottom");
XmlNodeRef NumberFormat = Style->newChild("NumberFormat");
NumberFormat->setAttr("ss:Format", "#,##0");
}
{
// Style s23
// Centered, Float Number format
XmlNodeRef Style = Styles->newChild("Style");
Style->setAttr("ss:ID", "s23");
XmlNodeRef Alignment = Style->newChild("Alignment");
Alignment->setAttr("ss:Horizontal", "Center");
Alignment->setAttr("ss:Vertical", "Bottom");
//XmlNodeRef NumberFormat = Style->newChild( "NumberFormat" );
//NumberFormat->setAttr( "ss:Format","#,##0" );
}
/*
<Style ss:ID="s25">
<Font x:CharSet="204" x:Family="Swiss" ss:Bold="1"/>
<Interior ss:Color="#FFFF99" ss:Pattern="Solid"/>
</Style>
*/
}
//////////////////////////////////////////////////////////////////////////
XmlNodeRef CExcelExportBase::NewWorksheet(const char* name)
{
m_CurrWorksheet = m_Workbook->newChild("Worksheet");
m_CurrWorksheet->setAttr("ss:Name", name);
m_CurrTable = m_CurrWorksheet->newChild("Table");
return m_CurrWorksheet;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddRow()
{
m_CurrRow = m_CurrTable->newChild("Row");
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddCell_SumOfRows(int nRows)
{
XmlNodeRef cell = m_CurrRow->newChild("Cell");
XmlNodeRef data = cell->newChild("Data");
data->setAttr("ss:Type", "Number");
data->setContent("0");
m_CurrCell = cell;
if (nRows > 0)
{
char buf[128];
sprintf_s(buf, "=SUM(R[-%d]C:R[-1]C)", nRows);
m_CurrCell->setAttr("ss:Formula", buf);
}
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddCell(float number)
{
XmlNodeRef cell = m_CurrRow->newChild("Cell");
cell->setAttr("ss:StyleID", "s23"); // Centered
XmlNodeRef data = cell->newChild("Data");
data->setAttr("ss:Type", "Number");
char str[128];
sprintf_s(str, "%.3f", number);
data->setContent(str);
m_CurrCell = cell;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddCell(int number)
{
XmlNodeRef cell = m_CurrRow->newChild("Cell");
cell->setAttr("ss:StyleID", "s22"); // Centered
XmlNodeRef data = cell->newChild("Data");
data->setAttr("ss:Type", "Number");
char str[128];
sprintf_s(str, "%d", number);
data->setContent(str);
m_CurrCell = cell;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddCell(uint32 number)
{
XmlNodeRef cell = m_CurrRow->newChild("Cell");
cell->setAttr("ss:StyleID", "s22"); // Centered
XmlNodeRef data = cell->newChild("Data");
data->setAttr("ss:Type", "Number");
char str[128];
sprintf_s(str, "%u", number);
data->setContent(str);
m_CurrCell = cell;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddCell(const char* str, int nFlags)
{
XmlNodeRef cell = m_CurrRow->newChild("Cell");
XmlNodeRef data = cell->newChild("Data");
data->setAttr("ss:Type", "String");
data->setContent(str);
SetCellFlags(cell, nFlags);
m_CurrCell = cell;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AddCellAtIndex(int nIndex, const char* str, int nFlags)
{
XmlNodeRef cell = m_CurrRow->newChild("Cell");
cell->setAttr("ss:Index", nIndex);
XmlNodeRef data = cell->newChild("Data");
data->setAttr("ss:Type", "String");
data->setContent(str);
SetCellFlags(cell, nFlags);
m_CurrCell = cell;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::SetCellFlags(XmlNodeRef cell, int flags)
{
if (flags & CELL_BOLD)
{
if (flags & CELL_CENTERED)
{
cell->setAttr("ss:StyleID", "s26");
}
else
{
cell->setAttr("ss:StyleID", "s21");
}
}
else if (flags & CELL_CENTERED)
{
cell->setAttr("ss:StyleID", "s20");
}
else if (flags & CELL_HIGHLIGHT)
{
cell->setAttr("ss:StyleID", "s27");
}
}
//////////////////////////////////////////////////////////////////////////
bool CExcelExportBase::SaveToFile(const char* filename) const
{
string xml = m_Workbook->getXML();
string header = GetXmlHeader();
FILE* file = nullptr;
azfopen(&file, filename, "wb");
if (file)
{
fprintf(file, "%s", header.c_str());
fprintf(file, "%s", xml.c_str());
fclose(file);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
XmlNodeRef CExcelExportBase::NewWorkbook()
{
XmlNodeRef Workbook = LoadICryXML()->GetXMLSerializer()->CreateNode("Workbook");
InitExcelWorkbook(Workbook);
return Workbook;
}
//////////////////////////////////////////////////////////////////////////
XmlNodeRef CExcelExportBase::AddColumn(const char* name, int nWidth)
{
XmlNodeRef Column = m_CurrTable->newChild("Column");
Column->setAttr("ss:Width", nWidth);
m_columns.push_back(name);
return Column;
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::BeginColumns()
{
m_columns.clear();
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::EndColumns()
{
AddRow();
m_CurrRow->setAttr("ss:StyleID", "s25");
for (int i = 0; i < m_columns.size(); i++)
{
AddCell(m_columns[i]);
}
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::FreezeFirstRow()
{
XmlNodeRef options = m_CurrWorksheet->newChild("WorksheetOptions");
options->setAttr("xmlns", "urn:schemas-microsoft-com:office:excel");
options->newChild("FreezePanes");
options->newChild("FrozenNoSplit");
options->newChild("SplitHorizontal")->setContent("1");
options->newChild("TopRowBottomPane")->setContent("1");
options->newChild("ActivePane")->setContent("2");
}
//////////////////////////////////////////////////////////////////////////
void CExcelExportBase::AutoFilter(int nRow, int nNumColumns)
{
XmlNodeRef options = m_CurrWorksheet->newChild("AutoFilter");
options->setAttr("xmlns", "urn:schemas-microsoft-com:office:excel");
string range;
range.Format("R%dC1:R%dC%d", nRow, nRow, nNumColumns);
options->setAttr("x:Range", range); // x:Range="R1C1:R1C8"
}
@@ -0,0 +1,66 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXCELEXPORT_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXCELEXPORT_H
#pragma once
#include <IXml.h>
// Base class for custom CryEngine excel exporters
class CExcelExportBase
{
public:
enum CellFlags
{
CELL_BOLD = 0x0001,
CELL_CENTERED = 0x0002,
CELL_HIGHLIGHT = 0x0004,
};
bool SaveToFile(const char* filename) const;
XmlNodeRef NewWorkbook();
void InitExcelWorkbook(XmlNodeRef Workbook);
XmlNodeRef NewWorksheet(const char* name);
XmlNodeRef AddColumn(const char* name, int nWidth);
void BeginColumns();
void EndColumns();
void AddCell(float number);
void AddCell(int number);
void AddCell(uint32 number);
void AddCell(uint64 number) { AddCell((uint32)number); };
void AddCell(int64 number) { AddCell((int)number); };
void AddCell(const char* str, int flags = 0);
void AddCellAtIndex(int nIndex, const char* str, int flags = 0);
void SetCellFlags(XmlNodeRef cell, int flags);
void AddRow();
void AddCell_SumOfRows(int nRows);
string GetXmlHeader() const;
void FreezeFirstRow();
void AutoFilter(int nRow, int nNumColumns);
protected:
XmlNodeRef m_Workbook;
XmlNodeRef m_CurrTable;
XmlNodeRef m_CurrWorksheet;
XmlNodeRef m_CurrRow;
XmlNodeRef m_CurrCell;
std::vector<string> m_columns;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXCELEXPORT_H
@@ -0,0 +1,394 @@
/*
* 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.
// Description : Implementation of the CryEngine Unit Testing framework
#include "ResourceCompiler_precompiled.h"
#include "AssetFileInfo.h"
#include "CryPath.h"
#include "ExcelReport.h"
#include "IResCompiler.h"
#include "StringUtils.h" // for cry_strcat
//////////////////////////////////////////////////////////////////////////
struct FilesComparePredicate
{
bool operator()(const CAssetFileInfo* p1, const CAssetFileInfo* p2)
{
if (p1->m_bSuccess != p2->m_bSuccess)
{
return p1->m_bSuccess < p2->m_bSuccess;
}
return p1->m_DstFileSize > p2->m_DstFileSize;
}
};
//////////////////////////////////////////////////////////////////////////
static inline int64 ComputeSizeInKB(int64 sz)
{
return (sz < 0) ? 0 : (sz + 512) / 1024;
}
//////////////////////////////////////////////////////////////////////////
bool CExcelReport::Export(IResourceCompiler* pRC, const char* filename, std::vector<CAssetFileInfo*>& files)
{
m_pRC = pRC;
XmlNodeRef WorkBook = NewWorkbook();
std::sort(files.begin(), files.end(), FilesComparePredicate());
ExportSummary(files);
ExportTextures(files);
ExportCGF(files);
ExportCHR(files);
ExportCAF(files);
return SaveToFile(filename);
}
//////////////////////////////////////////////////////////////////////////
void CExcelReport::ExportSummary(const std::vector<CAssetFileInfo*>& files)
{
NewWorksheet("Summary");
const SFileVersion& fv = m_pRC->GetFileVersion();
AddColumn("", 150);
AddColumn("", 150);
AddRow();
AddCell("RC Version", CELL_BOLD);
char buffer[1024];
azsnprintf(buffer, sizeof(buffer), "%d.%d.%d", fv.v[2], fv.v[1], fv.v[0]);
AddCell(buffer);
AddRow();
AddCell("RC Compile Time", CELL_BOLD);
azsnprintf(buffer, sizeof(buffer), "%s %s", __DATE__, __TIME__);
AddCell(buffer);
AddRow();
AddRow();
size_t unusedCount = 0;
uint64 unusedSize = 0;
for (size_t i = 0; i < files.size(); i++)
{
const CAssetFileInfo& afi = *files[i];
if (!afi.m_bReferencedInLevels &&
(afi.m_type == CAssetFileInfo::eTexture ||
afi.m_type == CAssetFileInfo::eCGF ||
afi.m_type == CAssetFileInfo::eCHR))
{
++unusedCount;
unusedSize += afi.m_DstFileSize;
}
}
azsnprintf(buffer, sizeof(buffer), "%d files processed", (int)files.size());
AddCell(buffer);
AddRow();
const unsigned int bytesInMegabyte = 1024 * 1024;
azsnprintf(buffer, sizeof(buffer), "%u unused assets found (%u MB)", (unsigned int)unusedCount, (unsigned int)(unusedSize / bytesInMegabyte));
AddCell(buffer);
}
//////////////////////////////////////////////////////////////////////////
void CExcelReport::ExportTextures(const std::vector<CAssetFileInfo*>& files)
{
NewWorksheet("Textures");
FreezeFirstRow();
AutoFilter(1, 10);
BeginColumns();
AddColumn("Ok", 40);
AddColumn("File", 400);
AddColumn("In Levels", 60);
AddColumn("User", 80);
AddColumn("Size (KB)", 80);
AddColumn("Width", 50);
AddColumn("Height", 50);
AddColumn("Mips", 50);
AddColumn("Format", 80);
AddColumn("Type", 80);
AddColumn("Alpha", 50);
AddColumn("Sides", 50);
AddColumn("Perforce", 100);
AddColumn("Error", 100);
EndColumns();
for (uint32 i = 0; i < files.size(); i++)
{
const CAssetFileInfo& afi = *files[i];
if (afi.m_type != CAssetFileInfo::eTexture)
{
continue;
}
AddRow();
AddCell(afi.m_bSuccess ? "OK" : "FAIL", (afi.m_bSuccess ? 0 : CELL_HIGHLIGHT));
AddCell(afi.m_sSourceFilename);
AddCell(afi.m_bReferencedInLevels ? "USED" : "NOT USED", afi.m_bReferencedInLevels ? CELL_CENTERED : CELL_BOLD | CELL_CENTERED);
AddCell(ComputeSizeInKB(afi.m_DstFileSize));
AddCell(afi.m_textureInfo.w);
AddCell(afi.m_textureInfo.h);
AddCell(afi.m_textureInfo.nNumMips);
AddCell(afi.m_textureInfo.format, CELL_CENTERED);
const char* type = "2D";
if (afi.m_textureInfo.nDepth > 1)
{
type = "3D";
}
else if (afi.m_textureInfo.nSides > 1)
{
type = "Cubemap";
}
AddCell(type, CELL_CENTERED);
AddCell((afi.m_textureInfo.bAlpha) ? "Yes" : "", CELL_CENTERED);
AddCell(afi.m_textureInfo.nSides);
AddCell(afi.m_sErrorLog);
}
}
//////////////////////////////////////////////////////////////////////////
void CExcelReport::ExportCGF(const std::vector<CAssetFileInfo*>& files)
{
NewWorksheet("Geometry");
FreezeFirstRow();
AutoFilter(1, 15);
BeginColumns();
AddColumn("Ok", 40);
AddColumn("File", 400);
AddColumn("In Levels", 60);
AddColumn("User", 80);
AddColumn("File Size", 80);
AddColumn("Mesh Size (KB)", 80);
AddColumn("Mesh Size Lod0 (KB)", 80);
AddColumn("LODs", 50);
AddColumn("Sub Meshes", 50);
AddColumn("Vertices", 50);
AddColumn("Tris", 50);
AddColumn("Joints", 50);
AddColumn("Phys Tris", 80);
AddColumn("Phys Size (KB)", 80);
AddColumn("Phys Proxies", 80);
AddColumn("LODs Tris", 80);
AddColumn("Split LODs", 80);
AddColumn("Perforce", 100);
AddColumn("Error", 100);
EndColumns();
for (uint32 i = 0; i < files.size(); i++)
{
const CAssetFileInfo& afi = *files[i];
if (afi.m_type != CAssetFileInfo::eCGF)
{
continue;
}
int nMeshSizeTotal = 0;
for (int lod = 0; lod < CAssetFileInfo::kMaxCgfLods; lod++)
{
nMeshSizeTotal += afi.m_geomInfo.nMeshSizePerLod[lod];
}
AddRow();
AddCell(afi.m_bSuccess ? "OK" : "FAIL", (afi.m_bSuccess ? 0 : CELL_HIGHLIGHT));
AddCell(afi.m_sSourceFilename);
AddCell(afi.m_bReferencedInLevels ? "USED" : "NOT USED", afi.m_bReferencedInLevels ? CELL_CENTERED : CELL_BOLD | CELL_CENTERED);
AddCell(ComputeSizeInKB(afi.m_DstFileSize));
AddCell((nMeshSizeTotal + 512) / 1024);
AddCell((afi.m_geomInfo.nMeshSize + 512) / 1024);
AddCell(afi.m_geomInfo.nLods);
AddCell(afi.m_geomInfo.nSubMeshCount);
AddCell(afi.m_geomInfo.nVertices);
AddCell(afi.m_geomInfo.nIndices / 3);
AddCell(afi.m_geomInfo.nJoints);
AddCell(afi.m_geomInfo.nPhysTriCount);
AddCell((afi.m_geomInfo.nPhysProxySize + 512) / 1024);
AddCell((afi.m_geomInfo.nPhysProxyCount));
if (afi.m_geomInfo.nLods > 1)
{
// Print lod1/lod2/lod3 ...
char tempstr[256];
char numstr[32];
tempstr[0] = 0;
int numlods = 0;
for (int lod = 0; lod < CAssetFileInfo::kMaxCgfLods; lod++)
{
if (afi.m_geomInfo.nIndicesPerLod[lod] != 0)
{
azsnprintf(numstr, sizeof(numstr), "%d", (afi.m_geomInfo.nIndicesPerLod[lod] / 3));
if (numlods > 0)
{
cry_strcat(tempstr, " / ");
}
cry_strcat(tempstr, numstr);
numlods++;
}
}
AddCell(tempstr, CELL_CENTERED);
}
else
{
AddCell("");
}
AddCell((afi.m_geomInfo.bSplitLods) ? "Yes" : "");
AddCell(afi.m_sErrorLog);
}
}
//////////////////////////////////////////////////////////////////////////
void CExcelReport::ExportCHR(const std::vector<CAssetFileInfo*>& files)
{
NewWorksheet("Characters");
FreezeFirstRow();
AutoFilter(1, 15);
BeginColumns();
AddColumn("Ok", 40);
AddColumn("File", 400);
AddColumn("In Levels", 60);
AddColumn("User", 80);
AddColumn("File Size", 80);
AddColumn("Mesh Size (KB)", 80);
AddColumn("Mesh Size Lod0 (KB)", 80);
AddColumn("LODs", 50);
AddColumn("Sub Meshes", 50);
AddColumn("Vertices", 50);
AddColumn("Tris", 50);
AddColumn("Phys Tris", 80);
AddColumn("Phys Size (KB)", 80);
AddColumn("Phys Proxies", 80);
AddColumn("LODs Tris", 80);
AddColumn("Perforce", 100);
AddColumn("Error", 100);
EndColumns();
for (uint32 i = 0; i < files.size(); i++)
{
const CAssetFileInfo& afi = *files[i];
if (afi.m_type != CAssetFileInfo::eCHR)
{
continue;
}
int nMeshSizeTotal = 0;
for (int lod = 0; lod < CAssetFileInfo::kMaxCgfLods; lod++)
{
nMeshSizeTotal += afi.m_geomInfo.nMeshSizePerLod[lod];
}
AddRow();
AddCell(afi.m_bSuccess ? "OK" : "FAIL", (afi.m_bSuccess ? 0 : CELL_HIGHLIGHT));
AddCell(afi.m_sSourceFilename);
AddCell(afi.m_bReferencedInLevels ? "USED" : "NOT USED", afi.m_bReferencedInLevels ? CELL_CENTERED : CELL_BOLD | CELL_CENTERED);
AddCell(ComputeSizeInKB(afi.m_DstFileSize));
AddCell((nMeshSizeTotal + 512) / 1024);
AddCell((afi.m_geomInfo.nMeshSize + 512) / 1024);
AddCell(afi.m_geomInfo.nLods);
AddCell(afi.m_geomInfo.nSubMeshCount);
AddCell(afi.m_geomInfo.nVertices);
AddCell(afi.m_geomInfo.nIndices / 3);
AddCell(afi.m_geomInfo.nPhysTriCount);
AddCell((afi.m_geomInfo.nPhysProxySize + 512) / 1024);
AddCell((afi.m_geomInfo.nPhysProxyCount));
if (afi.m_geomInfo.nLods > 1)
{
// Print lod1/lod2/lod3 ...
char tempstr[256];
char numstr[32];
tempstr[0] = 0;
int numlods = 0;
for (int lod = 0; lod < CAssetFileInfo::kMaxCgfLods; lod++)
{
if (afi.m_geomInfo.nIndicesPerLod[lod] != 0)
{
sprintf_s(numstr, sizeof(numstr), "%d", (afi.m_geomInfo.nIndicesPerLod[lod] / 3));
if (numlods > 0)
{
cry_strcat(tempstr, " / ");
}
cry_strcat(tempstr, numstr);
numlods++;
}
}
AddCell(tempstr, CELL_CENTERED);
}
else
{
AddCell("");
}
AddCell(afi.m_sErrorLog);
}
}
//////////////////////////////////////////////////////////////////////////
void CExcelReport::ExportCAF(const std::vector<CAssetFileInfo*>& files)
{
NewWorksheet("Animations");
FreezeFirstRow();
AutoFilter(1, 5);
BeginColumns();
AddColumn("Ok", 40);
AddColumn("File", 400);
AddColumn("User", 80);
AddColumn("File Size", 80);
AddColumn("Perforce", 100);
AddColumn("Error", 100);
EndColumns();
for (uint32 i = 0; i < files.size(); i++)
{
const CAssetFileInfo& afi = *files[i];
if (afi.m_type != CAssetFileInfo::eCAF)
{
continue;
}
int nMeshSizeTotal = 0;
for (int lod = 0; lod < CAssetFileInfo::kMaxCgfLods; lod++)
{
nMeshSizeTotal += afi.m_geomInfo.nMeshSizePerLod[lod];
}
AddRow();
AddCell(afi.m_bSuccess ? "OK" : "FAIL", (afi.m_bSuccess ? 0 : CELL_HIGHLIGHT));
AddCell(afi.m_sSourceFilename);
AddCell(ComputeSizeInKB(afi.m_DstFileSize));
AddCell(afi.m_sErrorLog);
}
}
@@ -0,0 +1,41 @@
/*
* 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.
// Description : ExcelReporter
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXCELREPORT_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXCELREPORT_H
#pragma once
#include "ExcelExport.h"
#include "ConvertContext.h"
// Base class for custom CryEngine excel exporters
class CExcelReport
: public CExcelExportBase
{
public:
bool Export(IResourceCompiler* pRC, const char* filename, std::vector<CAssetFileInfo*>& files);
void ExportSummary(const std::vector<CAssetFileInfo*>& files);
void ExportTextures(const std::vector<CAssetFileInfo*>& files);
void ExportCGF(const std::vector<CAssetFileInfo*>& files);
void ExportCHR(const std::vector<CAssetFileInfo*>& files);
void ExportCAF(const std::vector<CAssetFileInfo*>& files);
protected:
IResourceCompiler* m_pRC;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXCELREPORT_H
@@ -0,0 +1,98 @@
/*
* 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 <time.h>
#include "ExtensionManager.h"
#include "IConvertor.h"
#include "IResCompiler.h" // IResourceCompiler
#include "IRCLog.h" // IRCLog
#include "StringHelpers.h"
//////////////////////////////////////////////////////////////////////////
ExtensionManager::ExtensionManager()
{
}
//////////////////////////////////////////////////////////////////////////
ExtensionManager::~ExtensionManager()
{
UnregisterAll();
}
//////////////////////////////////////////////////////////////////////////
IConvertor* ExtensionManager::FindConvertor(const char* filename) const
{
string const strFilename = StringHelpers::MakeLowerCase(string(filename));
for (size_t i = 0; i < m_extVector.size(); ++i)
{
if (StringHelpers::EndsWith(strFilename, m_extVector[i].first))
{
return m_extVector[i].second;
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void ExtensionManager::RegisterConvertor(const char* name, IConvertor* conv, [[maybe_unused]] IResourceCompiler* rc)
{
assert(conv);
assert(rc);
m_convertors.push_back(conv);
string strExt;
for (int i = 0;; ++i)
{
const char* const ext = conv->GetExt(i);
if (!ext || !ext[0])
{
break;
}
if (i)
{
strExt += ", ";
}
strExt += "\"";
strExt += ext;
strExt += "\"";
const string extToAdd = StringHelpers::MakeLowerCase(string(".") + ext);
m_extVector.push_back(ExtVector::value_type(extToAdd, conv));
}
if (strExt.empty())
{
RCLogError(" %s failed to provide list of extensions", name);
}
else
{
RCLog(" Registered %s (%s)", name, strExt.c_str());
}
}
//////////////////////////////////////////////////////////////////////////
void ExtensionManager::UnregisterAll()
{
for (size_t i = 0; i < m_convertors.size(); ++i)
{
IConvertor* conv = m_convertors[i];
conv->Release();
}
m_convertors.clear();
m_extVector.clear();
}
@@ -0,0 +1,47 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXTENSIONMANAGER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXTENSIONMANAGER_H
#pragma once
// forward declarations.
struct IConvertor;
/** Manages mapping between file extensions and convertors.
*/
class ExtensionManager
{
public:
ExtensionManager();
~ExtensionManager();
//! Register new convertor with extension manager.
//! \param conv must not be 0
//! \param rc must not be 0
void RegisterConvertor(const char* name, IConvertor* conv, IResourceCompiler* rc);
//! Unregister all convertors.
void UnregisterAll();
//! Find convertor that matches given platform and extension.
IConvertor* FindConvertor(const char* filename) const;
private:
// Links extensions and convertors.
typedef std::vector<std::pair<string, IConvertor*> > ExtVector;
ExtVector m_extVector;
std::vector<IConvertor*> m_convertors;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_EXTENSIONMANAGER_H
@@ -0,0 +1,56 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* 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.
#ifndef FUNCTIONTHREAD_H
#define FUNCTIONTHREAD_H
#include <QThread>
#if !defined(AZ_PLATFORM_WINDOWS)
#define STILL_ACTIVE 259
#endif
class FunctionThread : public QThread
{
public:
FunctionThread(unsigned int (*function)(void* param), void* param)
: m_function(function),
m_param(param)
{
}
unsigned int returnCode() const
{
return m_returnCode;
}
static FunctionThread* CreateThread(int,int, unsigned int (*function)(void* param), void* param, int, int)
{
auto t = new FunctionThread(function, param);
t->start();
return t;
}
protected:
void run() override
{
m_returnCode = m_function(m_param);
}
private:
unsigned int m_returnCode = STILL_ACTIVE;
unsigned int (*m_function)(void* param);
void* m_param;
};
#endif
+65
View File
@@ -0,0 +1,65 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICFGFILE_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICFGFILE_H
#pragma once
enum EConfigPriority : uint32_t;
class IConfigSink;
/** Configuration file interface.
Use format similar to windows .ini files.
*/
class ICfgFile
{
public:
virtual ~ICfgFile() {}
//! Delete instance of configuration file class.
virtual void Release() = 0;
//! Load configuration file.
//! @return true=success, false otherwise
virtual bool Load(const string& fileName) = 0;
//! Save configuration file, with the stored name in m_fileName
//! @return true=success, false otherwise
virtual bool Save() = 0;
//! @param inszSection
//! @param inszKey
//! @param inszValue
virtual void UpdateOrCreateEntry(const char* inszSection, const char* inszKey, const char* inszValue) = 0;
//! @param inszSection
//! @param inszKey
virtual void RemoveEntry(const char* inszSection, const char* inszKey) = 0;
//! Copy section keys to config specified by the 'config' parameter.
// keySuffixes is a non-empty string containing one or more comma-separated suffixes:
// copies keys named <name>:<suffix> and <name>, suffix is stripped out.
// keySuffixes is an empty string:
// copies keys named <name>. keys in format <name>:<suffix> are ignored.
// keySuffixes is 0:
// copies all keys "as is".
virtual void CopySectionKeysToConfig(EConfigPriority ePri, int sectionIndex, const char* keySuffixes, IConfigSink* config) const = 0;
// can be used to iterate through the section names
//! @return 0 if sectionIndex is < 0 or >= than number of sections.
virtual const char* GetSectionName(int sectionIndex) const = 0;
//! @return section index or -1 if section not found.
virtual int FindSection(const char* sectionName) const = 0;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICFGFILE_H
+251
View File
@@ -0,0 +1,251 @@
/*
* 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 "IConfig.h"
#include "IRCLog.h"
bool IConfig::HasKey(const char* const key, const int ePriMask) const
{
const char* pValue;
return GetKeyValue(key, pValue, ePriMask);
}
IConfig::EResult IConfig::Get(const char* const key, bool& value, const int ePriMask) const
{
const char* pValue;
if (!GetKeyValue(key, pValue, ePriMask))
{
return eResult_KeyIsNotFound;
}
{
int tmpInt;
if (azsscanf(pValue, "%d", &tmpInt) == 1)
{
value = (tmpInt != 0);
return eResult_Success;
}
}
if (!azstricmp(pValue, "true") ||
!azstricmp(pValue, "yes") ||
!azstricmp(pValue, "enable") ||
!azstricmp(pValue, "y") ||
!azstricmp(pValue, "t"))
{
value = true;
return eResult_Success;
}
if (!azstricmp(pValue, "false") ||
!azstricmp(pValue, "no") ||
!azstricmp(pValue, "disable") ||
!azstricmp(pValue, "n") ||
!azstricmp(pValue, "f"))
{
value = false;
return eResult_Success;
}
return eResult_ValueIsEmptyOrBad;
}
IConfig::EResult IConfig::Get(const char* const key, int& value, const int ePriMask) const
{
const char* pValue;
if (!GetKeyValue(key, pValue, ePriMask))
{
return eResult_KeyIsNotFound;
}
int tmpValue;
if (azsscanf(pValue, "%d", &tmpValue) == 1)
{
value = tmpValue;
return eResult_Success;
}
return eResult_ValueIsEmptyOrBad;
}
IConfig::EResult IConfig::Get(const char* const key, float& value, const int ePriMask) const
{
const char* pValue;
if (!GetKeyValue(key, pValue, ePriMask))
{
return eResult_KeyIsNotFound;
}
float tmpValue;
if (azsscanf(pValue, "%f", &tmpValue) == 1)
{
value = tmpValue;
return eResult_Success;
}
return eResult_ValueIsEmptyOrBad;
}
IConfig::EResult IConfig::Get(const char* const key, string& value, const int ePriMask) const
{
const char* pValue;
if (!GetKeyValue(key, pValue, ePriMask))
{
return eResult_KeyIsNotFound;
}
if (pValue && pValue[0])
{
value = pValue;
return eResult_Success;
}
return eResult_ValueIsEmptyOrBad;
}
bool IConfig::GetAsBool(const char* const key, const bool keyIsNotFoundValue, const bool emptyOrBadValue, const int ePriMask) const
{
bool value;
switch (Get(key, value, ePriMask))
{
case eResult_Success:
return value;
case eResult_KeyIsNotFound:
return keyIsNotFoundValue;
default:
return emptyOrBadValue;
}
}
int IConfig::GetAsInt(const char* const key, const int keyIsNotFoundValue, const int emptyOrBadValue, const int ePriMask) const
{
int value;
switch (Get(key, value, ePriMask))
{
case eResult_Success:
return value;
case eResult_KeyIsNotFound:
return keyIsNotFoundValue;
default:
return emptyOrBadValue;
}
}
float IConfig::GetAsFloat(const char* const key, const float keyIsNotFoundValue, const float emptyOrBadValue, const int ePriMask) const
{
float value;
switch (Get(key, value, ePriMask))
{
case eResult_Success:
return value;
case eResult_KeyIsNotFound:
return keyIsNotFoundValue;
default:
return emptyOrBadValue;
}
}
string IConfig::GetAsString(const char* const key, const char* const keyIsNotFoundValue, const char* const emptyOrBadValue, const int ePriMask) const
{
string value;
switch (Get(key, value, ePriMask))
{
case eResult_Success:
return value;
case eResult_KeyIsNotFound:
return string(keyIsNotFoundValue);
default:
return string(emptyOrBadValue);
}
}
static inline void SkipWhitespace(const char*& p)
{
while (*p && *p <= ' ')
{
++p;
}
}
void IConfig::SetFromString(const EConfigPriority ePri, const char* p)
{
assert(Util::isPowerOfTwo(ePri));
if (p == 0)
{
return;
}
while (*p)
{
string sKey;
string sValue;
SkipWhitespace(p);
if (*p != '/')
{
RCLog("Config string format is invalid ('/' expected): '%s'", p);
break;
}
++p; // jump over '/'
while (IsValidNameChar(*p))
{
sKey += *p++;
}
SkipWhitespace(p);
if (*p != '=')
{
RCLog("Config string format is invalid ('=' expected): '%s'", p);
break;
}
++p; // jump over '='
SkipWhitespace(p);
if (*p == '\"') // in quotes
{
++p;
while (*p && *p != '\"') // value
{
sValue += *p++;
}
if (*p == '\"')
{
++p;
}
}
else // without quotes
{
while (IsValidNameChar(*p)) // value
{
sValue += *p++;
}
}
SkipWhitespace(p);
sKey.Trim();
sValue.Trim();
SetKeyValue(ePri, sKey, sValue);
}
}
+144
View File
@@ -0,0 +1,144 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICONFIG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICONFIG_H
#pragma once
#include "Util.h" // BIT()
#include <vector>
#include <platform.h>
class Config;
class CPropertyVars;
enum EConfigPriority : uint32_t
{
// low priorities first
eCP_PriorityLowest = BIT(0), // used internally
eCP_PriorityFile = BIT(1), // per-file settings
eCP_PriorityPreset = BIT(2), // settings from section [<preset_name>] of rc.ini
eCP_PriorityRcIni = BIT(3), // settings from rc.ini (common + per-platform)
eCP_PriorityCmdline = BIT(4), // rc.exe's command line
eCP_PriorityProperty = BIT(5), // settings from RCJob XML properties
eCP_PriorityJob = BIT(6), // per-job configuration
eCP_PriorityHighest = BIT(7), // used internally
eCP_PriorityAll = eCP_PriorityHighest + (eCP_PriorityHighest - 1) // binary OR of all possible priority values
};
class IConfigSink
{
public:
virtual ~IConfigSink()
{
}
// Arguments:
// value - can be 0 to delete a key, can be "" to set a key without value (e.g. /refresh)
virtual void SetKeyValue(EConfigPriority ePri, const char* key, const char* value) = 0;
};
/** Configuration options interface.
*/
class IConfig
: public IConfigSink
{
public:
// Delete instance of configuration class.
virtual void Release() = 0;
virtual const Config* GetInternalRepresentation() const = 0;
virtual bool HasKeyRegistered(const char* key) const = 0;
// Returns true if the config contains a key that matches 'wildcards' name.
virtual bool HasKeyMatchingWildcards(const char* wildcards) const = 0;
// Get pointer to ASCIIZ value of a key. The pointer is not modified if the key is not found.
// Returns:
// true if key found, false if not.
virtual bool GetKeyValue(const char* key, const char*& value, int ePriMask = eCP_PriorityAll) const = 0;
// Get sum of all values of a key.
// Returns:
// 0 if key is not found or has no value
virtual int GetSum(const char* key) const = 0;
// Find unknown keys in configuration.
virtual void GetUnknownKeys(std::vector<string>& unknownKeys) const = 0;
// Merge configuration.
virtual void AddConfig(const IConfig* pCfg) = 0;
virtual void Clear() = 0;
virtual uint32 ClearPriorityUsage(int ePriMask) = 0;
virtual uint32 CountPriorityUsage(int ePriMask) const = 0;
virtual void CopyToConfig(EConfigPriority ePri, IConfigSink* pDestConfig) const = 0;
virtual void CopyToPropertyVars(CPropertyVars& properties) const = 0;
//////////////////////////////////////////////////////////////////////////
// Check if configuration has a key
bool HasKey(const char* key, int ePriMask = eCP_PriorityAll) const;
// Get value of a key
bool GetAsBool(const char* const key, const bool keyIsNotFoundValue, const bool emptyOrBadValue, int ePriMask = eCP_PriorityAll) const;
int GetAsInt(const char* const key, const int keyIsNotFoundValue, const int emptyOrBadValue, int ePriMask = eCP_PriorityAll) const;
float GetAsFloat(const char* const key, const float keyIsNotFoundValue, const float emptyOrBadValue, int ePriMask = eCP_PriorityAll) const;
string GetAsString(const char* const key, const char* const keyIsNotFoundValue, const char* const emptyOrBadValue, int ePriMask = eCP_PriorityAll) const;
// str - e.g. "/reduce=2 /space=tangent"
void SetFromString(EConfigPriority ePri, const char* str);
static bool IsValidNameChar(const unsigned char c)
{
return (c > ' ') && (c != '=') && (c != ';') && (c != ':') && (c != '/');
}
private:
// Get value of a key. The value (passed by reference) is not modified if
// the key is not found or the value attached to the key is empty or bad.
enum EResult
{
eResult_Success,
eResult_KeyIsNotFound,
eResult_ValueIsEmptyOrBad,
};
EResult Get(const char* key, bool& value, int ePriMask) const;
EResult Get(const char* key, int& value, int ePriMask) const;
EResult Get(const char* key, float& value, int ePriMask) const;
EResult Get(const char* key, string& value, int ePriMask) const;
};
class IConfigKeyRegistry
{
public:
virtual ~IConfigKeyRegistry()
{
}
virtual void VerifyKeyRegistration(const char* szKey) const = 0;
virtual bool HasKeyRegistered(const char* szKey) const = 0;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICONFIG_H
@@ -0,0 +1,86 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICONVERTOR_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICONVERTOR_H
#pragma once
#include "ConvertContext.h"
// A Convertor does no actual work, it merely describes the work that a Compiler will do,
// and can create Compiler instances to do the actual processing.
// Compiler interface, all compilers must implement this interface.
struct ICompiler
{
virtual ~ICompiler() = default;
// Release memory of interface.
virtual void Release() = 0;
// This function is called by RC before starting processing files.
virtual void BeginProcessing(const IConfig* config) = 0;
// This function is called by RC after finishing processing files.
virtual void EndProcessing() = 0;
// Return a convert context object.
// RC will fill with compilation parameters right before calling Process().
virtual IConvertContext* GetConvertContext() = 0;
// Process a file.
//
// The file and processing parameters are provided by RC
// by calling appropriate functions of a convert context
// object returned by GetConvertContext().
//
// Returns true if succeeded.
virtual bool Process() = 0;
virtual bool CreateJobs() { return false; };
};
class RcFile;
struct ConvertorInitContext
{
const IConfig* config;
size_t inputFileCount;
const RcFile* inputFiles;
const char* appRootPath = nullptr;
};
// Convertor interface, all converters must implement this interface.
struct IConvertor
{
virtual ~IConvertor() = default;
// Release memory of interface.
virtual void Release() = 0;
//Init is called before any compilers are created.
virtual void Init([[maybe_unused]] const ConvertorInitContext& context) {}
virtual void DeInit() {}
// Return an object that will do actual processing.
// Called only once since we do not support multi-threading in RC
virtual ICompiler* CreateCompiler() = 0;
// Get supported extension by zero-based index.
// If index is < 0 or >= number of supported extensions,
// then the function *must* return 0.
virtual const char* GetExt(int index) const = 0;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ICONVERTOR_H
@@ -0,0 +1,41 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IMULTIPLATFORMCONFIG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IMULTIPLATFORMCONFIG_H
#pragma once
#include "IConfig.h" // IConfig, IConfigKeyRegistry, enum EConfigPriority
class IMultiplatformConfig
{
public:
virtual ~IMultiplatformConfig()
{
}
virtual void init(int platformCount, int activePlatform, IConfigKeyRegistry* pConfigKeyRegistry) = 0;
virtual int getPlatformCount() const = 0;
virtual int getActivePlatform() const = 0;
virtual const IConfig& getConfig(int platform) const = 0;
virtual IConfig& getConfig(int platform) = 0;
virtual const IConfig& getConfig() const = 0;
virtual IConfig& getConfig() = 0;
virtual void setKeyValue(EConfigPriority ePri, const char* key, const char* value) = 0;
virtual void setActivePlatform(int platformIndex) = 0;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IMULTIPLATFORMCONFIG_H
@@ -0,0 +1,29 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IPROGRESS_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IPROGRESS_H
#pragma once
class IProgress
{
public:
virtual ~IProgress() {}
virtual void StartProgress() = 0;
virtual void ShowProgress(const char* pMessage, size_t progressValue, size_t maxProgressValue) = 0;
virtual void FinishProgress() = 0;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IPROGRESS_H
+50
View File
@@ -0,0 +1,50 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IRCLOG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IRCLOG_H
#pragma once
#include <stdarg.h>
// This interface is used by RC and convertors to log events
struct IRCLog
{
enum EType
{
eType_Info,
eType_Warning,
eType_Error,
eType_Context,
eType_Summary
};
virtual ~IRCLog()
{
}
virtual void LogV(const EType eType, const char* szFormat, va_list args) = 0;
virtual void Log(const EType eType, const char* szMessage) = 0;
};
void SetRCLog(IRCLog* pRCLog);
void RCLog(const char* szFormat, ...);
void RCLogWarning(const char* szFormat, ...);
void RCLogError(const char* szFormat, ...);
void RCLogContext(const char* szMessage);
void RCLogSummary(const char* szFormat, ...);
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IRCLOG_H
@@ -0,0 +1,210 @@
/*
* 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.
// Description : IResourceCompiler interface.
#pragma once
#include <platform.h>
#include <AzCore/std/string/string.h>
struct ConvertContext;
struct CryChunkedFile;
class ICfgFile;
struct IAssetWriter;
struct ICompiler;
class IConfig;
struct IConvertor;
struct IPakSystem;
struct IRCLog;
class MultiplatformConfig;
struct SFileVersion;
class XmlNodeRef;
namespace AZ
{
namespace Internal
{
class EnvironmentInterface;
} // Internal
} // AZ
struct PlatformInfo
{
enum
{
kMaxNameLength = 15
};
enum
{
kMaxPlatformNames = 3
};
int index; // unique, starts from 0, increased by one for next platform, persistent for a session
bool bBigEndian;
int pointerSize;
char platformNames[kMaxPlatformNames][kMaxNameLength + 1]; // every name is guaranteed to be zero-terminated, [0] is guaranteed to be non-empty
void Clear()
{
index = -1;
pointerSize = 0;
for (int i = 0; i < kMaxPlatformNames; ++i)
{
platformNames[i][0] = 0;
}
}
bool HasName(const char* const pName) const
{
for (int i = 0; i < kMaxPlatformNames && platformNames[i][0] != 0; ++i)
{
if (azstricmp(pName, &platformNames[i][0]) == 0)
{
return true;
}
}
return false;
}
bool SetName(int idx, const char* const pName)
{
if (idx < 0 || idx >= kMaxPlatformNames ||
!pName || !pName[0])
{
return false;
}
const size_t len = strlen(pName);
if (len + 1 > sizeof(platformNames[0]))
{
return false;
}
memcpy(platformNames[idx], pName, len + 1);
return true;
}
const char* GetMainName() const
{
return &platformNames[0][0];
}
const AZStd::string GetCommaSeparatedNames() const
{
AZStd::string names;
for (int i = 0; i < PlatformInfo::kMaxPlatformNames && platformNames[i][0] != 0; ++i)
{
if (!names.empty())
{
names += ",";
}
names += &platformNames[i][0];
}
return names;
}
};
/** Main interface of resource compiler.
*/
struct IResourceCompiler
{
class IExitObserver
{
public:
virtual ~IExitObserver()
{
}
virtual void OnExit() = 0;
};
//! Register new convertor.
virtual void RegisterConvertor(const char* name, IConvertor* conv) = 0;
// Get the interface for opening files - handles files stored in ZIP archives.
virtual IPakSystem* GetPakSystem() = 0;
virtual const ICfgFile* GetIniFile() const = 0;
virtual int GetPlatformCount() const = 0;
virtual const PlatformInfo* GetPlatformInfo(int index) const = 0;
// Returns index of the platform (or -1 if platform not found)
virtual int FindPlatform(const char* name) const = 0;
// One input file can generate multiple output files.
virtual void AddInputOutputFilePair(const char* inputFilename, const char* outputFilename) = 0;
// Mark file for removal in clean stage.
virtual void MarkOutputFileForRemoval(const char* sOutputFilename) = 0;
// Add pointer to an observer object which will be notified in case of 'unexpected' exit()
virtual void AddExitObserver(IExitObserver* p) = 0;
// Remove an observer object which was added previously by AddExitObserver() call
virtual void RemoveExitObserver(IExitObserver* p) = 0;
virtual IRCLog* GetIRCLog() = 0;
virtual int GetVerbosityLevel() const = 0;
virtual const SFileVersion& GetFileVersion() const = 0;
virtual const void GetGenericInfo(char* buffer, size_t bufferSize, const char* rowSeparator) const = 0;
// Arguments:
// key - must not be 0
// helptxt - must not be 0
virtual void RegisterKey(const char* key, const char* helptxt) = 0;
// returns the path of the resource compiler executable's directory (ending with backslash)
virtual const char* GetExePath() const = 0;
// returns the path of a directory for temporary files (ending with backslash)
virtual const char* GetTmpPath() const = 0;
// returns directory which was current at the moment of RC call (ending with backslash)
virtual const char* GetInitialCurrentDir() const = 0;
// returns an xmlnode for the given xml file or null node if the file could not be parsed
virtual XmlNodeRef LoadXml(const char* filename) = 0;
// returns an xmlnode with the given tag name
virtual XmlNodeRef CreateXml(const char* tag) = 0;
virtual bool CompileSingleFileBySingleProcess(const char* filename) = 0;
// Register Asset Writer interface
virtual void SetAssetWriter(IAssetWriter* pAssetWriter) = 0;
// Get Asset Writer interface
virtual IAssetWriter* GetAssetWriter() const = 0;
// Get the app root that the resource
virtual const char* GetAppRoot() const = 0;
};
extern "C"
{
// this is the plugin function that's exported by plugins
// Registers all convertors residing in this DLL.
// Must be called RegusterConvertors
typedef void(__stdcall * FnRegisterConvertors)(IResourceCompiler* pRC);
// this is the optional initialization function that may be exported by plugins
// It accepts the AZ shared system environment and should attach to it
typedef void (__stdcall * FnInitializeModule)(AZ::Internal::EnvironmentInterface* sharedEnvironment);
// (optional) called before the DLL is unloaded to perform cleanup if you need to.
// must be called BeforeUnloadDLL
typedef void(__stdcall * FnBeforeUnloadDLL)();
}
@@ -0,0 +1,31 @@
/*
* 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.
*
*/
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IUNITTESTHELPER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IUNITTESTHELPER_H
#pragma once
// IT IS RECOMMENDED TO USE THESE MACROS FOR UNIT TESTS INSTEAD OF THE METHODS LISTED BELOW
#define TEST_BOOL(statement) TestBool(statement, #statement)
class IUnitTestHelper
{
public:
virtual ~IUnitTestHelper() {};
// This tests a boolean value that should be true, the test will fail if it is false
// It is recommended that you use the TEST_BOOL macro to auto-stringify the statement for easier identification when unit tests fail
// Alternatively, specify your own testValueStatement to also help identify which unit test fails
virtual bool TestBool(bool testValueIsTrue, const char* testValueStatement) = 0;
};
#endif // #ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_IUNITTESTHELPER_H
+308
View File
@@ -0,0 +1,308 @@
/*
* 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;
}
+54
View File
@@ -0,0 +1,54 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_LISTFILE_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_LISTFILE_H
#pragma once
class CListFile
{
public:
CListFile(IResourceCompiler* pRC);
bool Process(
const string& listFile,
const string& formatList,
const string& wildcardList,
const string& defaultFolder,
std::vector< std::pair<string, string> >& outFiles);
private:
void 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);
bool ProcessLine(
const string& line,
const std::vector<string>& formats,
const std::vector<string>& wildcards,
const string& defaultFolder,
std::vector< std::pair<string, string> >& outFiles);
bool ReadLines(
const string& listFile,
std::vector<string>& lines);
private:
IResourceCompiler* m_pRC;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_LISTFILE_H
@@ -0,0 +1,38 @@
/*
* 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.
// Description : Memory management functions used by CryMemoryManager
// it looks for them first in the executable, then in CrySystem.dll
// TEMPORARY FIX - define this macro to allow app to be built without using VS2005 SP1 CRT libraries - we
// want to continue using the pre-SP1 libraries (at least for now), since non-programmers don't have the new
// libraries as yet.
#include <stdlib.h>
#include <AzCore/PlatformDef.h>
extern "C" {
AZ_DLL_EXPORT void* CryMalloc(size_t size) {
return malloc(size);
}
AZ_DLL_EXPORT void* CryRealloc(void* memblock, size_t size) {
return realloc(memblock, size);
}
AZ_DLL_EXPORT void* CryReallocSize(void* memblock, size_t oldsize, size_t size) {
return realloc(memblock, size);
}
AZ_DLL_EXPORT void CryFree(void* p) { free(p); }
AZ_DLL_EXPORT void CryFreeSize(void* p, size_t size) { free(p); }
}
@@ -0,0 +1,106 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_MULTIPLATFORMCONFIG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_MULTIPLATFORMCONFIG_H
#pragma once
#include "Config.h"
#include "IMultiplatformConfig.h"
class MultiplatformConfig
: public IMultiplatformConfig
{
public:
MultiplatformConfig()
: m_platformCount(0)
{
}
virtual void init(int platformCount, int activePlatform, IConfigKeyRegistry* pConfigKeyRegistry)
{
if (platformCount < 0 ||
platformCount > kMaxPlatformCount ||
unsigned(activePlatform) >= platformCount ||
pConfigKeyRegistry == 0)
{
assert(0);
m_platformCount = 0;
return;
}
m_platformCount = platformCount;
m_activePlatform = activePlatform;
for (int i = 0; i < platformCount; ++i)
{
m_config[i].SetConfigKeyRegistry(pConfigKeyRegistry);
}
}
virtual int getPlatformCount() const
{
return m_platformCount;
}
virtual int getActivePlatform() const
{
return m_activePlatform;
}
virtual const IConfig& getConfig(int platform) const
{
assert(unsigned(platform) < unsigned(m_platformCount));
return m_config[platform];
}
virtual IConfig& getConfig(int platform)
{
assert(unsigned(platform) < unsigned(m_platformCount));
return m_config[platform];
}
virtual const IConfig& getConfig() const
{
return getConfig(m_activePlatform);
}
virtual IConfig& getConfig()
{
return getConfig(m_activePlatform);
}
virtual void setKeyValue(EConfigPriority ePri, const char* key, const char* value)
{
for (int i = 0; i < m_platformCount; ++i)
{
m_config[i].SetKeyValue(ePri, key, value);
}
}
virtual void setActivePlatform(int platformIndex)
{
m_activePlatform = platformIndex;
}
private:
enum
{
kMaxPlatformCount = 20
};
int m_platformCount;
int m_activePlatform;
Config m_config[kMaxPlatformCount];
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_MULTIPLATFORMCONFIG_H
@@ -0,0 +1,151 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_NAMECONVERTOR_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_NAMECONVERTOR_H
#pragma once
#include "StringHelpers.h"
#include "IRCLog.h" // RCLog
class NameConvertor
{
private:
struct Rule
{
string mask;
string format;
};
std::vector<Rule> m_rules;
public:
bool HasRules() const
{
return !m_rules.empty();
}
bool SetRules(const string& rules)
{
m_rules.clear();
std::vector<string> tmpPairs;
std::vector<string> tmpPair;
StringHelpers::Split(rules, ";", false, tmpPairs);
for (size_t i = 0; i < tmpPairs.size(); ++i)
{
tmpPair.clear();
StringHelpers::Split(tmpPairs[i], ",", false, tmpPair);
if (tmpPair.size() != 2 || tmpPair[0].empty() || tmpPair[1].empty())
{
RCLogError("%s: Syntax error in converting rule: '%s'", __FUNCTION__, tmpPairs[i].c_str());
m_rules.clear();
return false;
}
Rule r;
r.mask = tmpPair[0];
r.format = tmpPair[1];
m_rules.push_back(r);
}
return true;
}
string GetConvertedName(const string& name) const
{
if (name.empty())
{
RCLogError("Empty name sent to %s", __FUNCTION__);
return string();
}
if (m_rules.empty())
{
return name;
}
const Rule* pRule = 0;
std::vector<string> tokens;
for (size_t i = 0; i < m_rules.size(); ++i)
{
if (StringHelpers::MatchesWildcardsIgnoreCase(name, m_rules[i].mask))
{
if (!StringHelpers::MatchesWildcardsIgnoreCaseExt(name, m_rules[i].mask, tokens))
{
RCLogError("Unexpected failure in %s", __FUNCTION__);
return string();
}
pRule = &m_rules[i];
break;
}
}
if (!pRule)
{
return name;
}
string newName = pRule->format;
size_t scanFromPos = 0;
for (;; )
{
const size_t startPos = newName.find('{', scanFromPos);
if (startPos == newName.npos)
{
break;
}
const size_t endPos = newName.find('}', startPos + 1);
if (endPos == newName.npos)
{
break;
}
const string indexStr = newName.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("%s: Syntax error in element {%s} in input string %s", __FUNCTION__, indexStr.c_str(), pRule->format.c_str());
return string();
}
const int index = atoi(indexStr.c_str());
if ((index < 0) || (index > tokens.size()))
{
RCLogError("%s: Bad index specified in {%s} in input string %s", __FUNCTION__, indexStr.c_str(), pRule->format.c_str());
return string();
}
const string& replaceWith = (index == 0) ? name : tokens[index - 1];
newName = newName.replace(startPos, endPos - startPos + 1, replaceWith);
scanFromPos = startPos + replaceWith.size();
}
return newName;
}
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_NAMECONVERTOR_H
@@ -0,0 +1,556 @@
/*
* 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 "PakHelpers.h"
#include "PathHelpers.h"
#include "StringHelpers.h"
#include "StringUtils.h"
#include "FileUtil.h"
#include "IRCLog.h"
#include <AzCore/base.h>
//////////////////////////////////////////////////////////////////////////
bool PakHelpers::PakEntry::MakeSortableStreamingSuffix(const string& suffix, string* sortable, int nDigits, int nIncrement)
{
int nMipmap = 0;
char cAttached = '\0';
char verify[32] = "";
// Scan, recreate and compare to verify if the given string is a valid streaming suffix
#if AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS
int nTokens = sscanf_s(suffix.data(), "%d%c", &nMipmap, &cAttached, 1);
#else
int nTokens = sscanf(suffix.data(), "%d%c", &nMipmap, &cAttached);
#endif
switch (nTokens)
{
case 2:
// .dds.0a, .dds.1a, etc.
azsnprintf(verify, sizeof(verify), "%d%c", nMipmap, cAttached);
break;
case 1:
// .dds.0, .dds.1, etc.
azsnprintf(verify, sizeof(verify), "%d", nMipmap);
break;
default:
// .dds.a
#if AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS
if (sscanf_s(suffix.data(), "%c", &cAttached, 1) == 1)
#else
if (sscanf(suffix.data(), "%c", &cAttached) == 1)
#endif
{
azsnprintf(verify, sizeof(verify), "%c", cAttached);
nTokens = 2;
}
break;
}
if (!StringHelpers::Equals(suffix, verify) || ((nTokens > 1) && (cAttached != 'a')))
{
return false;
}
// Recreate a streaming suffix we can use to sort (constant length)
if (sortable)
{
char digits[32];
if (nDigits > 0)
{
azsnprintf(digits, sizeof(digits), "%%0%dd", nDigits);
}
else
{
cry_strcpy(digits, "%d");
}
if (nTokens > 1)
{
cry_strcat(digits, "%c");
}
switch (nTokens)
{
case 2:
azsnprintf(verify, sizeof(verify), digits, nMipmap + nIncrement, cAttached);
break;
case 1:
azsnprintf(verify, sizeof(verify), digits, nMipmap + nIncrement);
break;
default:
break;
}
*sortable = verify;
}
return true;
}
string PakHelpers::PakEntry::GetRealFilename() const
{
const string sRealFilename = PathHelpers::Join(m_rcFile.m_sourceLeftPath,
m_rcFile.m_sourceInnerPathAndName);
return sRealFilename;
}
string PakHelpers::PakEntry::GetStreamingSuffix() const
{
const size_t splitter = m_rcFile.m_sourceInnerPathAndName.find_last_of('.');
if (splitter == string::npos)
{
return string();
}
// for split DDS files the file extension is .dds, .dds.1, .dds.a, .dds.1a ...
// Take the number part, and return just the mip number and alpha name
const string suffix = m_rcFile.m_sourceInnerPathAndName.substr(splitter + 1);
string sortablesuffix;
if (!MakeSortableStreamingSuffix(suffix, &sortablesuffix))
{
return string();
}
return sortablesuffix;
}
string PakHelpers::PakEntry::GetExtension() const
{
size_t splitter = m_rcFile.m_sourceInnerPathAndName.find_last_of('.');
if (splitter == string::npos)
{
return string();
}
// for DDS files on consoles the file extension is .dds.0, .dds.1, .dds.0a, .dds.1a ...
// Skip the number part, and return the actual file extension without the mip number and alpha name
const string extension = m_rcFile.m_sourceInnerPathAndName.substr(splitter + 1);
if (!MakeSortableStreamingSuffix(extension))
{
return extension;
}
const string tmp = m_rcFile.m_sourceInnerPathAndName.substr(0, splitter);
splitter = tmp.find_last_of('.');
if (splitter == string::npos)
{
return string();
}
return tmp.substr(splitter + 1);
}
string PakHelpers::PakEntry::GetNameWithoutExtension(bool bFilenameOnly) const
{
string name = m_rcFile.m_sourceInnerPathAndName;
if (bFilenameOnly)
{
name = PathHelpers::GetFilename(name);
}
size_t splitter = name.find_last_of('.');
if (splitter == string::npos)
{
return name;
}
// for DDS files on consoles the file extension is .dds.0, .dds.1, .dds.0a, .dds.1a ...
// Skip the number part, and return the actual file extension without the mip number and alpha name
const string extension = name.substr(splitter + 1);
if (MakeSortableStreamingSuffix(extension))
{
name = name.substr(0, splitter);
}
splitter = name.find_last_of('.');
if (splitter == string::npos)
{
return name;
}
return name.substr(0, splitter);
}
string PakHelpers::PakEntry::GetDirnameWithoutFile(bool bRootdirOnly) const
{
string name = m_rcFile.m_sourceInnerPathAndName;
if (bRootdirOnly)
{
const size_t splitter = name.find_first_of("\\/");
if (splitter != string::npos)
{
name = name.substr(0, splitter);
}
else
{
name = "";
}
}
else
{
name = PathHelpers::GetDirectory(name);
}
return name;
}
PakHelpers::ETextureType PakHelpers::PakEntry::GetTextureType() const
{
const string sLowerCaseName = StringHelpers::MakeLowerCase(PathHelpers::RemoveExtension(m_rcFile.m_sourceInnerPathAndName));
if (StringHelpers::EndsWith(sLowerCaseName, "_diff"))
{
return eTextureType_Diffuse;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_ddn") ||
StringHelpers::EndsWith(sLowerCaseName, "_ddna"))
{
return eTextureType_Normal;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_spec"))
{
return eTextureType_Specular;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_detail"))
{
return eTextureType_Detail;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_mask"))
{
return eTextureType_Mask;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_sss"))
{
return eTextureType_SubSurfaceScattering;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_cm") ||
StringHelpers::EndsWith(sLowerCaseName, "_cubemap"))
{
return eTextureType_Cubemap;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_cch"))
{
return eTextureType_Colorchart;
}
if (StringHelpers::EndsWith(sLowerCaseName, "_displ") ||
StringHelpers::EndsWith(sLowerCaseName, "_dmap"))
{
return eTextureType_Displacement;
}
return eTextureType_Undefined;
}
//////////////////////////////////////////////////////////////////////////
namespace
{
struct StreamingFileOrder
{
bool operator()(const PakHelpers::PakEntry& left, const PakHelpers::PakEntry& right) const
{
// first sort by extension
const string& extA = left.m_extension;
const string& extB = right.m_extension;
int res = StringHelpers::CompareIgnoreCase(extA, extB);
if (res != 0)
{
return res < 0;
}
if (StringHelpers::EqualsIgnoreCase(extA, "dds"))
{
// then sort dds textures by type
const PakHelpers::ETextureType eAType = left.m_textureType;
const PakHelpers::ETextureType eBType = right.m_textureType;
if (eAType != eBType)
{
return eAType < eBType;
}
// then sort by name
const string& shortNameA = PathHelpers::Join(left.m_innerDir, left.m_baseName);
const string& shortNameB = PathHelpers::Join(right.m_innerDir, right.m_baseName);
res = StringHelpers::CompareIgnoreCase(shortNameA, shortNameB);
if (res != 0)
{
return res < 0;
}
if (left.m_sourceFileSize != right.m_sourceFileSize)
{
return left.m_sourceFileSize < right.m_sourceFileSize;
}
}
else
{
/*
// The following code is commented out because some of the files
// are loaded directly from an alphabetical resource list which breaks
// the whole loading times
if (left.m_sourceFileSize != right.m_sourceFileSize)
{
return left.m_sourceFileSize < right.m_sourceFileSize;
}
*/
}
res = StringHelpers::CompareIgnoreCase(
left.m_rcFile.m_sourceInnerPathAndName, right.m_rcFile.m_sourceInnerPathAndName);
return res < 0;
}
};
struct SizeFileOrder
{
bool operator()(const PakHelpers::PakEntry& left, const PakHelpers::PakEntry& right) const
{
return left.m_sourceFileSize < right.m_sourceFileSize;
}
};
struct AlphabeticalFileOrder
{
bool operator()(const PakHelpers::PakEntry& left, const PakHelpers::PakEntry& right) const
{
const int res = StringHelpers::CompareIgnoreCase(
left.m_rcFile.m_sourceInnerPathAndName, right.m_rcFile.m_sourceInnerPathAndName);
return res < 0;
}
};
struct StreamingSuffixFileOrder
: public AlphabeticalFileOrder
{
bool operator()(const PakHelpers::PakEntry& left, const PakHelpers::PakEntry& right) const
{
// first sort by streaming suffix
const string& sfxA = left.m_streamingSuffix;
const string& sfxB = right.m_streamingSuffix;
// Empty suffices always at the end of the PAK, no matter what
if (!sfxA.empty() || !sfxB.empty())
{
if (sfxA.empty())
{
return true;
}
if (sfxB.empty())
{
return false;
}
const int res = StringHelpers::CompareIgnoreCase(sfxA, sfxB);
if (res != 0)
{
return res < 0;
}
}
// then sort by name
const string& shortNameA = left.m_baseName;
const string& shortNameB = right.m_baseName;
int res = StringHelpers::CompareIgnoreCase(shortNameA, shortNameB);
if (res != 0)
{
return res < 0;
}
// then sort by extension
const string& extA = left.m_extension;
const string& extB = right.m_extension;
res = StringHelpers::CompareIgnoreCase(extA, extB);
if (res != 0)
{
return res < 0;
}
// then alphabetically
return AlphabeticalFileOrder::operator()(left, right);
}
};
}
//////////////////////////////////////////////////////////////////////////
size_t PakHelpers::CreatePakEntryList(
const std::vector<RcFile>& files,
std::map<string, std::vector<PakHelpers::PakEntry> >& pakEntries,
PakHelpers::ESortType eSortType,
PakHelpers::ESplitType eSplitType,
const string& sPakName)
{
const string sPakBase = PathHelpers::RemoveExtension(PathHelpers::GetFilename(sPakName));
string sPakDir;
size_t entryCount = 0;
for (std::vector<RcFile>::const_iterator it = files.begin(); it != files.end(); ++it)
{
const RcFile& file = *it;
string sNewPakName = sPakName;
bool bSkip = false;
PakEntry entry;
entry.m_rcFile = file;
entry.m_rcFile.m_sourceLeftPath = PathHelpers::ToPlatformPath(file.m_sourceLeftPath);
entry.m_rcFile.m_sourceInnerPathAndName = PathHelpers::ToPlatformPath(file.m_sourceInnerPathAndName);
entry.m_rcFile.m_targetLeftPath = PathHelpers::ToPlatformPath(file.m_targetLeftPath);
// cache values used for fast sorting
entry.m_streamingSuffix = entry.GetStreamingSuffix();
entry.m_extension = entry.GetExtension();
entry.m_textureType = entry.GetTextureType();
entry.m_baseName = entry.GetNameWithoutExtension(true);
entry.m_innerDir = entry.GetDirnameWithoutFile(false);
entry.m_sourceFileSize = FileUtil::GetFileSize(entry.GetRealFilename());
if (eSplitType == eSplitType_ExtensionMipmap)
{
if (entry.m_sourceFileSize >= 0)
{
if (StringHelpers::EqualsIgnoreCase(entry.m_extension, "dds"))
{
if (!entry.m_streamingSuffix.empty())
{
const string szPlainSuffix = entry.m_rcFile.m_sourceInnerPathAndName.substr(entry.m_rcFile.m_sourceInnerPathAndName.find_last_of('.') + 1);
string szIncrementedSuffix = "";
if (entry.MakeSortableStreamingSuffix(szPlainSuffix, &szIncrementedSuffix, 0, 1))
{
string tmpFilename = PathHelpers::Join(file.m_sourceLeftPath, entry.m_innerDir);
tmpFilename = PathHelpers::Join(tmpFilename, entry.m_baseName + "." + entry.m_extension + "." + szIncrementedSuffix);
entry.m_bIsLastMip = !FileUtil::FileExists(tmpFilename);
}
}
if (entry.m_bIsLastMip)
{
sNewPakName = sPakName + string("streaming\\dds_high.pak");
}
else
{
sNewPakName = sPakName + string("streaming\\dds_low.pak");
}
}
else
{
sNewPakName = sPakName + string("streaming\\") + entry.m_extension + string(".pak");
}
}
else
{
bSkip = true;
}
}
else if (eSplitType == eSplitType_Suffix)
{
// filter files without suffices > 0 into different pak
if (!entry.m_streamingSuffix.empty())
{
const string tmpFilename = PathHelpers::Join(file.m_sourceLeftPath,
entry.m_innerDir + "\\" + entry.m_baseName + "." + entry.m_extension + ".1");
if (!FileUtil::FileExists(tmpFilename))
{
entry.m_streamingSuffix = "";//"00o";
}
}
sNewPakName = sPakDir + sPakBase + "-m" + entry.m_streamingSuffix + string(".pak");
}
else if (eSplitType == eSplitType_Basedir)
{
sNewPakName = sPakDir + entry.GetDirnameWithoutFile(true) + string(".pak");
}
else
{
if (eSortType == eSortType_Size)
{
bSkip = !(entry.m_sourceFileSize >= 0);
}
}
if (StringHelpers::EqualsIgnoreCase(entry.m_extension, "$dds") ||
StringHelpers::EqualsIgnoreCase(entry.m_extension, "pak"))
{
bSkip = true;
}
if (!bSkip)
{
pakEntries[sNewPakName].push_back(entry);
++entryCount;
}
}
// sort the entries by requested sorting operator
for (std::map<string, std::vector<PakEntry> >::iterator it = pakEntries.begin(); it != pakEntries.end(); ++it)
{
std::vector<PakEntry>& files = it->second;
// Sort by type
switch (eSortType)
{
case PakHelpers::eSortType_NoSort:
{
RCLog("Using sort method to add to pack : nosort");
break;
}
case PakHelpers::eSortType_Size:
{
RCLog("Using sort method to add to pack : size");
// Sort alphabetically first so there is a consistent ordering before sorting by size
// (to ensure that files with the same size are ordered by name)
std::sort(files.begin(), files.end(), AlphabeticalFileOrder());
std::stable_sort(files.begin(), files.end(), SizeFileOrder());
break;
}
case PakHelpers::eSortType_Streaming:
{
RCLog("Using sort method to add to pack : streaming");
std::sort(files.begin(), files.end(), StreamingFileOrder());
break;
}
case PakHelpers::eSortType_Suffix:
{
RCLog("Using sort method to add to pack : suffix");
std::sort(files.begin(), files.end(), StreamingSuffixFileOrder());
break;
}
case PakHelpers::eSortType_Alphabetically:
{
RCLog("Using sort method to add to pack : alphabetically");
std::sort(files.begin(), files.end(), AlphabeticalFileOrder());
break;
}
default:
{
assert(0);
RCLogError("Using sort method to add to pack : undefined!");
break;
}
}
}
return entryCount;
}
//////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,92 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PAKHELPERS_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PAKHELPERS_H
#pragma once
#include <map> // stl multimap<>
#include "RcFile.h"
namespace PakHelpers
{
enum ESortType
{
eSortType_NoSort, // don't sort files
eSortType_Size, // sort files by size
eSortType_Streaming, // sort files by extension+type+name+size
eSortType_Suffix, // sort files by suffix+name+extension
eSortType_Alphabetically, // sort files by full path
};
enum ESplitType
{
eSplitType_Original, // don't create paks differing from the original configuration (XML or command line)
eSplitType_Basedir, // split paks by base directory name
eSplitType_ExtensionMipmap, // split paks by extension and mipmap level (high/low)
eSplitType_Suffix, // split paks by suffix
};
enum ETextureType
{
eTextureType_Diffuse,
eTextureType_Normal,
eTextureType_Specular,
eTextureType_Detail,
eTextureType_Mask,
eTextureType_SubSurfaceScattering,
eTextureType_Cubemap,
eTextureType_Colorchart,
eTextureType_Displacement,
eTextureType_Undefined,
};
struct PakEntry
{
PakEntry()
: m_sourceFileSize(-1)
, m_bIsLastMip(false)
{
}
RcFile m_rcFile;
int64 m_sourceFileSize;
bool m_bIsLastMip;
string m_streamingSuffix;
string m_extension;
ETextureType m_textureType;
string m_baseName;
string m_innerDir;
static bool MakeSortableStreamingSuffix(const string& suffix, string* sortable = NULL, int nDigits = 2, int nIncrement = 0);
string GetRealFilename() const;
string GetStreamingSuffix() const;
string GetExtension() const;
string GetNameWithoutExtension(bool bFilenameOnly) const;
string GetDirnameWithoutFile(bool bRootdirOnly) const;
ETextureType GetTextureType() const;
};
size_t CreatePakEntryList(
const std::vector<RcFile>& files,
std::map<string, std::vector<PakEntry> >& pakEntries,
ESortType eSortType,
ESplitType eSplitType,
const string& sPakName);
}
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PAKHELPERS_H
@@ -0,0 +1,934 @@
/*
* 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 "PakManager.h"
#if defined(AZ_PLATFORM_WINDOWS)
#include <Shlwapi.h> // PathRelativePathTo(), PathCanonicalize()
#pragma message("Note: including Shlwapi.lib")
#pragma comment(lib, "Shlwapi.lib")
#endif
#include "IRCLog.h"
#include "FileUtil.h"
#include <ResourceCompiler.h> // for functions like GetSourceRootsReversed
#include "CryCrc32.h"
#include "ZipEncryptor.h"
#include "ThreadUtils.h"
#include <AzCore/std/algorithm.h>
#include <AzCore/IO/SystemFile.h>
//////////////////////////////////////////////////////////////////////////
PakManager::PakManager(IProgress* pProgress)
: m_pProgress(pProgress)
{
}
PakManager::~PakManager()
{
}
void PakManager::RegisterKeys(IResourceCompiler* pRC)
{
pRC->RegisterKey("split_listfile_to_zips", "split a list file into multiple zip files");
pRC->RegisterKey("zip", "Compress source files into the zip file specified with this parameter");
pRC->RegisterKey("zip_encrypt", "Encrypts headers of zip files. Disabled by default.");
pRC->RegisterKey("zip_encrypt_key", "Specifies a 128-bit key in hexadecimal format: 32-character string. Low endian format.");
pRC->RegisterKey("zip_encrypt_content", "Encrypts files inside of zip. Works only when zip_encrypt enabled. Disabled by default.");
pRC->RegisterKey("zip_compression", "Specify compression level for zipped files. [0-9] 0=no compression, 9=max compression. Default is 6.");
pRC->RegisterKey("zip_sort", "Define sorting type when adding files to the pak, currently supported:\n"
"nosort, size, streaming, suffix, alphabetically. Alphabetically is default.");
pRC->RegisterKey("zip_split", "Define split type for distributing files into different paks automatically, currently supported:\n"
"original, basedir, streaming, suffix. 'original' is default, except for streaming for which it is streaming.");
pRC->RegisterKey("zip_maxsize", "Maximum compressed size of the zip in KBs");
pRC->RegisterKey("zip_sizesplit", "Split zip files automatically when the maximum compressed size (configured or supported) has been reached");
pRC->RegisterKey("zip_alignment", "Alignment of files inside zip. Default is 1 byte.");
pRC->RegisterKey("zip_new", "Forces creation of new zip file overwriting existing one");
pRC->RegisterKey("FolderInZip", "Put source files into this specified folder inside of zip file (see 'zip' command)");
pRC->RegisterKey("sourceminsize", "only copy or zip a source file if its size is greater or equal than the size specified. used with 'copyonly' and 'zip' commands.");
pRC->RegisterKey("sourcemaxsize", "only copy or zip a source file if its size is less or equal than the size specified. used with 'copyonly' and 'zip' commands.");
pRC->RegisterKey("unzip", "Decompress source file into the specified folder with this parameter");
}
//////////////////////////////////////////////////////////////////////////
IPakSystem* PakManager::GetPakSystem()
{
return &m_pPakSystem;
}
//////////////////////////////////////////////////////////////////////////
unsigned PakManager::GetMaxThreads() const
{
return AZStd::GetMax<unsigned>(1, AZStd::thread::hardware_concurrency() / 2);
}
//////////////////////////////////////////////////////////////////////////
bool PakManager::HasPakFiles() const
{
return m_zipFiles.size() > 0;
}
//////////////////////////////////////////////////////////////////////////
PakManager::ECallResult PakManager::CompileFilesIntoPaks(
const IConfig* config,
const std::vector<RcFile>& m_allFiles)
{
{
const string pakFilePath = config->GetAsString("split_listfile_to_zips", "", "");
if (!pakFilePath.empty())
{
std::vector<string> sourceRootsReversed;
ResourceCompiler::GetSourceRootsReversed(config, sourceRootsReversed);
return SplitListFileToPaks(config, sourceRootsReversed, m_allFiles, pakFilePath);
}
}
{
const string pakFilename = config->GetAsString("zip", "", "");
if (!pakFilename.empty())
{
const string folderInPak = config->GetAsString("FolderInZip", "", "");
const bool bUpdate = !config->GetAsBool("zip_new", false, true); // forces to recreate pak-file
return CreatePakFile(config, m_allFiles, folderInPak, pakFilename, bUpdate);
}
}
{
const string unzipFolder = config->GetAsString("unzip", "", "");
if (!unzipFolder.empty())
{
return UnzipPakFile(config, m_allFiles, unzipFolder);
}
}
return eCallResult_Skipped;
}
//////////////////////////////////////////////////////////////////////////
PakManager::ECallResult PakManager::SplitListFileToPaks(
const IConfig* config,
const std::vector<string>& sourceRootsReversed,
const std::vector<RcFile>& files,
const string& pakFilePath)
{
typedef std::map<string, std::vector<RcFile> > TSplitListMap;
TSplitListMap splitListMap;
for (size_t i = 0; i < files.size(); ++i)
{
const string line(files[i].m_sourceInnerPathAndName);
const size_t splitter = line.find_first_of("|;,");
if (splitter == string::npos)
{
continue;
}
string groupName = line.substr(0, splitter);
string fileName = line.substr(splitter + 1);
groupName.Trim();
fileName.Trim();
const string sourceLeftPath = ResourceCompiler::FindSuitableSourceRoot(sourceRootsReversed, fileName);
splitListMap[groupName].push_back(RcFile(sourceLeftPath, fileName, ""));
}
for (TSplitListMap::iterator it = splitListMap.begin(); it != splitListMap.end(); ++it)
{
const string& groupName = it->first;
std::vector<RcFile>& fileList = it->second;
const string pakFilename = pakFilePath + groupName + ".pak";
CreatePakFile(config, fileList, "", pakFilename, true);
}
return eCallResult_Succeeded;
}
//////////////////////////////////////////////////////////////////////////
PakManager::ECallResult PakManager::DeleteFilesFromPaks(
const IConfig* config,
const std::vector<string>& deletedTargetFiles)
{
if (HasPakFiles() && deletedTargetFiles.size())
{
RCLog("Deleting files from zip archives");
return SynchronizePaks(config, deletedTargetFiles);
}
return eCallResult_Skipped;
}
PakManager::ECallResult PakManager::SynchronizePaks(
const IConfig* config,
const std::vector<string>& deletedTargetFiles)
{
const int nTotalToScan = m_zipFiles.size() * deletedTargetFiles.size();
const int zipFileAlignment = config->GetAsInt("zip_alignment", 1, 1);
int nDeletedInZip = 0;
int nScannedFiles = 0;
// If we created some zip file, check if files need to be deleted from them.
for (size_t nzip = 0; (nzip < m_zipFiles.size()) && (nTotalToScan > 0); ++nzip)
{
string zipFilename = m_zipFiles[nzip];
PakSystemArchive* pPakFile = GetPakSystem()->OpenArchive(zipFilename.c_str(), zipFileAlignment);
if (pPakFile)
{
const string progress = string("Deleting files from ") + zipFilename;
char szRelative[MAX_PATH];
string zipFileDir = PathHelpers::GetDirectory(zipFilename);
for (size_t i = 0; i < deletedTargetFiles.size(); ++i)
{
string filename = deletedTargetFiles[i];
#if defined(AZ_PLATFORM_WINDOWS)
// Detect path offset of the zip location to source folder
if (TRUE == PathRelativePathTo(szRelative, zipFileDir.c_str(), FILE_ATTRIBUTE_DIRECTORY, filename.c_str(), FILE_ATTRIBUTE_NORMAL))
{
char szRelative2[MAX_PATH];
PathCanonicalize(szRelative2, szRelative);
filename = szRelative2;
}
#else
//TODO: Needs implementation for other platforms via localFileIo. Adding an assert for now in case this code gets run.
assert(0);
#endif
++nScannedFiles;
if (GetPakSystem()->DeleteFromArchive(pPakFile, filename.c_str()))
{
++nDeletedInZip;
RCLog("Remove file from zip: [%s] %s", zipFilename.c_str(), filename.c_str());
}
m_pProgress->ShowProgress(progress.c_str(), nScannedFiles, nTotalToScan);
}
GetPakSystem()->CloseArchive(pPakFile);
}
}
return eCallResult_Succeeded;
}
//////////////////////////////////////////////////////////////////////////
PakManager::ECallResult PakManager::CreatePakFile(
const IConfig* config,
const std::vector<RcFile>& sourceFiles,
const string& folderInPak,
const string& requestedPakFilename,
bool bUpdate)
{
const int iVerbose = config->GetAsInt("verbose", 0, 1);
const bool bSkipMissing = config->GetAsBool("skipmissing", false, true);
if (iVerbose > 0)
{
RCLog("CreatingPakFile %s ...", requestedPakFilename.c_str());
}
PakHelpers::ESortType eSortType = PakHelpers::eSortType_Alphabetically;
const string sortType = config->GetAsString("zip_sort", "", "");
if (!sortType.empty())
{
if (StringHelpers::EqualsIgnoreCase(sortType, "nosort"))
{
eSortType = PakHelpers::eSortType_NoSort;
}
else if (StringHelpers::EqualsIgnoreCase(sortType, "size"))
{
eSortType = PakHelpers::eSortType_Size;
}
else if (StringHelpers::EqualsIgnoreCase(sortType, "streaming"))
{
eSortType = PakHelpers::eSortType_Streaming;
}
else if (StringHelpers::EqualsIgnoreCase(sortType, "suffix"))
{
eSortType = PakHelpers::eSortType_Suffix;
}
else if (StringHelpers::EqualsIgnoreCase(sortType, "alphabetically"))
{
eSortType = PakHelpers::eSortType_Alphabetically;
}
else
{
RCLogError("Invalid zip_sort argument: '%s'. Creating of pak failed.", sortType.c_str());
return eCallResult_BadArgs;
}
}
PakHelpers::ESplitType eSplitType = PakHelpers::eSplitType_Original;
if (eSortType == PakHelpers::eSortType_Streaming)
{
eSplitType = PakHelpers::eSplitType_ExtensionMipmap;
}
const string splitType = config->GetAsString("zip_split", "", "");
if (!splitType.empty())
{
if (StringHelpers::EqualsIgnoreCase(splitType, "original"))
{
eSplitType = PakHelpers::eSplitType_Original;
}
else if (StringHelpers::EqualsIgnoreCase(splitType, "basedir"))
{
eSplitType = PakHelpers::eSplitType_Basedir;
}
else if (StringHelpers::EqualsIgnoreCase(splitType, "streaming"))
{
eSplitType = PakHelpers::eSplitType_ExtensionMipmap;
}
else if (StringHelpers::EqualsIgnoreCase(splitType, "suffix"))
{
eSplitType = PakHelpers::eSplitType_Suffix;
}
else
{
RCLogError("Invalid zip_split argument: '%s'. Creating of pak failed.", splitType.c_str());
return eCallResult_BadArgs;
}
}
string platformPakFilename = PathHelpers::ToPlatformPath(requestedPakFilename);
if (!FileUtil::EnsureDirectoryExists(PathHelpers::GetDirectory(platformPakFilename).c_str()))
{
RCLogError("Failed creating directory for %s", platformPakFilename.c_str());
return eCallResult_Failed;
}
std::map<string, std::vector<PakHelpers::PakEntry> > fileMap;
{
const size_t nCount = PakHelpers::CreatePakEntryList(sourceFiles, fileMap, eSortType, eSplitType, platformPakFilename);
if (nCount == 0)
{
return eCallResult_Failed;
}
RCLog("Requested %u files to be packed. Found %u valid files to add.", sourceFiles.size(), nCount);
}
std::set<unsigned int> crc32set;
const bool name_as_crc32 = config->GetAsBool("name_as_crc32", false, true);
const int nMinZipSize = sizeof(ZipFile::CDREnd); // size of an empty CDR
const int nMaxZipSize = config->GetAsInt("zip_maxsize", 0, 0) * 1024;
const bool bSplitOnSizeOverflow = config->GetAsBool("zip_sizesplit", false, true);
const int nMaxSrcSize = config->GetAsInt("sourcemaxsize", -1, -1);
const int nMinSrcSize = config->GetAsInt("sourceminsize", 0, 0);
const int zipCompressionLevel = config->GetAsInt("zip_compression", 6, 6);
const bool useFastestDecompressionCodec = config->GetAsBool("use_fastest", false, false);
ECallResult bResult = eCallResult_Succeeded;
for (std::map<string, std::vector<PakHelpers::PakEntry> >::iterator it = fileMap.begin(); it != fileMap.end(); ++it)
{
const string& pakFilename = it->first;
std::vector<PakHelpers::PakEntry>& files = it->second;
RCLog("Found %u valid files to add to zip file %s", files.size(), pakFilename.c_str());
AZ::IO::LocalFileIO localFileIO;
if (!bUpdate)
{
#if defined(AZ_PLATFORM_WINDOWS)
// Delete old pak file.
::SetFileAttributes(pakFilename.c_str(), FILE_ATTRIBUTE_ARCHIVE);
#endif
localFileIO.Remove(pakFilename.c_str());
}
if (!FileUtil::EnsureDirectoryExists(PathHelpers::GetDirectory(pakFilename).c_str()))
{
RCLogError("Failed creating directory for %s", pakFilename.c_str());
return eCallResult_Failed;
}
const int zipFileAlignment = config->GetAsInt("zip_alignment", 1, 1);
const bool zipEncrypt = config->GetAsBool("zip_encrypt", false, true);
const bool zipEncryptContent = config->GetAsBool("zip_encrypt_content", false, true);
const string zipEncryptKey = config->GetAsString("zip_encrypt_key", "", "");
uint32 encryptionKey[4];
if (!zipEncryptKey.empty())
{
if (!ZipEncryptor::ParseKey(encryptionKey, zipEncryptKey.c_str()))
{
RCLogError("Misformed zip_encrypt_key: expected 128-bit integer in hexadecimal format (32 character)");
return eCallResult_Failed;
}
}
// check if pak is multi-part and redirect it before opening the pak
bool bMultiPartPak = false;
string pakFilenameToWrite = pakFilename;
if (bSplitOnSizeOverflow)
{
string pakFilenameMultiPart = pakFilename;
pakFilenameMultiPart.replace(".pak", "-part0.pak");
if (FileUtil::FileExists(pakFilenameMultiPart))
{
RCLog("Found explicit multi-part zip, writing to zip file %s instead", pakFilenameMultiPart.c_str());
bMultiPartPak = true;
pakFilenameToWrite = pakFilenameMultiPart;
}
}
const size_t numFiles = files.size();
size_t numFilesAdded = 0;
size_t numFilesUpToDate = 0;
size_t numFilesSkipped = 0;
size_t numFilesMissing = 0;
size_t numFilesFailed = 0;
const string sProgressOp = "Adding files to zip file " + pakFilenameToWrite;
m_pProgress->StartProgress();
std::vector<string> realFilenames;
std::vector<string> filenamesInZip;
realFilenames.reserve(numFiles);
filenamesInZip.reserve(numFiles);
// create list of filenames
for (size_t i = 0; i < numFiles; ++i)
{
string sFileNameInZip = PathHelpers::RemoveDuplicateSeparators(PathHelpers::ToPlatformPath(PathHelpers::Join(folderInPak, files[i].m_rcFile.m_sourceInnerPathAndName)));
const string sRealFilename = PathHelpers::Join(files[i].m_rcFile.m_sourceLeftPath, files[i].m_rcFile.m_sourceInnerPathAndName);
// Skip files with extensions starting with "$" or "pak".
{
const string ext = PathHelpers::FindExtension(sRealFilename);
if (!ext.empty() && (ext[0] == '$' || _stricmp(ext, "pak") == 0))
{
++numFilesSkipped;
continue;
}
}
if (name_as_crc32)
{
const unsigned int crc32 = CCrc32::ComputeLowercase(sFileNameInZip.c_str());
if (crc32set.find(crc32) != crc32set.end())
{
RCLogError("Duplicate CRC32 code %X for file %s when creating Pak File: %s", crc32, sFileNameInZip.c_str(), pakFilenameToWrite.c_str());
++numFilesFailed;
bResult = eCallResult_Erroneous;
break;
}
crc32set.insert(crc32);
sFileNameInZip.Format("%X", crc32);
}
filenamesInZip.push_back(sFileNameInZip);
realFilenames.push_back(sRealFilename);
}
std::vector<const char*> realFilenamePtrs;
std::vector<const char*> filenameInZipPtrs;
std::vector<const char*> filenameInZipPtrsForDelete;
size_t filenameCount = realFilenames.size();
assert(filenameCount == filenamesInZip.size());
realFilenamePtrs.resize(filenameCount);
filenameInZipPtrs.resize(filenameCount);
for (size_t i = 0; i < filenameCount; ++i)
{
realFilenamePtrs[i] = realFilenames[i].c_str();
filenameInZipPtrs[i] = filenamesInZip[i].c_str();
}
size_t currentPakPart = 0;
bool bKeepTrying = false;
do
{
// Add them to pak file.
PakSystemArchive* pPakFile = GetPakSystem()->OpenArchive(pakFilenameToWrite.c_str(), zipFileAlignment, zipEncrypt, zipEncryptKey.empty() ? 0 : encryptionKey);
if (!pPakFile)
{
// Problem to accss the file? it could have get corrupted so try to delete the file and recreate it
AZ::IO::SystemFile::Delete(pakFilenameToWrite.c_str());
pPakFile = GetPakSystem()->OpenArchive(pakFilenameToWrite.c_str(), zipFileAlignment, zipEncrypt, zipEncryptKey.empty() ? 0 : encryptionKey);
if (!pPakFile)
{
RCLogError("Error: Failed to create zip file %s", pakFilenameToWrite.c_str());
return eCallResult_Failed;
}
}
// submit files for packing
{
struct ZipErrorReporter
: public ZipDir::IReporter
{
IProgress& m_progress;
const char* m_zipFilename;
bool m_bVerbose;
size_t m_fileCount;
size_t& m_numFilesAdded;
size_t& m_numFilesUpToDate;
size_t& m_numFilesSkipped;
size_t& m_numFilesMissing;
size_t& m_numFilesFailed;
ZipErrorReporter(IProgress& progress, const char* zipFilename, int numFiles, bool verbose,
size_t& numFilesAdded, size_t& numFilesUpToDate, size_t& numFilesSkipped, size_t& numFilesMissing, size_t& numFilesFailed)
: m_progress(progress)
, m_zipFilename(zipFilename)
, m_bVerbose(verbose)
, m_fileCount(numFiles)
, m_numFilesAdded(numFilesAdded)
, m_numFilesUpToDate(numFilesUpToDate)
, m_numFilesSkipped(numFilesSkipped)
, m_numFilesMissing(numFilesMissing)
, m_numFilesFailed(numFilesFailed)
{
}
virtual void ReportAdded(const char* filename)
{
if (m_bVerbose)
{
RCLog("Zip [%s]: added file %s", m_zipFilename, filename);
}
++m_numFilesAdded;
ShowProgress();
}
virtual void ReportMissing(const char* filename)
{
RCLogWarning("Zip [%s]: missing file %s", m_zipFilename, filename);
++m_numFilesMissing;
ShowProgress();
}
virtual void ReportUpToDate(const char* filename)
{
if (m_bVerbose)
{
RCLog("Zip [%s]: up to date %s", m_zipFilename, filename);
}
++m_numFilesUpToDate;
ShowProgress();
}
virtual void ReportSkipped(const char* filename)
{
RCLog("Zip [%s]: skipped %s", m_zipFilename, filename);
++m_numFilesSkipped;
ShowProgress();
}
virtual void ReportFailed(const char* filename, const char* reason)
{
RCLog("Zip [%s]: failed to add %s. %s", m_zipFilename, filename, reason);
++m_numFilesFailed;
ShowProgress();
}
virtual void ReportSpeed(double speed)
{
RCLog("Zip [%s] compression speed: %.2f MB/sec", m_zipFilename, speed / 1024.0 / 1024.0);
ShowProgress();
}
void ShowProgress()
{
size_t processedFiles = m_numFilesAdded + m_numFilesUpToDate + m_numFilesFailed + m_numFilesSkipped + m_numFilesMissing;
m_progress.ShowProgress("Adding files into pak", processedFiles, m_fileCount);
}
};
struct ZipSizeSplitter
: public ZipDir::ISplitter
{
int m_fileLast;
int m_fileCount;
size_t m_fileSizeLimit;
size_t m_fileSizeThreshold;
ZipSizeSplitter(int filenameCount, size_t filesizeLimit)
: m_fileLast(filenameCount - 1)
, m_fileCount(filenameCount - 1)
, m_fileSizeLimit(filesizeLimit)
, m_fileSizeThreshold(0)
{
}
virtual bool CheckWriteLimit(size_t total, size_t add, size_t sub) const
{
return ((total - sub) > (m_fileSizeLimit - add));
}
virtual void SetLastFile([[maybe_unused]] size_t total, size_t add, [[maybe_unused]] size_t sub, int last)
{
m_fileLast = last;
m_fileSizeThreshold = m_fileSizeLimit - add;
}
bool HasReachedWriteLimit() const
{
return m_fileLast < m_fileCount;
}
};
ZipErrorReporter errorReporter(*m_pProgress, pakFilenameToWrite.c_str(), numFiles, iVerbose>1,
numFilesAdded, numFilesUpToDate, numFilesSkipped, numFilesMissing, numFilesFailed);
ZipSizeSplitter sizeSplitter(filenameCount, nMaxZipSize ? min(nMaxZipSize, INT_MAX) : INT_MAX);
RCLog("Adding files into %s...", pakFilenameToWrite.c_str());
pPakFile->zip->UpdateMultipleFiles(&realFilenamePtrs[0], &filenameInZipPtrs[0], filenameCount,
zipCompressionLevel, zipEncrypt && zipEncryptContent, nMaxZipSize, nMinSrcSize, nMaxSrcSize,
GetMaxThreads(), &errorReporter, bSplitOnSizeOverflow ? &sizeSplitter : nullptr, useFastestDecompressionCodec);
// divide files in case it has overflown the maximum allowed file-size
if (bSplitOnSizeOverflow)
{
char cPart[16];
char nPart[16];
azsnprintf(cPart, sizeof(cPart), "-part%zu.pak", currentPakPart + 0);
azsnprintf(nPart, sizeof(nPart), "-part%zu.pak", currentPakPart + 1);
const size_t pos = pakFilenameToWrite.find(cPart);
if (!bKeepTrying)
{
// delete previously consumed files from archive
const size_t filenameCountForDelete = filenameInZipPtrsForDelete.size();
for (size_t i = 0; i < filenameCountForDelete; ++i)
{
pPakFile->zip->RemoveFile(filenameInZipPtrsForDelete[i]);
}
}
// move consumed filenames into deletable list
const size_t filenameCountForDelete = filenameInZipPtrsForDelete.size();
const size_t filenameCountConsumed = sizeSplitter.m_fileLast + 1;
filenameInZipPtrsForDelete.resize(filenameCountForDelete + filenameCountConsumed);
memcpy(&filenameInZipPtrsForDelete[filenameCountForDelete],
&filenameInZipPtrs[0], sizeof(filenameInZipPtrs[0]) * filenameCountConsumed);
filenameCount -= filenameCountConsumed;
if (filenameCount > 0)
{
assert(realFilenamePtrs.size() > filenameCountConsumed);
memmove(&realFilenamePtrs[0], &realFilenamePtrs[filenameCountConsumed],
sizeof(realFilenamePtrs[0]) * filenameCount);
assert(filenameInZipPtrs.size() > filenameCountConsumed);
memmove(&filenameInZipPtrs[0], &filenameInZipPtrs[filenameCountConsumed],
sizeof(filenameInZipPtrs[0]) * filenameCount);
}
realFilenamePtrs.resize(filenameCount);
filenameInZipPtrs.resize(filenameCount);
if (!bKeepTrying)
{
// delete skipped over files from archive
for (size_t i = 0; i < filenameCount; ++i)
{
pPakFile->zip->RemoveFile(filenameInZipPtrs[i]);
}
}
if (sizeSplitter.HasReachedWriteLimit())
{
RCLog("Hitting limit of %d bytes on %s, trying reconsolidation...", sizeSplitter.m_fileSizeLimit, pakFilenameToWrite.c_str());
// close archive
GetPakSystem()->CloseArchive(pPakFile);
// check if the reconsolidation of the pak gave more space free than we needed previously
// in case it did, keep adding to the same file, instead of adding it to the next part
const int64 fileSize = FileUtil::GetFileSize(pakFilenameToWrite);
if (fileSize < sizeSplitter.m_fileSizeThreshold)
{
// if we tried keepTrying without effect, don't try again
if ((filenameCountConsumed != 0) || !bKeepTrying)
{
if (pos == string::npos)
{
RCLog("Reconsolidation on %s dropped at least %d bytes below %d, keep adding...", pakFilenameToWrite.c_str(), sizeSplitter.m_fileSizeLimit - sizeSplitter.m_fileSizeThreshold, sizeSplitter.m_fileSizeLimit);
}
else
{
RCLog("Reconsolidation on %s dropped at least %d bytes below %d, keep adding to part %d...", pakFilenameToWrite.c_str(), sizeSplitter.m_fileSizeLimit - sizeSplitter.m_fileSizeThreshold, sizeSplitter.m_fileSizeLimit, currentPakPart);
}
bKeepTrying = true;
continue;
}
}
// rename archive if it's the first time becoming multi-part
if (pos == string::npos)
{
RCLog("Start splitting %s, writing to part %d...", pakFilenameToWrite.c_str(), currentPakPart + 1);
string pakFilenameToRename = pakFilenameToWrite;
pakFilenameToRename.replace(".pak", cPart);
localFileIO.Rename(pakFilenameToWrite.c_str(), pakFilenameToRename.c_str());
bMultiPartPak = true;
pakFilenameToWrite = pakFilenameToRename;
}
else
{
RCLog("Continue splitting %s, writing to part %d...", pakFilenameToWrite.c_str(), currentPakPart + 1);
}
// continue adding to the next part
pakFilenameToWrite.replace(cPart, nPart);
currentPakPart++;
bKeepTrying = false;
continue;
}
assert(filenameCount == 0);
assert(realFilenamePtrs.size() == 0);
assert(filenameInZipPtrs.size() == 0);
}
else
{
filenameCount = 0;
realFilenamePtrs.clear();
filenameInZipPtrs.clear();
}
}
GetPakSystem()->CloseArchive(pPakFile);
const int64 fileSize = FileUtil::GetFileSize(pakFilenameToWrite);
if (fileSize > INT_MAX)
{
RCLogError("PAK File size exceeds 2GB limit. This will not be loaded by Engine: %s", pakFilenameToWrite.c_str());
}
else if (bSplitOnSizeOverflow && bMultiPartPak)
{
// delete all 0 size pak-parts and close holes in the numbering of the parts
bool trailingUntouched = false;
int trailingPakPart = currentPakPart;
for (;; )
{
char cPart[16];
char nPart[16];
azsnprintf(cPart, sizeof(cPart), "-part%d.pak", trailingPakPart + 0);
azsnprintf(nPart, sizeof(nPart), "-part%d.pak", trailingPakPart + 1);
string pakFilenameToDelete = pakFilename;
pakFilenameToDelete.replace(".pak", cPart);
if (!FileUtil::FileExists(pakFilenameToDelete))
{
break;
}
// delete skipped over files from archives not touched
if (trailingUntouched)
{
PakSystemArchive* const pPakFile2 = GetPakSystem()->OpenArchive(pakFilenameToDelete.c_str(), zipFileAlignment, zipEncrypt, zipEncryptKey.empty() ? 0 : encryptionKey);
if (pPakFile2)
{
const size_t filenameCountForDelete = filenameInZipPtrsForDelete.size();
for (size_t i = 0; i < filenameCountForDelete; ++i)
{
pPakFile2->zip->RemoveFile(filenameInZipPtrsForDelete[i]);
}
GetPakSystem()->CloseArchive(pPakFile2);
}
}
const int64 fileSize2 = FileUtil::GetFileSize(pakFilenameToDelete);
if (fileSize2 <= nMinZipSize)
{
// eliminate paks without content (may occur by filtering or reordering)
localFileIO.Remove(pakFilenameToDelete);
// shift successive part-names into the hole left by the deleted pak
for (int q = trailingPakPart;; q++)
{
char cPart2[16];
char nPart2[16];
azsnprintf(cPart2, sizeof(cPart2), "-part%d.pak", q + 0);
azsnprintf(nPart2, sizeof(nPart2), "-part%d.pak", q + 1);
string pakFilenameToReplace = pakFilename;
string pakFilenameToRename = pakFilename;
pakFilenameToReplace.replace(".pak", cPart2);
pakFilenameToRename.replace(".pak", nPart2);
if (!FileUtil::FileExists(pakFilenameToRename))
{
break;
}
localFileIO.Rename(pakFilenameToRename.c_str(), pakFilenameToReplace.c_str());
}
}
else
{
++trailingPakPart;
}
trailingUntouched = true;
}
{
string pakFilenameFirstPart = pakFilename;
string pakFilenameNextPart = pakFilename;
pakFilenameFirstPart.replace(".pak", "-part0.pak");
pakFilenameNextPart.replace(".pak", "-part1.pak");
// remove part-suffix if just one part exists after cleanup
if (FileUtil::FileExists(pakFilenameFirstPart) &&
!FileUtil::FileExists(pakFilenameNextPart))
{
localFileIO.Rename(pakFilenameFirstPart.c_str(), pakFilename.c_str());
m_zipFiles.push_back(pakFilename);
}
// register all parts of the pak for sucessive operations
else
{
for (int q = 0; q < trailingPakPart; q++)
{
char cPart[16];
azsnprintf(cPart, sizeof(cPart), "-part%d.pak", q + 0);
string pakFilenamePart = pakFilename;
pakFilenamePart.replace(".pak", cPart);
m_zipFiles.push_back(pakFilenamePart);
}
}
}
}
else if (fileSize <= nMinZipSize)
{
// eliminate paks without content (may occur by filtering)
localFileIO.Remove(pakFilenameToWrite);
}
else
{
// Add this zip to the array.
m_zipFiles.push_back(pakFilenameToWrite);
}
bKeepTrying = false;
} while (filenameCount);
RCLog("Finished adding %d files to zip file %s:",
numFiles, pakFilename.c_str());
RCLog(" %d added, %d up-to-date, %d skipped, %d missing, %d failed",
numFilesAdded, numFilesUpToDate, numFilesSkipped, numFilesMissing, numFilesFailed);
}
return bResult;
}
struct UnpakParameters
{
typedef AZStd::function<void(bool, const string&)> OnFinishCallback;
ZipDir::CachePtr m_cache;
string m_srcFile;
string m_destFolder;
OnFinishCallback& m_onFinishCb;
};
PakManager::ECallResult PakManager::UnzipPakFile(const IConfig* config, const std::vector<RcFile>& sourceFiles, const string& unzipFolder)
{
const string zipDecryptKey = config->GetAsString("zip_encrypt_key", "", "");
const int decryptKeySizeInUint32 = 4;
uint32 decryptionKey[decryptKeySizeInUint32];
if (!zipDecryptKey.empty())
{
if (!ZipEncryptor::ParseKey(decryptionKey, zipDecryptKey.c_str()))
{
RCLogError("Misformed zip_encrypt_key: expected 128-bit integer in hexadecimal format (32 character)");
return eCallResult_Failed;
}
}
ThreadUtils::SimpleThreadPool pool(false);
std::vector<UnpakParameters> params;
params.reserve(sourceFiles.size());
// Don't capture parameters in the lambda so it can be converted to a function pointer. Instead pack everything in a struct that is passed as an argument.
auto unpakFunc = [](UnpakParameters* params)
{
params->m_onFinishCb(params->m_cache->UnpakToDisk(params->m_destFolder), params->m_srcFile);
};
AZStd::mutex progressMutex;
size_t currentProgress = 0;
UnpakParameters::OnFinishCallback onFinishCb = [&](bool result, const string& srcFile)
{
AZStd::lock_guard<AZStd::mutex> lock(progressMutex);
string msg = (result ? "Finished unpacking file " : "Failed to unpack file ") + srcFile;
m_pProgress->ShowProgress(msg.c_str(), ++currentProgress, sourceFiles.size());
};
m_pProgress->StartProgress();
for (auto it = sourceFiles.begin(); it != sourceFiles.end(); ++it)
{
const RcFile& pakFile = *it;
#if defined(AZ_PLATFORM_WINDOWS)
const string pakFilePath = PathHelpers::Join(PathHelpers::ToDosPath(pakFile.m_sourceLeftPath), PathHelpers::ToDosPath(pakFile.m_sourceInnerPathAndName));
#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX)
const string pakFilePath = PathHelpers::Join(PathHelpers::ToUnixPath(pakFile.m_sourceLeftPath), PathHelpers::ToUnixPath(pakFile.m_sourceInnerPathAndName));
#endif
ZipDir::CacheFactory factory(ZipDir::ZD_INIT_FAST, 0);
ZipDir::CachePtr cache = factory.New(pakFilePath.c_str(), zipDecryptKey.empty() ? nullptr : decryptionKey);
size_t index = pakFile.m_sourceInnerPathAndName.find(PathHelpers::GetFilename(pakFile.m_sourceInnerPathAndName));
if (index == string::npos)
{
continue;
}
#if defined(AZ_PLATFORM_WINDOWS)
const string destFolder = PathHelpers::Join(PathHelpers::ToDosPath(unzipFolder), PathHelpers::ToDosPath(pakFile.m_sourceInnerPathAndName.substr(0, index)));
#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX)
const string destFolder = PathHelpers::Join(PathHelpers::ToUnixPath(unzipFolder), PathHelpers::ToUnixPath(pakFile.m_sourceInnerPathAndName.substr(0, index)));
#endif
params.emplace_back(UnpakParameters{ cache, pakFilePath, destFolder, onFinishCb });
pool.Submit<UnpakParameters>(unpakFunc, &params.back());
}
pool.Start(GetMaxThreads());
pool.WaitAllJobs();
m_pProgress->FinishProgress();
return eCallResult_Succeeded;
}
@@ -0,0 +1,88 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PAKMANAGER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PAKMANAGER_H
#pragma once
#include "ZipDir/ZipDir.h"
#include "PakSystem.h"
#include "PakHelpers.h"
#include "RcFile.h"
#include "IProgress.h"
struct IResourceCompiler;
class IConfig;
class PakManager
{
public:
PakManager(IProgress* pProgress);
~PakManager();
void RegisterKeys(IResourceCompiler* pRC);
IPakSystem* GetPakSystem();
bool HasPakFiles() const;
unsigned GetMaxThreads() const;
// -----------------------------------------------
enum ECallResult
{
eCallResult_Skipped, // functionality didn't apply and has been skipped
eCallResult_Succeeded, // call has been successfull
eCallResult_Erroneous, // call has run and ended, but with minor errors (duplicate CRC etc.)
eCallResult_Failed, // call has failed - pak files are in inconsistent state
eCallResult_BadArgs, // arguments are illformed - pak files have not been touched or changed
};
ECallResult CompileFilesIntoPaks(
const IConfig* config,
const std::vector<RcFile>& m_allFiles);
ECallResult DeleteFilesFromPaks(
const IConfig* config,
const std::vector<string>& deletedTargetFiles);
private:
ECallResult SplitListFileToPaks(
const IConfig* config,
const std::vector<string>& sourceRootsReversed,
const std::vector<RcFile>& files,
const string& pakFilePath);
ECallResult CreatePakFile(
const IConfig* config,
const std::vector<RcFile>& sourceFiles,
const string& folderInPak,
const string& requestedPakFilename,
bool bUpdate);
ECallResult SynchronizePaks(
const IConfig* config,
const std::vector<string>& deletedTargetFiles);
ECallResult UnzipPakFile(
const IConfig* config,
const std::vector<RcFile>& sourceFiles,
const string& unzipFolder);
private:
// All output zip files.
std::vector<string> m_zipFiles;
PakSystem m_pPakSystem;
IProgress* m_pProgress;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PAKMANAGER_H
@@ -0,0 +1,12 @@
#
# 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.
#
set(LY_COMPILE_OPTIONS PRIVATE -fexceptions)
@@ -0,0 +1,12 @@
#
# 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.
#
set(LY_COMPILE_OPTIONS PRIVATE /EHsc)
@@ -0,0 +1,10 @@
#
# 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.
#
@@ -0,0 +1,10 @@
#
# 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.
#
@@ -0,0 +1,13 @@
#
# 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.
#
set(LY_TARGET_PROPERTIES
BUILD_RPATH "@executable_path/")
@@ -0,0 +1,10 @@
#
# 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.
#
@@ -0,0 +1,129 @@
/*
* 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 "CrashHandler_Windows.h"
#include <IConsole.h>
#include "IResourceCompilerHelper.h"
#include "CryFixedString.h"
#include <DbgHelp.h>
#define DBGHELP_DLL_NAME "dbghelp.dll"
//=============================================================================
CrashHandler::CrashHandler()
{
m_dumpFilename[0] = '\0';
BusConnect();
}
//=============================================================================
CrashHandler::~CrashHandler()
{
BusDisconnect();
}
//=============================================================================
bool CrashHandler::OnException(const char* /*message*/)
{
if (m_dumpFilename[0])
{
WriteMinidump();
}
return false; // continue error handler execution
}
//=============================================================================
void CrashHandler::SetDumpFile(const char* const dumpFilename)
{
if (dumpFilename && dumpFilename[0])
{
azstrncpy(m_dumpFilename, AZ_ARRAY_SIZE(m_dumpFilename), dumpFilename, strlen(dumpFilename));
}
}
//=============================================================================
void CrashHandler::WriteMinidump()
{
// load any version we can. Win now distributes the dll, and all the functions that are used have been around since winxp
HMODULE hDll = LoadLibraryA(DBGHELP_DLL_NAME);
CryFixedStringT<MAX_PATH + 200> strResult;
if (hDll)
{
// based on DbgHelp.h
typedef BOOL (WINAPI * MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
if (pDump)
{
{
// create the file
HANDLE hFile = ::CreateFile(m_dumpFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = (PEXCEPTION_POINTERS)AZ::Debug::Trace::GetNativeExceptionInfo();
ExInfo.ClientPointers = NULL;
// write the dump
MINIDUMP_TYPE const mdumpValue = (MINIDUMP_TYPE)
(MiniDumpNormal // include call stack, thread info, etc
| MiniDumpWithIndirectlyReferencedMemory // try to find pointers on the stack and dump memory near where they're pointing
| MiniDumpWithDataSegs); // dump global variables (like gEnv)
BOOL const bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdumpValue, &ExInfo, NULL, NULL);
if (bOK)
{
strResult.Format("Saved crash dump file to '%s'", m_dumpFilename);
}
else
{
strResult.Format("Failed to save crash dump file to '%s' (error %d)", m_dumpFilename, GetLastError());
}
::CloseHandle(hFile);
}
else
{
strResult.Format("Failed to create crash dump file '%s' (error %d)", m_dumpFilename, GetLastError());
}
}
}
else
{
strResult = "Failed to save crash dump file because " DBGHELP_DLL_NAME " is too old";
}
}
else
{
strResult = "Failed to save crash dump file because " DBGHELP_DLL_NAME " is not found";
}
if (!strResult.empty())
{
fprintf(stderr, "%s\r\n", strResult.c_str());
}
}
@@ -0,0 +1,45 @@
/*
* 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.
// Description : Based on DebugCallStack code.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CRASHHANDLER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CRASHHANDLER_H
#pragma once
#include <AzCore/Debug/TraceMessageBus.h>
//!============================================================================
//!
//! CrashHandler class
//! writes minidump files.
//!
//!============================================================================
class CrashHandler : AZ::Debug::TraceMessageBus::Handler
{
public:
CrashHandler();
~CrashHandler();
bool OnException(const char* message) override;
void SetDumpFile(const char* dumpFilename);
private:
void WriteMinidump();
char m_dumpFilename[MAX_PATH];
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_CRASHHANDLER_H
@@ -0,0 +1,15 @@
#
# 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.
#
set(LY_BUILD_DEPENDENCIES
PRIVATE
psapi.lib
)
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
CrashHandler_Windows.cpp
CrashHandler_Windows.h
)
@@ -0,0 +1,108 @@
/*
* 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 "PropertyVars.h"
#include "IRCLog.h"
#include "StringHelpers.h"
CPropertyVars::CPropertyVars(IResourceCompiler* pRC)
{
m_pRC = pRC;
}
//////////////////////////////////////////////////////////////////////////
void CPropertyVars::SetProperty(const string& name, const string& value)
{
m_properties[StringHelpers::MakeLowerCase(name)] = value;
}
//////////////////////////////////////////////////////////////////////////
void CPropertyVars::RemoveProperty(const string& name)
{
m_properties.erase(StringHelpers::MakeLowerCase(name));
}
//////////////////////////////////////////////////////////////////////////
void CPropertyVars::ClearProperties()
{
m_properties.clear();
}
//////////////////////////////////////////////////////////////////////////
void CPropertyVars::ExpandProperties(string& str) const
{
const string original = str;
for (;; )
{
const size_t startpos = str.find("${");
if (startpos == str.npos)
{
return;
}
const size_t endpos = str.find('}', startpos + 2);
if (endpos == str.npos)
{
return;
}
// Find property.
const string propName = StringHelpers::MakeLowerCase(str.substr(startpos + 2, endpos - startpos - 2));
PropertyMap::const_iterator it = m_properties.find(propName);
if (it == m_properties.end())
{
RCLogError("Error: Unknown property name ${%s} in input string %s", propName.c_str(), original.c_str());
return;
}
const string value = it->second;
const string last = str;
str = str.replace(startpos, endpos - startpos + 1, value);
// If we did a replacement and the string is still the same we are in an infinite loop.
if (str.compare(last) == 0)
{
RCLogError("Error: Infinite loop with property ${%s} in input string '%s'. Original string '%s'.", propName.c_str(), last.c_str(), original.c_str());
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
bool CPropertyVars::GetProperty(const string& key, string& value) const
{
PropertyMap::const_iterator it = m_properties.find(StringHelpers::MakeLowerCase(key));
if (it == m_properties.end())
{
return false;
}
value = it->second;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CPropertyVars::HasProperty(const string& key) const
{
return m_properties.find(StringHelpers::MakeLowerCase(key)) != m_properties.end();
}
//////////////////////////////////////////////////////////////////////////
void CPropertyVars::PrintProperties() const
{
for (PropertyMap::const_iterator it = m_properties.begin(); it != m_properties.end(); ++it)
{
RCLog(" %s \'%s\'", it->first.c_str(), it->second.c_str());
}
}
@@ -0,0 +1,56 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PROPERTYVARS_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PROPERTYVARS_H
#pragma once
struct IResourceCompiler;
class CPropertyVars
{
public:
CPropertyVars(IResourceCompiler* pRC);
void SetProperty(const string& name, const string& value);
void RemoveProperty(const string& key);
void ClearProperties();
// Return property.
bool GetProperty(const string& name, string& value) const;
bool HasProperty(const string& name) const;
// Expand variables as ${propertyName} with the value of propertyName variable
void ExpandProperties(string& str) const;
void PrintProperties() const;
// Enumerate properties
// Functor takes two arguments: (name, value)
template<typename Functor>
void Enumerate(const Functor& callback) const
{
for (PropertyMap::const_iterator it = m_properties.begin(); it != m_properties.end(); ++it)
{
callback(it->first, it->second);
}
}
private:
typedef std::map<string, string> PropertyMap;
PropertyMap m_properties;
IResourceCompiler* m_pRC;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_PROPERTYVARS_H
+38
View File
@@ -0,0 +1,38 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_RCFILE_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_RCFILE_H
#pragma once
class RcFile
{
public:
string m_sourceLeftPath;
string m_sourceInnerPathAndName;
string m_targetLeftPath;
public:
RcFile()
{
}
RcFile(const string& sourceLeftPath, const string& sourceInnerPathAndName, const string& targetLeftPath)
: m_sourceLeftPath(sourceLeftPath)
, m_sourceInnerPathAndName(sourceInnerPathAndName)
, m_targetLeftPath(targetLeftPath.empty() ? sourceLeftPath : targetLeftPath)
{
}
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_RCFILE_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,345 @@
/*
* 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.
#pragma once
#include "IRCLog.h"
#include "IResCompiler.h"
#include "CfgFile.h"
#include "Config.h"
#include "DependencyList.h"
#include "ExtensionManager.h"
#include "MultiplatformConfig.h"
#include "PakSystem.h"
#include "PakManager.h"
#include "RcFile.h"
#include "CryVersion.h"
#include "IProgress.h"
#include <ISystem.h>
#include <AzFramework/Archive/Codec.h>
#include <map> // stl multimap<>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
class CPropertyVars;
class XmlNodeRef;
class ICryXML;
ICryXML* LoadICryXML();
/** Implementation of IResCompiler interface.
*/
class ResourceCompiler
: public IResourceCompiler
, public IProgress
, public IRCLog
, public IConfigKeyRegistry
{
public:
struct FilesToConvert
{
std::vector<RcFile> m_allFiles;
std::vector<RcFile> m_inputFiles;
std::vector<RcFile> m_outOfMemoryFiles;
std::vector<RcFile> m_failedFiles;
std::vector<RcFile> m_convertedFiles;
};
struct RcCompileFileInfo
{
ResourceCompiler* rc;
FilesToConvert* pFilesToConvert;
IConvertor* convertor;
ICompiler* compiler;
bool bLogMemory;
bool bWarningHeaderLine;
bool bErrorHeaderLine;
string logHeaderLine;
};
ResourceCompiler();
virtual ~ResourceCompiler();
//! e.g. print statistics
void PostBuild();
int GetNumWarnings() const {return m_numWarnings; }
int GetNumErrors() const {return m_numErrors; }
// interface IProgress --------------------------------------------------
void RegisterDefaultKeys();
virtual void StartProgress();
virtual void ShowProgress(const char* pMessage, size_t progressValue, size_t maxProgressValue);
virtual void FinishProgress();
// interface IConfigKeyRegistry ------------------------------------------
virtual void VerifyKeyRegistration(const char* szKey) const;
virtual bool HasKeyRegistered(const char* szKey) const;
// -----------------------------------------------------------------------
// interface IResourceCompiler -------------------------------------------
virtual void RegisterKey(const char* key, const char* helptxt);
virtual const char* GetExePath() const;
virtual const char* GetTmpPath() const;
virtual const char* GetInitialCurrentDir() const;
const char* GetAppRoot() const override;
virtual void RegisterConvertor(const char* name, IConvertor* conv);
void AddPluginDLL(HMODULE pluginDLL);
void RemovePluginDLL(HMODULE pluginDLL);
virtual IPakSystem* GetPakSystem();
virtual const ICfgFile* GetIniFile() const;
virtual int GetPlatformCount() const;
virtual const PlatformInfo* GetPlatformInfo(int index) const;
virtual int FindPlatform(const char* name) const;
virtual XmlNodeRef LoadXml(const char* filename);
virtual XmlNodeRef CreateXml(const char* tag);
virtual void AddInputOutputFilePair(const char* inputFilename, const char* outputFilename);
virtual void MarkOutputFileForRemoval(const char* sOutputFilename);
virtual void AddExitObserver(IExitObserver* p);
virtual void RemoveExitObserver(IExitObserver* p);
virtual IRCLog* GetIRCLog()
{
return this;
}
virtual int GetVerbosityLevel() const
{
return m_verbosityLevel;
}
virtual bool UseFastestDecompressionCodec() const
{
return m_bUseFastestDecompressionCodec;
}
virtual const SFileVersion& GetFileVersion() const
{
return m_fileVersion;
}
virtual const void GetGenericInfo(char* buffer, size_t bufferSize, const char* rowSeparator) const;
string GetResourceCompilerGenericInfo(const string& newline) const;
static bool CheckCommandLineOptions(const IConfig& config, const std::vector<string>* keysToIgnore);
static void CopyStringToClipboard(const string& s);
virtual bool CompileSingleFileBySingleProcess(const char* filename);
virtual void SetAssetWriter(IAssetWriter* pAssetWriter)
{
m_pAssetWriter = pAssetWriter;
}
virtual IAssetWriter* GetAssetWriter() const
{
return m_pAssetWriter;
}
// -----------------------------------------------------------------------
// interface IRCLog ------------------------------------------------------
virtual void LogV(const IRCLog::EType eType, const char* szFormat, va_list args);
virtual void Log(const IRCLog::EType eType, const char* szMessage);
// -----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// Resource compiler implementation.
//////////////////////////////////////////////////////////////////////////
void Init(Config& config);
bool LoadIniFile();
void UnregisterConvertors();
bool AddPlatform(const string& names, bool bBigEndian, int pointerSize);
MultiplatformConfig& GetMultiplatformConfig();
void SetComplilingFileInfo(RcCompileFileInfo* compileFileInfo);
bool CollectFilesToCompile(const string& filespec, std::vector<RcFile>& files);
bool CompileFilesBySingleProcess(const std::vector<RcFile>& files);
int ProcessJobFile();
void RemoveOutputFiles(); // to remove old files for less confusion
void CleanTargetFolder(bool bUseOnlyInputFiles);
bool CompileFile();
const char* GetLogPrefix() const;
//! call this if user asks for help
void ShowHelp(bool bDetailed);
//////////////////////////////////////////////////////////////////////////
void SetAppRootPath(const string& appRootPath);
static string GetAppRootPathFromGameRoot(const string& gameRootPath);
void QueryVersionInfo();
void InitPaths();
void NotifyExitObservers();
void InitLogs(Config& config);
string FormLogFileName(const char* suffix) const;
const string& GetMainLogFileName() const;
const string& GetErrorLogFileName() const;
clock_t GetStartTime() const;
bool GetTimeLogging() const;
void SetTimeLogging(bool enable);
void LogMemoryUsage(bool bReportProblemsOnly);
void InitPakManager();
static string FindSuitableSourceRoot(const std::vector<string>& sourceRootsReversed, const string& fileName);
static void GetSourceRootsReversed(const IConfig* config, std::vector<string>& sourceRootsReversed);
void InitSystem(SSystemInitParams& startupParams);
private:
void FilterExcludedFiles(std::vector<RcFile>& files);
void CopyFiles(const std::vector<RcFile>& files, bool bNoOverwrite = false, bool recompress = false);
/*!
Files discovered at the \p directory node will be added to \p filenames with full path, if other
directories are found inside \p directory then more files will be added recursively.
\param directory The input directory node
\param directoryName Full directory name of \p directory starting from the root directory.
It is expected that only for the root directory this string is "".
This function assumes that if this string is NOT empty, it includes the trailing "\\".
\param filenames Output vector where filepaths will be added as files are recursively discovered.
\returns void
*/
void GetFileListRecursively(const ZipDir::FileEntryTree* directory, const AZStd::string& directoryName, AZStd::vector<AZStd::string>& filenames) const;
bool RecompressFiles(const string& sourceFileName, const string& destinationFileName);
bool m_bUseFastestDecompressionCodec;
void ExtractJobDefaultProperties(std::vector<string>& properties, const XmlNodeRef& jobNode);
int EvaluateJobXmlNode(CPropertyVars& properties, XmlNodeRef& jobNode, bool runJobs);
int RunJobByName(CPropertyVars& properties, XmlNodeRef& anyNode, const char* name);
void ScanForAssetReferences(std::vector<string>& outReferences, const string& refsRoot);
void SaveAssetReferences(const std::vector<string>& references, const string& filename, const string& includeMasks, const string& excludeMasks);
void LogLine(const IRCLog::EType eType, const char* szText);
// to log multiple lines (\n separated) with padding before
void LogMultiLine(const char* szText);
// -----------------------------------------------------------------------
public:
static const char* const m_filenameRcExe;
static const char* const m_filenameRcIni;
static const char* const m_filenameOptions;
static const char* const m_filenameLog;
static const char* const m_filenameLogWarnings;
static const char* const m_filenameLogErrors;
static const char* const m_filenameCrashDump;
static const char* const m_filenameOutputFileList; //!< list of source=target filenames that rc processed, used for cleaning target folder
static const char* const m_filenameDeletedFileList;
static const char* const m_filenameCreatedFileList;
static const char* const m_rcPluginSubfolder; //!< The name of the subfolder where the Resource Compiler plugins are built to relative of rc
bool m_bQuiet; //!< true= don't log anything to console
private:
static const size_t s_internalBufferSize = 4 * 1024;
static const size_t s_environmentBufferSize = 64 * 1024;
enum
{
kMaxPlatformCount = 20
};
int m_platformCount;
PlatformInfo m_platforms[kMaxPlatformCount];
ExtensionManager m_extensionManager;
IAssetWriter* m_pAssetWriter;
AZStd::mutex m_inputOutputFilesLock;
CDependencyList m_inputOutputFileList;
std::vector<IExitObserver*> m_exitObservers;
AZStd::mutex m_exitObserversLock;
float m_memorySizePeakMb;
AZStd::mutex m_memorySizeLock;
// log files
string m_logPrefix;
string m_mainLogFileName; //!< for all messages, might be empty (no file logging)
string m_warningLogFileName; //!< for warnings only, might be empty (no file logging)
string m_errorLogFileName; //!< for errors only, might be empty (no file logging)
string m_logHeaderLine;
AZStd::mutex m_logLock;
clock_t m_startTime;
bool m_bTimeLogging;
float m_progressLastPercent;
int m_verbosityLevel;
CfgFile m_iniFile;
MultiplatformConfig m_multiConfig;
bool m_bWarningHeaderLine; //!< true= header was already printed, false= header needs to be printed
bool m_bErrorHeaderLine; //!< true= header was already printed, false= header needs to be printed
bool m_bWarningsAsErrors; //!< true= treat any warning as error.
RcCompileFileInfo* m_currentRcCompileFileInfo;
SFileVersion m_fileVersion;
string m_exePath;
string m_tempPath;
string m_initialCurrentDir;
string m_appRoot;
std::map<string, string> m_KeyHelp; // [lower key] = help, created from RegisterKey
// Files to delete
std::vector<RcFile> m_inputFilesDeleted;
PakManager* m_pPakManager;
int m_numWarnings;
int m_numErrors;
std::vector<HMODULE> m_loadedPlugins;
#if AZ_TRAIT_OS_PLATFORM_APPLE
bool m_isRunningFromBundle;
string m_bundleRoot;
#endif
};
@@ -0,0 +1,102 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,8,6
PRODUCTVERSION 1,1,8,6
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "Resource Compiler"
VALUE "CompanyName", "Amazon.com, Inc."
VALUE "FileDescription", "Resource Compiler"
VALUE "FileVersion", "1.1.8.6"
VALUE "InternalName", "ResourceCompiler"
VALUE "LegalCopyright", "Portions of this file Copyright (c) Amazon.com, Inc. or its affiliates. All Rights Reserved. Original file Copyright (c) Crytek GMBH. Used under license by Amazon.com, Inc. and its affiliates."
VALUE "LegalTrademarks", "Lumberyard"
VALUE "OriginalFilename", "rc.exe"
VALUE "ProductName", "Resource Compiler"
VALUE "ProductVersion", "1.1.8.6"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
@@ -0,0 +1,86 @@
/*
* 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.
*
*/
// ResourceCompilerTest.cpp
#include "ResourceCompiler_precompiled.h"
#include "IUnitTestHelper.h"
#include "UnitTestHelper.h"
#include "IResourceCompilerHelper.h"
#include "string.h"
namespace ResourceCompilerTests
{
void TestFileTypes(UnitTestHelper* pUnitTestHelper)
{
//normal cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::GetNumSourceImageFormats() == IResourceCompilerHelper::NUM_SOURCE_IMAGE_TYPE); //should return the enum
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::GetNumEngineImageFormats() == IResourceCompilerHelper::NUM_ENGINE_IMAGE_TYPE); //should return the enum
//normal cases
pUnitTestHelper->TEST_BOOL(!azstricmp(IResourceCompilerHelper::GetSourceImageFormat(IResourceCompilerHelper::SOURCE_IMAGE_TYPE_TIF, true), ".tif")); //dot tif
pUnitTestHelper->TEST_BOOL(!azstricmp(IResourceCompilerHelper::GetSourceImageFormat(IResourceCompilerHelper::SOURCE_IMAGE_TYPE_TIF, false), "tif")); //without dot tif
pUnitTestHelper->TEST_BOOL(!azstricmp(IResourceCompilerHelper::GetSourceImageFormat(IResourceCompilerHelper::SOURCE_IMAGE_TYPE_PNG, true), ".png")); //dot png
pUnitTestHelper->TEST_BOOL(!azstricmp(IResourceCompilerHelper::GetSourceImageFormat(IResourceCompilerHelper::SOURCE_IMAGE_TYPE_PNG, false), "png")); //without dot png
//edge cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::GetSourceImageFormat(IResourceCompilerHelper::NUM_SOURCE_IMAGE_TYPE, true) == nullptr); //invalid range with dot
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::GetSourceImageFormat(IResourceCompilerHelper::NUM_SOURCE_IMAGE_TYPE, false) == nullptr); //invalid range without dot
//normal cases
pUnitTestHelper->TEST_BOOL(!azstricmp(IResourceCompilerHelper::GetEngineImageFormat(IResourceCompilerHelper::ENGINE_IMAGE_TYPE_DDS, true), ".dds")); //dot dds
pUnitTestHelper->TEST_BOOL(!azstricmp(IResourceCompilerHelper::GetEngineImageFormat(IResourceCompilerHelper::ENGINE_IMAGE_TYPE_DDS, false), "dds")); //without dot dds
//edge cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::GetEngineImageFormat(IResourceCompilerHelper::NUM_ENGINE_IMAGE_TYPE, true) == nullptr); //invalid range with dot
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::GetEngineImageFormat(IResourceCompilerHelper::NUM_ENGINE_IMAGE_TYPE, false) == nullptr); //invalid range without dot
//normal cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("somefile.tga") == true); //file name
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("somefile.dds") == false); //unsupported file name
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("blah/blah/some.png") == true); //full file name
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("blah/blah/some.dds") == false); //unsupported full file names
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("tga") == true); //no dot
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported(".tga") == true); //with dot
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported(".TGA") == true); //with dot case insensitive
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("Png") == true); //without case insensitive
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("gifs") == false); //extra characters not supported
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("Targa") == false); //names not supported
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("dds") == false); //invalid format
//edge cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported("") == false); //empty string
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsSourceImageFormatSupported(nullptr) == false); //nullptr
//normal cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("somefile.dds") == true); //file name
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("somefile.gif") == false); //unsupported file name
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("blah/blah/some.dds") == true); //full file name
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("blah/blah/some.png") == false); //unsupported full file names
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("dds") == true); //no dot
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported(".dds") == true); //with dot
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported(".DDs") == true); //with dot case insensitive
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("ddS") == true); //without case insensitive
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("ddSs") == false); //extra characters not supported
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("Direct Draw Surface") == false); //names not supported
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("gif") == false); //invalid format
//edge cases
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported("") == false); //empty string
pUnitTestHelper->TEST_BOOL(IResourceCompilerHelper::IsGameImageFormatSupported(nullptr) == false); //nullptr
}
void Run(UnitTestHelper* pUnitTestHelper)
{
TestFileTypes(pUnitTestHelper);
}
}
@@ -0,0 +1,14 @@
/*
* 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"
@@ -0,0 +1,80 @@
/*
* 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.
// Description : include file for standard system include files,
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include <assert.h>
#define CRY_ASSERT(condition) assert(condition)
#define CRY_ASSERT_TRACE(condition, message) assert(condition)
#define CRY_ASSERT_MESSAGE(condition, message) assert(condition)
// Define this to prevent including CryAssert (there is no proper hook for turning this off, like the above).
#define CRYINCLUDE_CRYCOMMON_CRYASSERT_H
#include <CryCommon/platform.h>
#include <CryCommon/IXml.h>
#if defined(AZ_PLATFORM_WINDOWS)
// Standard C headers.
#include <direct.h>
#include <tchar.h>
#define WIN32_EXTRA_LEAN
#include <windows.h>
#endif
// STL headers.
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <map>
#include <set>
//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#define VC_EXTRALEAN
//#include <StlDbgAlloc.h>
// to make smoother transition back from cry to std namespace...
#define cry std
#define CRY_AS_STD
#include <CryCommon/smartptr.h>
//////////////////////////////////////////////////////////////////////////
#include "ConvertContext.h"
#include <CryCommon/Cry_Math.h>
#include <CryCommon/primitives.h>
#include <CryCommon/CryHeaders.h>
#include <CryCommon/CryVersion.h>
#include "CryCommon/StlUtils.h"
@@ -0,0 +1,99 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_SIMPLESTRING_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_SIMPLESTRING_H
#pragma once
#include <cstring> // memcpy()
// Implementation note: we cannot use name CSimpleString because it is already used by ATL
class SimpleString
{
public:
SimpleString()
: m_str((char*)0)
, m_length(0)
{
}
explicit SimpleString(const char* s)
: m_str((char*)0)
, m_length(0)
{
*this = s;
}
SimpleString(const SimpleString& str)
: m_str((char*)0)
, m_length(0)
{
*this = str;
}
~SimpleString()
{
if (m_str)
{
delete [] m_str;
}
}
SimpleString& operator=(const SimpleString& str)
{
if (this != &str)
{
*this = str.m_str;
}
return *this;
}
SimpleString& operator=(const char* s)
{
char* const oldStr = m_str;
m_str = (char*)0;
m_length = 0;
if (s && s[0])
{
m_length = strlen(s);
m_str = new char[m_length + 1];
memcpy(m_str, s, m_length + 1);
}
if (oldStr)
{
delete [] oldStr;
}
return *this;
}
operator const char*() const
{
return c_str();
}
const char* c_str() const
{
return (m_str) ? m_str : "";
}
size_t length() const
{
return m_length;
}
private:
char* m_str;
size_t m_length;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_SIMPLESTRING_H
@@ -0,0 +1,39 @@
/*
* 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.
*
*/
#include <AzCore/Memory/AllocatorScope.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzTest/AzTest.h>
class ResourceCompilerTestEnvironment
: public AZ::Test::ITestEnvironment
{
public:
virtual ~ResourceCompilerTestEnvironment(){}
protected:
void SetupEnvironment() override
{
m_allocatorScope.ActivateAllocators();
AZ::IO::FileIOBase::SetInstance(nullptr); // The API requires the old instance to be destroyed first
AZ::IO::FileIOBase::SetInstance(new AZ::IO::LocalFileIO());
}
void TeardownEnvironment() override
{
m_allocatorScope.DeactivateAllocators();
}
AZ::AllocatorScope<AZ::OSAllocator, AZ::SystemAllocator, AZ::LegacyAllocator, CryStringAllocator> m_allocatorScope;
};
@@ -0,0 +1,44 @@
/*
* 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.
*
*/
#include <AzTest/AzTest.h>
#include "ZipEncryptor.h"
TEST(ResourceCompilerZipEncryptorTest, ParseKey_InputTooShort_ReturnFalse_FT)
{
uint32 key[4];
EXPECT_FALSE(ZipEncryptor::ParseKey(key, "Not32HexCharacters"));
}
TEST(ResourceCompilerZipEncryptorTest, ParseKey_ValidKey_ReturnTrue_FT)
{
uint32 key[4];
EXPECT_TRUE(ZipEncryptor::ParseKey(key, "123456789012345678901234567890AB"));
EXPECT_EQ(key[0], 1450741931);
EXPECT_EQ(key[1], 2022707764);
EXPECT_EQ(key[2], 2417112150);
EXPECT_EQ(key[3], 305419896);
}
TEST(ResourceCompilerZipEncryptorTest, ParseKey_InvalidInputV1_ReturnFalse_FT)
{
uint32 key[4];
EXPECT_FALSE(ZipEncryptor::ParseKey(key, "1234567890Z1345678901234567890AB"));
// Error text will be @Pos 11 ^ HERE. Invalid Hex value
}
TEST(ResourceCompilerZipEncryptorTest, ParseKey_InvalidInputV2_ReturnFalse_FT)
{
uint32 key[4];
EXPECT_FALSE(ZipEncryptor::ParseKey(key, "12345678901Z345678901234567890AB"));
// Error text will be @Pos 12 ^ HERE. Invalid Hex value
}
@@ -0,0 +1,95 @@
/*
* 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.
*
*/
#include <ResourceCompiler.h>
#include <AzTest/AzTest.h>
#include <AzCore/Memory/AllocatorScope.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <Utils/Utils.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <fstream>
class ResourceCompilerTestEnvironment
: public AZ::Test::ITestEnvironment
{
public:
virtual ~ResourceCompilerTestEnvironment()
{}
protected:
void SetupEnvironment() override
{
m_allocatorScope.ActivateAllocators();
AZ::IO::FileIOBase::SetInstance(nullptr); // The API requires the old instance to be destroyed first
AZ::IO::FileIOBase::SetInstance(new AZ::IO::LocalFileIO());
}
void TeardownEnvironment() override
{
m_allocatorScope.DeactivateAllocators();
}
AZ::AllocatorScope<AZ::OSAllocator, AZ::SystemAllocator, AZ::LegacyAllocator, CryStringAllocator> m_allocatorScope;
};
AZ_UNIT_TEST_HOOK(new ResourceCompilerTestEnvironment)
TEST(CollectFilesTest, CollectFiles_PatternWithAndWithoutWildcards_Success)
{
UnitTest::ScopedTemporaryDirectory tempDir;
AZStd::string tempRoot;
AZ::StringFunc::Path::Join(tempDir.GetDirectory(), "root", tempRoot);
AZ::IO::LocalFileIO::GetInstance()->CreatePath(tempRoot.c_str());
AZStd::string tempFile;
AZ::StringFunc::Path::Join(tempRoot.c_str(), "temp.xml", tempFile);
std::ofstream outFile(tempFile.c_str(), std::ofstream::out | std::ofstream::app);
outFile << "Temp";
outFile.close();
AZStd::string sourceRoots{ tempRoot };
AZStd::string tempSubFolder;
AZ::StringFunc::Path::Join(tempRoot.c_str(), "foldera", tempSubFolder);
AZ::IO::LocalFileIO::GetInstance()->CreatePath(tempSubFolder.c_str());
AZ::StringFunc::Path::Join(tempSubFolder.c_str(), "tempfile1.xml", tempFile);
std::ofstream outFile1(tempFile.c_str(), std::ofstream::out | std::ofstream::app);
outFile1 << "Tempfile1";
outFile1.close();
AZ::StringFunc::Path::Join(tempRoot.c_str(), "folderb", tempSubFolder);
AZ::IO::LocalFileIO::GetInstance()->CreatePath(tempSubFolder.c_str());
AZ::StringFunc::Path::Join(tempSubFolder.c_str(), "tempfile2.xml", tempFile);
std::ofstream outFile2(tempFile.c_str(), std::ofstream::out | std::ofstream::app);
outFile2 << "Tempfile2";
outFile2.close();
ResourceCompiler testResourceCompiler;
testResourceCompiler.RegisterDefaultKeys();
testResourceCompiler.GetMultiplatformConfig().init(1, 0, &testResourceCompiler);
testResourceCompiler.GetMultiplatformConfig().getConfig().SetKeyValue(eCP_PriorityCmdline, "sourceroot", sourceRoots.c_str());
std::vector<RcFile> resultList;
testResourceCompiler.CollectFilesToCompile("temp.xml", resultList);
EXPECT_EQ(resultList.size(), 1);
testResourceCompiler.CollectFilesToCompile("foldera/*.xml", resultList);
EXPECT_EQ(resultList.size(), 1);
testResourceCompiler.CollectFilesToCompile("foldera/*.xml;temp.xml;folderb/*.xml", resultList);
EXPECT_EQ(resultList.size(), 3);
}
@@ -0,0 +1,100 @@
/*
* 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 "TextFileReader.h"
#include "IPakSystem.h"
bool TextFileReader::Load(const char* filename, std::vector<char*>& lines)
{
FILE* file = nullptr;
azfopen(&file, filename, "rb");
if (!file)
{
return false;
}
fseek(file, 0, SEEK_END);
const size_t size = ftell(file);
fseek(file, 0, SEEK_SET);
m_buffer.resize(size + 1); // +1 for last terminating zero
if (fread(&m_buffer[0], 1, size, file) != size)
{
fclose(file);
return false;
}
m_buffer[size] = '\0';
fclose(file);
PrepareLines(lines);
return true;
}
bool TextFileReader::LoadFromPak(IPakSystem* system, const char* filename, std::vector<char*>& lines)
{
PakSystemFile* const file = system->Open(filename, "rb");
if (!file)
{
return false;
}
const size_t size = system->GetLength(file);
m_buffer.resize(size + 1); // +1 for last terminating zero
if (system->Read(file, &m_buffer[0], size) != size)
{
system->Close(file);
return false;
}
m_buffer[size] = '\0';
system->Close(file);
PrepareLines(lines);
return true;
}
// fix line endings to zeros, so we can use strings from the same buffer
void TextFileReader::PrepareLines(std::vector<char*>& lines)
{
lines.clear();
char* p = &m_buffer[0];
const char* const end = p + m_buffer.size();
char* line = p;
while (p != end)
{
if (*p == '\r' || *p == '\n')
{
*p = '\0';
if (*line)
{
lines.push_back(line);
}
++p;
line = p;
}
else
{
++p;
}
}
if (*line)
{
lines.push_back(line);
}
}
@@ -0,0 +1,35 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_TEXTFILEREADER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_TEXTFILEREADER_H
#pragma once
struct IPakSystem;
// Summary:
// Utility class to read text files and split lines inplace. One allocation per one file.
class TextFileReader
{
public:
bool Load(const char* filename, std::vector<char*>& lines);
bool LoadFromPak(IPakSystem* system, const char* filename, std::vector<char*>& lines);
private:
// fix line endings to zeros, so we can use strings from the same buffer
void PrepareLines(std::vector<char*>& lines);
std::vector<char> m_buffer;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_TEXTFILEREADER_H
@@ -0,0 +1,56 @@
/*
* 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.
*
*/
#include "ResourceCompiler_precompiled.h"
#include "UnitTestHelper.h"
#include "IRCLog.h"
UnitTestHelper::UnitTestHelper()
: m_testsPerformed(0)
, m_testsSucceeded(0)
{
}
UnitTestHelper::~UnitTestHelper()
{
}
bool UnitTestHelper::TestBool(bool testValueIsTrue, const char* testValueStatement)
{
++m_testsPerformed;
if (testValueIsTrue)
{
++m_testsSucceeded;
}
else
{
// Set a breakpoint here if you are debugging unit test failure
// Add callstack and other useful information here
RCLogError("Unit test failed! Evaluated to false when true was expected. Statement is: %s", testValueStatement ? testValueStatement : "Unknown statement");
}
return testValueIsTrue;
}
unsigned int UnitTestHelper::GetTestsPerformedCount()
{
return m_testsPerformed;
}
unsigned int UnitTestHelper::GetTestsSucceededCount()
{
return m_testsSucceeded;
}
bool UnitTestHelper::AllUnitTestsPassed()
{
return m_testsSucceeded == m_testsPerformed;
}
@@ -0,0 +1,35 @@
/*
* 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.
*
*/
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_UNITTESTHELPER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_UNITTESTHELPER_H
#pragma once
#include "IUnitTestHelper.h"
class UnitTestHelper
: public IUnitTestHelper
{
public:
UnitTestHelper();
~UnitTestHelper();
bool TestBool(bool testValueIsTrue, const char* testValueStatement) override;
unsigned int GetTestsPerformedCount();
unsigned int GetTestsSucceededCount();
bool AllUnitTestsPassed();
private:
unsigned int m_testsPerformed;
unsigned int m_testsSucceeded;
};
#endif // #ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_UNITTESTHELPER_H
@@ -0,0 +1,74 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_UPTODATEFILEHELPERS_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_UPTODATEFILEHELPERS_H
#pragma once
#include <assert.h>
#include "FileUtil.h"
#include "IRCLog.h" // RCLog
namespace UpToDateFileHelpers
{
inline bool FileExistsAndUpToDate(
const char* const pDstFileName,
const char* const pSrcFileName)
{
const FILETIME dstFileTime = FileUtil::GetLastWriteFileTime(pDstFileName);
if (!FileUtil::FileTimeIsValid(dstFileTime))
{
return false;
}
const FILETIME srcFileTime = FileUtil::GetLastWriteFileTime(pSrcFileName);
if (!FileUtil::FileTimeIsValid(srcFileTime))
{
RCLogWarning("%s: Source file \"%s\" doesn't exist", __FUNCTION__, pSrcFileName);
return false;
}
return FileUtil::FileTimesAreEqual(srcFileTime, dstFileTime);
}
inline bool SetMatchingFileTime(
const char* const pDstFileName,
const char* const pSrcFileName)
{
const FILETIME srcFileTime = FileUtil::GetLastWriteFileTime(pSrcFileName);
if (!FileUtil::FileTimeIsValid(srcFileTime))
{
RCLogError("%s: Source file \"%s\" doesn't exist", __FUNCTION__, pSrcFileName);
return false;
}
const FILETIME dstFileTime = FileUtil::GetLastWriteFileTime(pDstFileName);
if (!FileUtil::FileTimeIsValid(dstFileTime))
{
RCLogError("%s: Destination file \"%s\" doesn't exist", __FUNCTION__, pDstFileName);
return false;
}
if (!FileUtil::SetFileTimes(pSrcFileName, pDstFileName))
{
RCLogError("%s: Copying the date and time from \"%s\" to \"%s\" failed", __FUNCTION__, pSrcFileName, pDstFileName);
return false;
}
assert(FileExistsAndUpToDate(pDstFileName, pSrcFileName));
return true;
}
} // namespace UpToDateFileHelpers
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_UPTODATEFILEHELPERS_H
@@ -0,0 +1,10 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below indicates application support for Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--The ID below indicates application support for Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
</assembly>
@@ -0,0 +1,227 @@
/*
* 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 "IResCompiler.h"
#include "IRCLog.h"
#include "PakSystem.h"
#include <set>
#include "ZipEncryptor.h"
#include "ZipDir/ZipDir.h"
#include "FileUtil.h"
#include "StringHelpers.h"
#include <AzFramework/IO/LocalFileIO.h>
ZipEncryptor::ZipEncryptor([[maybe_unused]] IResourceCompiler* pRC)
{
}
ZipEncryptor::~ZipEncryptor()
{
}
ICompiler* ZipEncryptor::CreateCompiler()
{
return this;
}
void ZipEncryptor::Release()
{
}
string ZipEncryptor::GetOutputFileNameOnly() const
{
return m_CC.m_sourceFileNameOnly;
}
string ZipEncryptor::GetOutputPath() const
{
return PathHelpers::Join(m_CC.GetOutputFolder(), GetOutputFileNameOnly());
}
const char* ZipEncryptor::GetExt(int index) const
{
switch (index)
{
case 0:
return "pak";
case 1:
return "zip";
default:
return 0;
}
}
namespace {
struct EncryptPredicate
: ZipDir::IEncryptPredicate
{
string m_filter;
std::vector<string> m_filterItems;
EncryptPredicate(const string& filter)
: m_filter(filter)
{
if (!filter.empty())
{
StringHelpers::Split(filter, ";", false, m_filterItems);
}
}
virtual bool Match(const char* filename)
{
size_t count = m_filterItems.size();
for (size_t i = 0; i < count; ++i)
{
if (StringHelpers::MatchesWildcardsIgnoreCase(filename, m_filterItems[i]))
{
return true;
}
}
return false;
}
};
}
bool ZipEncryptor::Process()
{
const IConfig* config = m_CC.m_config;
if (!m_CC.m_config->HasKey("zip_encrypt"))
{
RCLogError("zip_encrypt option is not specified.");
return false;
}
const bool zipEncrypt = m_CC.m_config->GetAsBool("zip_encrypt", false, true);
const int zipFileAlignment = config->GetAsInt("zip_alignment", 1, 1);
uint32 encryptionKey[4];
const string zipEncryptKey = config->GetAsString("zip_encrypt_key", "", "");
if (!zipEncryptKey.empty())
{
if (!ParseKey(encryptionKey, zipEncryptKey.c_str()))
{
RCLogError("Misformed zip_encrypt_key: expected 128-bit integer in hexadecimal format (32 character)");
return false;
}
}
const string outputPath = GetOutputPath();
RCLog(zipEncrypt ? "Encrypting zip: %s" : "Decrypting zip: %s", outputPath.c_str());
if (!FileUtil::FileExists(m_CC.GetSourcePath()))
{
RCLogError("Non-existing input file: %s", m_CC.GetSourcePath().c_str());
return false;
}
if (!StringHelpers::EqualsIgnoreCase(m_CC.GetSourcePath().c_str(), outputPath.c_str()))
{
if (AZ::IO::LocalFileIO().Copy(m_CC.GetSourcePath(), outputPath.c_str()) == FALSE)
{
RCLogError("Unable to copy archive from %s to %s.", m_CC.GetSourcePath().c_str(), outputPath.c_str());
return false;
}
}
PakSystemArchive* pPakFile = m_CC.m_pRC->GetPakSystem()->OpenArchive(outputPath.c_str(), zipFileAlignment, zipEncrypt, zipEncryptKey.empty() ? 0 : encryptionKey);
if (!pPakFile)
{
RCLogError("Failed to open zip file %s", outputPath.c_str());
return false;
}
const string zipEncryptFilter = config->GetAsString("zip_encrypt_filter", "", "");
std::unique_ptr<EncryptPredicate> encryptPredicate(new EncryptPredicate(zipEncryptFilter));
int numChanged = 0;
int numSkipped = 0;
if (!pPakFile->zip->EncryptArchive(zipEncrypt ? pPakFile->zip->ENCRYPT : pPakFile->zip->DECRYPT, encryptPredicate.get(), &numChanged, &numSkipped))
{
RCLogError("PAK encryption failed. Archive is corrupted.");
return false;
}
RCLog(zipEncrypt ? "Encrypted content of %i/%i files" : "Decrypted content of %i/%i files", numChanged, numChanged + numSkipped);
m_CC.m_pRC->GetPakSystem()->CloseArchive(pPakFile);
return true;
}
static unsigned char s_charValueTable[256] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
bool ZipEncryptor::ParseKey(uint32 outputKey[4], const char* inputString)
{
if (!outputKey)
{
assert(outputKey);
return false;
}
if (!inputString)
{
assert(inputString);
return false;
}
size_t numBytes = sizeof(uint32) * 4;
size_t len = strlen(inputString);
if (len != numBytes * 2)
{
RCLogError("Encryption key should contain %i characters.", numBytes * 2);
return false;
}
const char* p = inputString;
const char* end = p + len;
size_t i = 0;
while (i != numBytes)
{
unsigned char v1 = s_charValueTable[(unsigned char)(inputString[i * 2])];
unsigned char v2 = s_charValueTable[(unsigned char)(inputString[i * 2 + 1])];
if (v1 == 0xff || v2 == 0xff)
{
size_t pos = i * 2 + ((v1 == 0xff) ? 1 : 2); // add 1 to position if v1==0xff, or 2 if v2==0xff
RCLogError("Encryption key contains bad character at position %i", pos);
return false;
}
((unsigned char*)outputKey)[numBytes - i - 1] = v2 + (v1 << 4);
++i;
}
return true;
}
@@ -0,0 +1,55 @@
/*
* 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.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ZIPENCRYPTOR_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ZIPENCRYPTOR_H
#pragma once
#include "IConvertor.h"
struct ConvertContext;
class ZipEncryptor
: public ICompiler
, public IConvertor
{
public:
ZipEncryptor(IResourceCompiler* pRC);
~ZipEncryptor();
static bool ParseKey(uint32 outputKey[4], const char* inputString);
// ICompiler + IConvertor methods.
virtual void Release();
// ICompiler methods.
virtual void BeginProcessing([[maybe_unused]] const IConfig* config) { }
virtual void EndProcessing() { }
virtual IConvertContext* GetConvertContext() { return &m_CC; }
virtual bool Process();
// IConvertor methods.
virtual ICompiler* CreateCompiler();
virtual const char* GetExt(int index) const;
private:
string GetOutputFileNameOnly() const;
string GetOutputPath() const;
private:
ConvertContext m_CC;
int m_refCount;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_ZIPENCRYPTOR_H
+732
View File
@@ -0,0 +1,732 @@
/*
* 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.
*
*/
#include <AzCore/PlatformDef.h>
#if defined(AZ_PLATFORM_WINDOWS)
#include "MathHelpers.h"
#endif //AZ_PLATFORM_WINDOWS
#include <QApplication>
#include <QSettings>
#include <QDir>
#include <AzCore/Math/Sfmt.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzFramework/CommandLine/CommandLine.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <ResourceCompiler.h>
#include <IResourceCompilerHelper.h>
#include <CmdLine.h>
#include <ParseEngineConfig.h>
#include <CryLibrary.h>
#include <ZipEncryptor.h>
#if defined(AZ_PLATFORM_WINDOWS)
#include <CrashHandler_Windows.h>
CrashHandler& GetCrashHandler()
{
static CrashHandler s_crashHandler;
return s_crashHandler;
}
#endif
namespace
{
volatile bool g_gotCTRLBreakSignalFromOS = false;
#if defined(AZ_PLATFORM_WINDOWS)
BOOL WINAPI CtrlHandlerRoutine([[maybe_unused]] DWORD dwCtrlType)
{
// we got this.
RCLogError("CTRL-BREAK was pressed!");
g_gotCTRLBreakSignalFromOS = true;
return TRUE;
}
#else
void CtrlHandlerRoutine(int signo)
{
if (signo == SIGINT)
{
RCLogError("CTRL-BREAK was pressed!");
g_gotCTRLBreakSignalFromOS = true;
}
}
#endif
}
std::unique_ptr<QCoreApplication> CreateQApplication(int& argc, char** argv)
{
//we are not going to start a mesg loop. so exec will not be called on the qapp
// special circumsance - if 'userDialog' is present on the command line, we need an interactive app:
AzFramework::CommandLine cmdLine;
cmdLine.Parse(argc, argv);
bool userDialog = cmdLine.HasSwitch("userdialog") &&
((cmdLine.GetNumSwitchValues("userdialog") == 0) || (cmdLine.GetSwitchValue("userdialog", 0) == "1"));
std::unique_ptr<QCoreApplication> qApplication = userDialog ? std::make_unique<QApplication>(argc, argv) : std::make_unique<QCoreApplication>(argc, argv);
return qApplication;
}
#if 0
static void EnableCrtMemoryChecks()
{
uint32 tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
tmp &= ~_CRTDBG_CHECK_ALWAYS_DF;
tmp |= _CRTDBG_ALLOC_MEM_DF;
tmp |= _CRTDBG_CHECK_CRT_DF;
tmp |= _CRTDBG_DELAY_FREE_MEM_DF;
tmp |= _CRTDBG_LEAK_CHECK_DF; // used on exit
// Set desired check frequency
const uint32 eachX = 1;
tmp = (tmp & 0xFFFF) | (eachX << 16);
_CrtSetDbgFlag(tmp);
// Check heap every
//_CrtSetBreakAlloc(2031);
}
#endif
static void ShowAboutDialog(const ResourceCompiler& rc)
{
const string newline("\r\n");
const string s = rc.GetResourceCompilerGenericInfo(newline);
string sSuffix;
sSuffix += newline;
sSuffix += newline;
sSuffix += newline;
sSuffix += "Use \"RC /help\" to list all available command-line options.";
sSuffix += newline;
sSuffix += newline;
sSuffix += "Press [OK] to copy the info above to clipboard.";
#if defined(AZ_PLATFORM_WINDOWS)
if (::MessageBoxA(NULL, (s + sSuffix).c_str(), "About", MB_OKCANCEL | MB_APPLMODAL | MB_SETFOREGROUND) == IDOK)
{
ResourceCompiler::CopyStringToClipboard(s);
}
#else
if (CryMessageBox((s + sSuffix).c_str(), "About", 0) == 1)
{
//TODO: CopyStringToClipboard needs cross platform support! Throwing an assert for now.
assert(0);
}
#endif
}
void GetCommandLineArguments(std::vector<string>& resArgs, int argc, char** argv)
{
resArgs.clear();
resArgs.reserve(argc);
for (int i = 0; i < argc; ++i)
{
resArgs.push_back(string(argv[i]));
}
}
void AddCommandLineArgumentsFromFile(std::vector<string>& args, const char* const pFilename)
{
FILE* f = nullptr;
azfopen(&f, pFilename, "rt");
if (!f)
{
return;
}
char line[1024];
while (fgets(line, sizeof(line), f) != 0)
{
if (line[0] == 0)
{
continue;
}
string sLine = line;
sLine.Trim();
if (sLine.empty())
{
continue;
}
args.push_back(sLine);
}
fclose(f);
}
static string GetTimeAsString(const time_t tm)
{
#if defined(AZ_PLATFORM_WINDOWS)
char buffer[26];
ctime_s(buffer, sizeof buffer, &tm);
#else
char* buffer = ctime(&tm);
#endif
string str = buffer;
while (StringHelpers::EndsWith(str, "\n"))
{
str = str.substr(0, str.length() - 1);
}
return str;
}
static void ShowResourceCompilerVersionInfo(const ResourceCompiler& rc)
{
const string newline("\n");
const string info = rc.GetResourceCompilerGenericInfo(newline);
std::vector<string> rows;
StringHelpers::Split(info, newline, true, rows);
for (size_t i = 0; i < rows.size(); ++i)
{
RCLog("%s", rows[i].c_str());
}
}
static void ShowResourceCompilerLaunchInfo(const std::vector<string>& args, int originalArgc, const ResourceCompiler& rc)
{
ShowResourceCompilerVersionInfo(rc);
RCLog("");
RCLog("Command line:");
for (size_t i = 0; i < args.size(); ++i)
{
if ((int)i < originalArgc)
{
RCLog(" \"%s\"", args[i].c_str());
}
else
{
RCLog(" \"%s\" (from %s)", args[i].c_str(), rc.m_filenameOptions);
}
}
RCLog("");
RCLog("Platforms specified in %s:", rc.m_filenameRcIni);
for (int i = 0; i < rc.GetPlatformCount(); ++i)
{
const PlatformInfo* const p = rc.GetPlatformInfo(i);
RCLog(" %s (%s)",
p->GetCommaSeparatedNames().c_str(),
(p->bBigEndian ? "big-endian" : "little-endian"));
}
RCLog("");
RCLog("Started at: %s", GetTimeAsString(time(0)).c_str());
}
static void ShowWaitDialog(const ResourceCompiler& rc, const string& action, const std::vector<string>& args, int originalArgc)
{
const string newline("\r\n");
const string title = string("RC is about to ") + action;
string sPrefix;
sPrefix += title;
sPrefix += " (/wait was specified).";
sPrefix += newline;
sPrefix += newline;
sPrefix += newline;
string s;
s += rc.GetResourceCompilerGenericInfo(newline);
s += "Command line:";
s += newline;
for (size_t i = 0; i < args.size(); ++i)
{
s += " \"";
s += args[i];
s += "\"";
if ((int)i >= originalArgc)
{
s += " (from ";
s += rc.m_filenameOptions;
s += ")";
}
s += newline;
}
string sSuffix;
sSuffix += newline;
sSuffix += "Do you want to copy the info above to clipboard?";
#if defined(AZ_PLATFORM_WINDOWS)
if (::MessageBoxA(NULL, (sPrefix + s + sSuffix).c_str(), title.c_str(), MB_YESNO | MB_ICONINFORMATION | MB_APPLMODAL | MB_SETFOREGROUND) == IDYES)
{
ResourceCompiler::CopyStringToClipboard(s);
}
#else
if (CryMessageBox((sPrefix + s + sSuffix).c_str(), title.c_str(), 0) == 1)
{
//TODO: CopyStringToClipboard needs cross platform support! Assert for now.
assert(0);
}
#endif
}
static bool RegisterConvertors(ResourceCompiler* pRc)
{
string strDir = pRc->GetExePath();
strDir.append(ResourceCompiler::m_rcPluginSubfolder);
strDir.append(AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
AZ::IO::LocalFileIO localFile;
bool foundOK = localFile.FindFiles(strDir.c_str(), CryLibraryDefName("ResourceCompiler*"), [&](const char* pluginFilename) -> bool
{
#if defined(AZ_PLATFORM_WINDOWS)
HMODULE hPlugin = CryLoadLibrary(pluginFilename);
#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX)
HMODULE hPlugin = CryLoadLibrary(pluginFilename, false, false);
#endif
if (!hPlugin)
{
const DWORD errCode = GetLastError();
char messageBuffer[1024] = { '?', 0 };
#if defined(AZ_PLATFORM_WINDOWS)
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
messageBuffer,
sizeof(messageBuffer) - 1,
NULL);
#endif
RCLogError("Couldn't load plug-in module \"%s\"", pluginFilename);
RCLogError("Error code: 0x%x = %s", errCode, messageBuffer);
// this return controls whether to keep going on other converters or stop the entire process here.
// it is NOT AN ERROR if one resource compiler dll fails to load
// it might not be the DLL that is required for this particular compile.
return true;
}
FnRegisterConvertors fnRegister =
hPlugin ? (FnRegisterConvertors)CryGetProcAddress(hPlugin, "RegisterConvertors") : NULL;
if (!fnRegister)
{
RCLog("Error: plug-in module \"%s\" doesn't have RegisterConvertors function", pluginFilename);
CryFreeLibrary(hPlugin);
// this return controls whether to keep going on other converters or stop the entire process here.
// it is NOT AN ERROR if one resource compiler dll fails to load
// it might not be the DLL that is required for this particular compile.
return true;
}
RCLog(" Loaded \"%s\"", pluginFilename);
pRc->AddPluginDLL(hPlugin);
const int oldErrorCount = pRc->GetNumErrors();
fnRegister(pRc);
const int newErrorCount = pRc->GetNumErrors();
if (newErrorCount > oldErrorCount)
{
RCLog("Error: plug-in module \"%s\" emitted errors during register", pluginFilename);
pRc->RemovePluginDLL(hPlugin);
FnBeforeUnloadDLL fnBeforeUnload = (FnBeforeUnloadDLL)CryGetProcAddress(hPlugin, "BeforeUnloadDLL");
if (fnBeforeUnload)
{
(*fnBeforeUnload)();
}
CryFreeLibrary(hPlugin);
// this return controls whether to keep going on other converters or stop the entire process here.
return true;
}
return true; // continue iterating to all plugins
});
return true;
}
int rcmain(int argc, char** argv, [[maybe_unused]] char** envp)
{
#if defined(AZ_PLATFORM_WINDOWS)
GetCrashHandler(); // just to initialize
#endif
std::unique_ptr<QCoreApplication> qApplication = CreateQApplication(argc, argv);
#if 0
EnableCrtMemoryChecks();
#endif
#if defined(AZ_PLATFORM_WINDOWS)
MathHelpers::EnableFloatingPointExceptions(~(_CW_DEFAULT));
#endif
ResourceCompiler rc;
rc.QueryVersionInfo();
rc.InitPaths();
if (argc <= 1)
{
ShowAboutDialog(rc);
return eRcExitCode_Success;
}
std::vector<string> args;
{
GetCommandLineArguments(args, argc, argv);
const string filename = string(rc.GetExePath()) + rc.m_filenameOptions;
AddCommandLineArgumentsFromFile(args, filename.c_str());
}
rc.RegisterDefaultKeys();
string fileSpec;
// Initialization, showing startup info, loading configs
{
Config mainConfig;
mainConfig.SetConfigKeyRegistry(&rc);
QSettings settings("HKEY_CURRENT_USER\\Software\\Amazon\\Lumberyard\\Settings", QSettings::NativeFormat);
bool enableSourceControl = settings.value("RC_EnableSourceControl", true).toBool();
mainConfig.SetKeyValue(eCP_PriorityCmdline, "nosourcecontrol", enableSourceControl ? "0" : "1");
CmdLine::Parse(args, &mainConfig, fileSpec);
// initialize rc (also initializes logs)
rc.Init(mainConfig);
AZ::Debug::Trace::HandleExceptions(true);
#if defined(AZ_PLATFORM_WINDOWS)
GetCrashHandler().SetDumpFile(rc.FormLogFileName(ResourceCompiler::m_filenameCrashDump));
#endif
if (mainConfig.GetAsBool("version", false, true))
{
ShowResourceCompilerVersionInfo(rc);
return eRcExitCode_Success;
}
switch (mainConfig.GetAsInt("wait", 0, 1))
{
case 3:
case 4:
ShowWaitDialog(rc, "start", args, argc);
break;
default:
break;
}
ShowResourceCompilerLaunchInfo(args, argc, rc);
rc.SetTimeLogging(mainConfig.GetAsBool("logtime", true, true));
rc.LogMemoryUsage(false);
RCLog("");
if (!rc.LoadIniFile())
{
return eRcExitCode_FatalError;
}
// Make sure that rc.ini doesn't have obsolete settings
for (int i = 0;; ++i)
{
const char* const pName = rc.GetIniFile()->GetSectionName(i);
if (!pName)
{
break;
}
Config cfg;
rc.GetIniFile()->CopySectionKeysToConfig(eCP_PriorityRcIni, i, 0, &cfg);
if (cfg.HasKeyMatchingWildcards("srgb") || cfg.HasKeyMatchingWildcards("srgb:*"))
{
RCLogError("Obsolete setting 'srgb' found in %s", rc.m_filenameRcIni);
RCLog(
"\n"
"Please replace all occurences of 'srgb' by corresponding\n"
"'colorspace' settings. Use the following table as the reference:\n"
" srgb=0 -> colorspace=linear,linear\n"
" srgb=1 -> colorspace=sRGB,auto\n"
" srgb=2 -> colorspace=sRGB,sRGB\n"
" srgb=3 -> colorspace=linear,sRGB\n"
" srgb=4 -> colorspace=sRGB,linear");
return eRcExitCode_FatalError;
}
}
// Load list of platforms
{
for (int i = 0;; ++i)
{
const char* const pName = rc.GetIniFile()->GetSectionName(i);
if (!pName)
{
break;
}
if (!StringHelpers::Equals(pName, "_platform"))
{
continue;
}
Config cfg;
rc.GetIniFile()->CopySectionKeysToConfig(eCP_PriorityRcIni, i, "", &cfg);
const string names = StringHelpers::MakeLowerCase(cfg.GetAsString("name", "", ""));
const bool bBigEndian = cfg.GetAsBool("bigendian", false, true);
const int pointerSize = cfg.GetAsInt("pointersize", 4, 0);
if (!rc.AddPlatform(names, bBigEndian, pointerSize))
{
RCLogError("Bad platform data in %s", rc.m_filenameRcIni);
return eRcExitCode_FatalError;
}
}
if (rc.GetPlatformCount() <= 0)
{
RCLogError("Missing [_platform] in %s", rc.m_filenameRcIni);
return eRcExitCode_FatalError;
}
}
// Obtain target platform
int platform;
{
string platformStr = mainConfig.GetAsString("p", "", "");
if (platformStr.empty())
{
if (!mainConfig.GetAsBool("version", false, true))
{
RCLog("Platform (/p) not specified, defaulting to 'pc'.");
RCLog("");
}
platformStr = "pc";
mainConfig.SetKeyValue(eCP_PriorityCmdline, "p", platformStr.c_str());
}
platform = rc.FindPlatform(platformStr.c_str());
if (platform < 0)
{
RCLogError("Unknown platform specified: '%s'", platformStr.c_str());
return eRcExitCode_FatalError;
}
}
// Load configs for every platform
rc.GetMultiplatformConfig().init(rc.GetPlatformCount(), platform, &rc);
for (int i = 0; i < rc.GetPlatformCount(); ++i)
{
IConfig& cfg = rc.GetMultiplatformConfig().getConfig(i);
rc.GetIniFile()->CopySectionKeysToConfig(eCP_PriorityRcIni, 0, rc.GetPlatformInfo(i)->GetCommaSeparatedNames().c_str(), &cfg);
cfg.AddConfig(&mainConfig);
}
}
const IConfig& config = rc.GetMultiplatformConfig().getConfig();
{
RCLog("Initializing pak management");
rc.InitPakManager();
RCLog("");
RCLog("Initializing System");
string appRootInput = config.GetAsString("approot", "", "");
if (!appRootInput.empty())
{
rc.SetAppRootPath(appRootInput);
}
else
{
// Create a local SettingsRegistry to read the bootstrap.cfg settings if the appRoot hasn't been overriden
// on the command line
AZ::SettingsRegistryImpl settingsRegistry;
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(settingsRegistry);
string gameName = config.GetAsString("gamesubdirectory", "", "");
if (!gameName.empty())
{
const auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder",
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey);
settingsRegistry.Set(gameFolderKey, gameName);
}
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(settingsRegistry);
// and because we're a tool, add the tool folders:
if (AZ::SettingsRegistryInterface::FixedValueString appRoot; settingsRegistry.Get(appRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
{
rc.SetAppRootPath(string{ appRoot.c_str(), appRoot.size() });
}
}
// only after installing and setting those up, do we install our handler because perforce does this too...
#if defined(AZ_PLATFORM_WINDOWS)
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandlerRoutine, TRUE);
#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX)
signal(SIGINT, CtrlHandlerRoutine);
#endif
RCLog("");
RCLog("Loading compiler plug-ins (ResourceCompiler*.dll)");
// Force the current working directory to be the same as the executable so
// that we can load any shared libraries that don't have run-time paths in
// them (I'm looking at you AWS SDK libraries!).
QString currentDir = QDir::currentPath();
QDir::setCurrent(QCoreApplication::applicationDirPath());
if (!RegisterConvertors(&rc))
{
RCLogError("A fatal error occurred when loading plug-ins (see error message(s) above). RC cannot continue.");
rc.UnregisterConvertors();
return eRcExitCode_FatalError;
}
// Restore currentDir so that file paths will work that are relative to
// where the user executed RC
QDir::setCurrent(currentDir);
RCLog("");
RCLog("Loading zip & pak compiler module");
rc.RegisterConvertor("zip & pak compiler", new ZipEncryptor(&rc));
RCLog("");
rc.LogMemoryUsage(false);
}
const bool bJobMode = config.HasKey("job");
// Don't even bother setting up if we aren't going to do anything
if (!bJobMode && !ResourceCompiler::CheckCommandLineOptions(config, 0))
{
return eRcExitCode_Error;
}
bool bExitCodeIsReady = false;
int exitCode = eRcExitCode_Success;
bool bShowUsage = false;
if (bJobMode)
{
const int tmpResult = rc.ProcessJobFile();
if (tmpResult)
{
exitCode = tmpResult;
bExitCodeIsReady = true;
}
rc.PostBuild(); // e.g. writing statistics files
}
else if (!fileSpec.empty())
{
rc.RemoveOutputFiles();
std::vector<RcFile> files;
if (rc.CollectFilesToCompile(fileSpec, files) && !files.empty())
{
rc.CompileFilesBySingleProcess(files);
}
rc.PostBuild(); // e.g. writing statistics files
}
else
{
bShowUsage = true;
}
rc.UnregisterConvertors();
rc.SetTimeLogging(false);
if (bShowUsage && !rc.m_bQuiet)
{
rc.ShowHelp(false);
}
if (config.GetAsBool("help", false, true))
{
rc.ShowHelp(true);
}
rc.LogMemoryUsage(false);
RCLog("");
RCLog("Finished at: %s", GetTimeAsString(time(0)).c_str());
if (rc.GetNumErrors() || rc.GetNumWarnings())
{
RCLog("");
RCLogSummary("%d errors, %d warnings.", rc.GetNumErrors(), rc.GetNumWarnings());
}
if (!bExitCodeIsReady)
{
const bool bFail = rc.GetNumErrors() || (rc.GetNumWarnings() && config.GetAsBool("failonwarnings", false, true));
exitCode = (bFail ? eRcExitCode_Error : eRcExitCode_Success);
bExitCodeIsReady = true;
}
switch (config.GetAsInt("wait", 0, 1))
{
case 1:
RCLog("");
RCLog(" Press <RETURN> (/wait was specified)");
getchar();
break;
case 2:
case 4:
ShowWaitDialog(rc, "finish", args, argc);
break;
default:
break;
}
return exitCode;
}
//////////////////////////////////////////////////////////////////////////
int __cdecl main(int argc, char** argv, char** envp)
{
AZ::Sfmt::Create();
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
AZ::AllocatorInstance<AZ::LegacyAllocator>::Create();
AZ::AllocatorInstance<CryStringAllocator>::Create();
int exitCode = 1;
{
exitCode = rcmain(argc, argv, envp);
}
AZ::AllocatorInstance<CryStringAllocator>::Destroy();
AZ::AllocatorInstance<AZ::LegacyAllocator>::Destroy();
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
AZ::Sfmt::Destroy();
//////////////////////////////////////////////////////////////////////////
AZ::AllocatorManager::Destroy();
return exitCode;
}
@@ -0,0 +1,147 @@
/*
* 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.
// This file should only be included Once in DLL module.
#include <platform.h>
#if defined(AZ_MONOLITHIC_BUILD)
# error It is not allowed to have AZ_MONOLITHIC_BUILD defined
#endif
#include <platform_implRC.h>
#include <Random.h>
#include <ISystem.h>
#if defined(AZ_PLATFORM_WINDOWS)
#define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k))
#define TLSFREE(k) (!TlsFree(k))
#define TLSGET(k) TlsGetValue(k)
#define TLSSET(k, a) (!TlsSetValue(k, a))
#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX)
#define TLSALLOC(k) pthread_key_create(k, 0)
#define TLSFREE(k) pthread_key_delete(k)
#define TLSGET(k) pthread_getspecific(k)
#define TLSSET(k, a) pthread_setspecific(k, a)
#else
#error TLS Not supported!!
#endif
IRCLog* g_pRCLog = 0;
void SetRCLog(IRCLog* pRCLog)
{
g_pRCLog = pRCLog;
}
void RCLog(const char* szFormat, ...)
{
va_list args;
va_start(args, szFormat);
if (g_pRCLog)
{
g_pRCLog->LogV(IRCLog::eType_Info, szFormat, args);
}
else
{
vprintf(szFormat, args);
printf("\n");
fflush(stdout);
}
va_end(args);
}
void RCLogWarning(const char* szFormat, ...)
{
va_list args;
va_start(args, szFormat);
if (g_pRCLog)
{
g_pRCLog->LogV(IRCLog::eType_Warning, szFormat, args);
}
else
{
vprintf(szFormat, args);
printf("\n");
fflush(stdout);
}
va_end(args);
}
void RCLogError(const char* szFormat, ...)
{
va_list args;
va_start (args, szFormat);
if (g_pRCLog)
{
g_pRCLog->LogV(IRCLog::eType_Error, szFormat, args);
}
else
{
vprintf(szFormat, args);
printf("\n");
fflush(stdout);
}
va_end(args);
}
void RCLogContext(const char* szMessage)
{
if (g_pRCLog)
{
g_pRCLog->Log(IRCLog::eType_Context, szMessage);
}
else
{
printf("%s\n", szMessage);
fflush(stdout);
}
}
void RCLogSummary(const char* szFormat, ...)
{
va_list args;
va_start(args, szFormat);
if (g_pRCLog)
{
g_pRCLog->LogV(IRCLog::eType_Summary, szFormat, args);
}
else
{
vprintf(szFormat, args);
printf("\n");
fflush(stdout);
}
va_end(args);
}
//////////////////////////////////////////////////////////////////////////
// Log important data that must be printed regardless verbosity.
void PlatformLogOutput(const char*, ...) PRINTF_PARAMS(1, 2);
inline void PlatformLogOutput(const char* format, ...)
{
assert(g_pRCLog);
if (g_pRCLog)
{
va_list args;
va_start(args, format);
g_pRCLog->LogV(IRCLog::eType_Error, format, args);
va_end(args);
}
}
@@ -0,0 +1,18 @@
/*
* 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.
// This file should only be included Once in DLL module.
#pragma once
#include <IRCLog.h>
+27
View File
@@ -0,0 +1,27 @@
/*
* 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.
*
*/
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ResourceCompiler.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
@@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
main.cpp
)
@@ -0,0 +1,71 @@
#
# 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.
#
set(FILES
IRCLog.h
IConfig.cpp
IConvertor.h
platform_implRC.h
platform_implRC.cpp
ZipEncryptor.cpp
ZipEncryptor.h
ICfgFile.h
IConfig.h
IConvertor.h
IMultiplatformConfig.h
IRCLog.h
IResCompiler.h
PakHelpers.cpp
PakManager.cpp
PakHelpers.h
PakManager.h
CfgFile.cpp
CmdLine.cpp
Config.cpp
DependencyList.cpp
ExcelExport.cpp
ExcelReport.cpp
ExtensionManager.cpp
ListFile.cpp
PropertyVars.cpp
ResourceCompiler_precompiled.cpp
ResourceCompiler_precompiled.h
TextFileReader.cpp
CfgFile.h
CmdLine.h
Config.h
ConvertContext.h
DebugLog.h
DependencyList.h
ExcelExport.h
ExcelReport.h
ExtensionManager.h
ListFile.h
MultiplatformConfig.h
PropertyVars.h
RcFile.h
resource.h
TextFileReader.h
AssetFileInfo.h
UpToDateFileHelpers.h
NameConvertor.h
SimpleString.h
IProgress.h
ResourceCompiler.rc
FunctionThread.h
ResourceCompiler.cpp
ResourceCompiler.h
)
set(SKIP_UNITY_BUILD_INCLUSION_FILES
IConfig.cpp
platform_implRC.cpp
)
@@ -0,0 +1,20 @@
#
# 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.
#
set(FILES
IUnitTestHelper.h
ResourceCompilerTests.cpp
UnitTestHelper.cpp
UnitTestHelper.h
Tests/test_Main.cpp
Tests/ResourceCompilerTestHelper.h
Tests/ZipEncryptorTests.cpp
)