mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-07 21:22:31 +08:00
801 lines
23 KiB
C++
801 lines
23 KiB
C++
#include "GacGen.h"
|
|
|
|
using namespace vl::collections;
|
|
using namespace vl::filesystem;
|
|
using namespace vl::presentation::controls;
|
|
|
|
GuiResourceCpuArchitecture targetCpuArchitecture = GuiResourceCpuArchitecture::Unspecified;
|
|
Array<WString>* arguments = 0;
|
|
WString executablePath;
|
|
|
|
void SetTargetCpuArchitecture()
|
|
{
|
|
if (arguments->Count() > 0)
|
|
{
|
|
if (arguments->Get(0) == L"/P32" || arguments->Get(0) == L"/D32" || arguments->Get(0) == L"/C32")
|
|
{
|
|
targetCpuArchitecture = GuiResourceCpuArchitecture::x86;
|
|
}
|
|
else if (arguments->Get(0) == L"/P64" || arguments->Get(0) == L"/D64" || arguments->Get(0) == L"/C64")
|
|
{
|
|
targetCpuArchitecture = GuiResourceCpuArchitecture::x64;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined VCZH_MSVC
|
|
int wmain(int argc, wchar_t* argv[])
|
|
{
|
|
executablePath = argv[0];
|
|
Array<WString> _arguments(argc - 1);
|
|
for (vint i = 1; i < argc; i++)
|
|
{
|
|
_arguments[i - 1] = argv[i];
|
|
}
|
|
arguments = &_arguments;
|
|
SetTargetCpuArchitecture();
|
|
return SetupGacGenNativeController();
|
|
}
|
|
#elif defined VCZH_GCC
|
|
int main(int argc, char* argv[])
|
|
{
|
|
executablePath = atow(argv[0]);
|
|
Array<WString> _arguments(argc - 1);
|
|
for (vint i = 1; i < argc; i++)
|
|
{
|
|
_arguments[i - 1] = atow(argv[i]);
|
|
}
|
|
arguments = &_arguments;
|
|
SetTargetCpuArchitecture();
|
|
return SetupGacGenNativeController();
|
|
}
|
|
#endif
|
|
|
|
void PrintErrors(List<GuiResourceError>& errors)
|
|
{
|
|
List<WString> output;
|
|
GuiResourceError::SortAndLog(errors, output);
|
|
for (auto line : output)
|
|
{
|
|
PrintErrorMessage(line);
|
|
}
|
|
}
|
|
|
|
void SaveErrors(FilePath errorFilePath, List<GuiResourceError>& errors)
|
|
{
|
|
PrintErrors(errors);
|
|
if (WriteErrors(errors, errorFilePath))
|
|
{
|
|
PrintErrorMessage(L"error> Error information is saved at : " + errorFilePath.GetFullPath());
|
|
}
|
|
else
|
|
{
|
|
PrintErrorMessage(L"error> Unable to write : " + errorFilePath.GetFullPath());
|
|
}
|
|
}
|
|
|
|
class Callback : public Object, public IGuiResourcePrecompileCallback, public IWfCompilerCallback
|
|
{
|
|
public:
|
|
vint lastPass = -1;
|
|
|
|
void OnLoadEnvironment()override
|
|
{
|
|
PrintInformationMessage(L" Workflow: Loading metadata from registered types ...");
|
|
}
|
|
|
|
void OnInitialize(analyzer::WfLexicalScopeManager* manager)override
|
|
{
|
|
PrintInformationMessage(L" Workflow: Creating metadata from declarations ...");
|
|
}
|
|
|
|
void OnValidateModule(Ptr<WfModule> module)override
|
|
{
|
|
PrintInformationMessage(L" Workflow: Validating module " + module->name.value + L" ...");
|
|
}
|
|
|
|
void OnGenerateMetadata()override
|
|
{
|
|
PrintInformationMessage(L" Workflow: Generating metadata ...");
|
|
}
|
|
|
|
void OnGenerateCode(Ptr<WfModule> module)override
|
|
{
|
|
PrintInformationMessage(L" Workflow: Generating code for module " + module->name.value + L" ...");
|
|
}
|
|
|
|
void OnGenerateDebugInfo()override
|
|
{
|
|
PrintInformationMessage(L" Workflow: Generating debug information ...");
|
|
}
|
|
|
|
IWfCompilerCallback* GetCompilerCallback()override
|
|
{
|
|
return this;
|
|
}
|
|
|
|
void PrintPass(vint passIndex)
|
|
{
|
|
if (lastPass != passIndex)
|
|
{
|
|
lastPass = passIndex;
|
|
switch (passIndex)
|
|
{
|
|
case IGuiResourceTypeResolver_Precompile::Workflow_Collect:
|
|
PrintInformationMessage(L"Pass: (1/8) Collect workflow scripts");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Workflow_Compile:
|
|
PrintInformationMessage(L"Pass: (2/8) Compile view model scripts");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Instance_CollectInstanceTypes:
|
|
PrintInformationMessage(L"Pass: (3/8) Collect instances");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Instance_CompileInstanceTypes:
|
|
PrintInformationMessage(L"Pass: (4/8) Validate instances");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Instance_CollectEventHandlers:
|
|
PrintInformationMessage(L"Pass: (5/8) Generate instance type stubs");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Instance_CompileEventHandlers:
|
|
PrintInformationMessage(L"Pass: (6/8) Compile instance type stubs");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Instance_GenerateInstanceClass:
|
|
PrintInformationMessage(L"Pass: (7/8) Generate instance types");
|
|
break;
|
|
case IGuiResourceTypeResolver_Precompile::Instance_CompileInstanceClass:
|
|
PrintInformationMessage(L"Pass: (8/8) Compile instance types");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnPerPass(vint passIndex)override
|
|
{
|
|
PrintPass(passIndex);
|
|
}
|
|
|
|
void OnPerResource(vint passIndex, Ptr<GuiResourceItem> resource)override
|
|
{
|
|
PrintPass(passIndex);
|
|
PrintInformationMessage(L" " + resource->GetResourcePath());
|
|
}
|
|
};
|
|
|
|
struct LoadConfigResult
|
|
{
|
|
Ptr<GuiResource> resource;
|
|
Ptr<CodegenConfig> config;
|
|
};
|
|
|
|
LoadConfigResult LoadConfig(FilePath inputPath)
|
|
{
|
|
List<GuiResourceError> errors;
|
|
auto resource = GuiResource::LoadFromXml(inputPath.GetFullPath(), errors);
|
|
|
|
for (vint i = errors.Count() - 1; i >= 0; i--)
|
|
{
|
|
auto error = errors[i];
|
|
if (INVLOC.FindFirst(error.message, L"Path of imported folder does not exist:", Locale::None).key == 0)
|
|
{
|
|
errors.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
if (errors.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load resource.");
|
|
PrintErrors(errors);
|
|
return {};
|
|
}
|
|
|
|
auto config = CodegenConfig::LoadConfig(resource, errors);
|
|
if (!config)
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load config.");
|
|
return {};
|
|
}
|
|
if (errors.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load resource metadata.");
|
|
PrintErrors(errors);
|
|
return {};
|
|
}
|
|
|
|
LoadConfigResult result;
|
|
result.resource = resource;
|
|
result.config = config;
|
|
return result;
|
|
}
|
|
|
|
bool LoadDependencies(Ptr<CodegenConfig> config, Dictionary<WString, FilePath>& resourceMappings, const WString& logFolderPostfix, FilePath errorFilePath)
|
|
{
|
|
if (config->metadata->version == L"")
|
|
{
|
|
config->metadata->version = GuiResource::CurrentVersionString;
|
|
}
|
|
|
|
if (config->metadata->version != GuiResource::CurrentVersionString)
|
|
{
|
|
PrintErrorMessage(L"error> Version of the resource should be \"" + WString(GuiResource::CurrentVersionString) + L"\"");
|
|
return false;
|
|
}
|
|
|
|
if (config->metadata->dependencies.Count() > 0 && config->metadata->name == L"")
|
|
{
|
|
PrintErrorMessage(L"error> Name of the resource should not be empty if it has dependencies.");
|
|
return false;
|
|
}
|
|
|
|
SortedList<WString> requireds, loaded;
|
|
CopyFrom(requireds, config->metadata->dependencies);
|
|
|
|
while (requireds.Count() > 0)
|
|
{
|
|
auto required = requireds[requireds.Count() - 1];
|
|
requireds.RemoveAt(requireds.Count() - 1);
|
|
if (loaded.Contains(required)) continue;
|
|
|
|
vint index = resourceMappings.Keys().IndexOf(required);
|
|
if (index == -1)
|
|
{
|
|
PrintErrorMessage(L"error> Cannot find the resource file of name: " + required);
|
|
return false;
|
|
}
|
|
|
|
FilePath resourceBinary = FilePath(resourceMappings.Values()[index].GetFullPath() + logFolderPostfix) / L"ScriptedResource.bin";
|
|
MemoryStream resourceStream;
|
|
{
|
|
FileStream fileStream(resourceBinary.GetFullPath(), FileStream::ReadOnly);
|
|
if (!fileStream.IsAvailable())
|
|
{
|
|
PrintErrorMessage(L"error> Cannot find binary resource file, please make sure the required resource \"" + required + L"\" has been properly compiled: " + required);
|
|
return false;
|
|
}
|
|
CopyStream(fileStream, resourceStream);
|
|
}
|
|
|
|
loaded.Add(required);
|
|
{
|
|
resourceStream.SeekFromBegin(0);
|
|
stream::internal::ContextFreeReader reader(resourceStream);
|
|
|
|
WString metadataText;
|
|
reader << metadataText;
|
|
|
|
GuiResourceError::List errors;
|
|
auto parser = GetParserManager()->GetParser<XmlDocument>(L"XML");
|
|
auto xmlMetadata = parser->Parse({}, metadataText, errors);
|
|
if (!xmlMetadata || errors.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> The binary resource file has an invalid metadata, please make sure the required resource \"" + required + L"\" has been properly compiled: " + required);
|
|
return false;
|
|
}
|
|
|
|
auto metadata = Ptr(new GuiResourceMetadata);
|
|
metadata->LoadFromXml(xmlMetadata, {}, errors);
|
|
if (errors.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> The binary resource file has an invalid metadata, please make sure the required resource \"" + required + L"\" has been properly compiled: " + required);
|
|
return false;
|
|
}
|
|
|
|
CopyFrom(requireds, metadata->dependencies, true);
|
|
}
|
|
|
|
resourceStream.SeekFromBegin(0);
|
|
GuiResourceError::List errors;
|
|
GetResourceManager()->LoadResourceOrPending(resourceStream, errors, GuiResourceUsage::InstanceClass);
|
|
if (errors.Count() > 0)
|
|
{
|
|
SaveErrors(errorFilePath, errors);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
List<WString> pendings;
|
|
GetResourceManager()->GetPendingResourceNames(pendings);
|
|
if (pendings.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> Unable to find dependencies: "
|
|
+ From(pendings)
|
|
.Aggregate(WString::Empty, [](const WString& a, const WString& b) {return a == L"" ? b : a + L", " + b; })
|
|
);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CompileResource(bool partialMode, FilePath inputPath, Nullable<FilePath> mappingPath)
|
|
{
|
|
PrintSuccessMessage(L"gacgen> Clearning logs ... : " + inputPath.GetFullPath());
|
|
|
|
WString logFolderPostfix;
|
|
switch (targetCpuArchitecture)
|
|
{
|
|
case GuiResourceCpuArchitecture::x86:
|
|
logFolderPostfix = L".log/x32";
|
|
break;
|
|
case GuiResourceCpuArchitecture::x64:
|
|
logFolderPostfix = L".log/x64";
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
FilePath logFolderPath = inputPath.GetFullPath() + logFolderPostfix;
|
|
FilePath scriptFilePath = logFolderPath / L"Workflow.txt";
|
|
FilePath errorFilePath = logFolderPath / L"Errors.txt";
|
|
FilePath workingDir = inputPath.GetFolder();
|
|
|
|
{
|
|
auto loadConfigResult = LoadConfig(inputPath);
|
|
if (!loadConfigResult.resource) return;
|
|
|
|
Dictionary<WString, FilePath> resourceMappings;
|
|
if (mappingPath)
|
|
{
|
|
FileStream fileStream(mappingPath.Value().GetFullPath(), FileStream::ReadOnly);
|
|
if (!fileStream.IsAvailable())
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load mapping file: " + mappingPath.Value().GetFullPath());
|
|
return;
|
|
}
|
|
BomDecoder decoder;
|
|
DecoderStream decoderStream(fileStream, decoder);
|
|
StreamReader reader(decoderStream);
|
|
while (!reader.IsEnd())
|
|
{
|
|
auto line = reader.ReadLine();
|
|
if (line != L"")
|
|
{
|
|
auto arrow = INVLOC.FindFirst(line, L"=>", Locale::None);
|
|
if (arrow.key == -1)
|
|
{
|
|
PrintErrorMessage(L"warning> Unable to parse mapping information: " + line);
|
|
return;
|
|
}
|
|
auto name = line.Left(arrow.key);
|
|
auto value = line.Right(line.Length() - arrow.key - arrow.value);
|
|
if (resourceMappings.Keys().Contains(name))
|
|
{
|
|
PrintErrorMessage(L"warning> Find duplicate mapping information: " + line);
|
|
return;
|
|
}
|
|
resourceMappings.Add(name, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!LoadDependencies(loadConfigResult.config, resourceMappings, logFolderPostfix, errorFilePath))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (partialMode)
|
|
{
|
|
PrintInformationMessage(L"gacgen> Partial mode activated, all output files will be put under " + logFolderPath.GetFullPath());
|
|
}
|
|
|
|
{
|
|
Folder logFolder(logFolderPath);
|
|
if (logFolder.Exists())
|
|
{
|
|
if (!logFolder.Delete(true))
|
|
{
|
|
PrintErrorMessage(L"gacgen> Unable to delete file in the log folder : " + logFolderPath.GetFullPath());
|
|
return;
|
|
}
|
|
}
|
|
if (!logFolder.Create(true))
|
|
{
|
|
Thread::Sleep(500);
|
|
if (!logFolder.Create(true))
|
|
{
|
|
PrintErrorMessage(L"gacgen> Unable to create log folder : " + logFolderPath.GetFullPath());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Ptr<GuiResource> resource;
|
|
{
|
|
PrintSuccessMessage(L"gacgen> Making : " + inputPath.GetFullPath());
|
|
List<GuiResourceError> errors;
|
|
resource = GuiResource::LoadFromXml(inputPath.GetFullPath(), errors);
|
|
if (errors.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load resource.");
|
|
SaveErrors(errorFilePath, errors);
|
|
return;
|
|
}
|
|
}
|
|
|
|
List<FilePath> cppResourcePaths;
|
|
List<FilePath> cppCompressedPaths;
|
|
List<FilePath> resResourcePaths;
|
|
List<FilePath> resCompressedPaths;
|
|
List<FilePath> resAssemblyPaths;
|
|
Ptr<CodegenConfig::CppOutput> cppOutput;
|
|
Ptr<CodegenConfig::ResOutput> resOutput;
|
|
{
|
|
Ptr<CodegenConfig> config;
|
|
{
|
|
List<GuiResourceError> errors;
|
|
config = CodegenConfig::LoadConfig(resource, errors);
|
|
if (!config)
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load config.");
|
|
return;
|
|
}
|
|
if (errors.Count() > 0)
|
|
{
|
|
PrintErrorMessage(L"error> Failed to load resource metadata.");
|
|
SaveErrors(errorFilePath, errors);
|
|
return;
|
|
}
|
|
}
|
|
{
|
|
cppResourcePaths.Add(logFolderPath / L"Resource.bin");
|
|
cppCompressedPaths.Add(logFolderPath / L"Compressed.bin");
|
|
resResourcePaths.Add(logFolderPath / L"ScriptedResource.bin");
|
|
resCompressedPaths.Add(logFolderPath / L"ScriptedCompressed.bin");
|
|
resAssemblyPaths.Add(logFolderPath / L"Assembly.bin");
|
|
}
|
|
|
|
cppOutput = config->cppOutput;
|
|
switch (targetCpuArchitecture)
|
|
{
|
|
case GuiResourceCpuArchitecture::x86:
|
|
resOutput = config->resOutputx32;
|
|
break;
|
|
case GuiResourceCpuArchitecture::x64:
|
|
resOutput = config->resOutputx64;
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
if (cppOutput)
|
|
{
|
|
if (config->cppOutput->resource != L"") cppResourcePaths.Add(workingDir / config->cppOutput->resource);
|
|
if (config->cppOutput->compressed != L"") resAssemblyPaths.Add(workingDir / config->cppOutput->compressed);
|
|
}
|
|
|
|
if (resOutput)
|
|
{
|
|
if (resOutput->resource != L"") resResourcePaths.Add(workingDir / resOutput->resource);
|
|
if (resOutput->compressed != L"") resCompressedPaths.Add(workingDir / resOutput->compressed);
|
|
if (resOutput->assembly != L"") resAssemblyPaths.Add(workingDir / resOutput->assembly);
|
|
}
|
|
}
|
|
|
|
PrintSuccessMessage(L"gacgen> Compiling...");
|
|
List<GuiResourceError> errors;
|
|
Callback callback;
|
|
|
|
auto precompiledFolder = PrecompileResource(resource, targetCpuArchitecture, &callback, errors);
|
|
if (errors.Count() > 0)
|
|
{
|
|
SaveErrors(errorFilePath, errors);
|
|
return;
|
|
}
|
|
|
|
if (auto compiled = WriteWorkflowScript(precompiledFolder, L"Workflow/InstanceClass", scriptFilePath))
|
|
{
|
|
if (cppOutput)
|
|
{
|
|
PrintSuccessMessage(L"gacgen> Generating C++ source code ...");
|
|
auto input = Ptr(new WfCppInput(cppOutput->name));
|
|
input->multiFile = WfCppFileSwitch::Enabled;
|
|
input->reflection = WfCppFileSwitch::Enabled;
|
|
input->comment = L"GacGen.exe " + FilePath(inputPath).GetName();
|
|
input->defaultFileName = cppOutput->name + L"PartialClasses";
|
|
input->includeFileName = cppOutput->name;
|
|
CopyFrom(input->normalIncludes, cppOutput->normalIncludes);
|
|
CopyFrom(input->reflectionIncludes, cppOutput->reflectionIncludes);
|
|
|
|
FilePath cppFolder = workingDir / cppOutput->sourceFolder;
|
|
if (partialMode)
|
|
{
|
|
File(logFolderPath / L"CppOutput.txt").WriteAllText(cppFolder.GetFullPath(), false, BomEncoder::Mbcs);
|
|
|
|
cppFolder = logFolderPath / L"Source";
|
|
if (!Folder(cppFolder).Create(true))
|
|
{
|
|
PrintSuccessMessage(L"gacgen> Unable to create source folder : " + cppFolder.GetFullPath());
|
|
}
|
|
}
|
|
|
|
auto output = WriteCppCodesToFile(resource, compiled, input, cppFolder, errors);
|
|
if (errors.Count() > 0)
|
|
{
|
|
SaveErrors(errorFilePath, errors);
|
|
return;
|
|
}
|
|
|
|
if (cppOutput->cppResource != L"")
|
|
{
|
|
WriteEmbeddedResource(resource, input, output, false, cppFolder / cppOutput->cppResource);
|
|
}
|
|
if (cppOutput->cppCompressed != L"")
|
|
{
|
|
WriteEmbeddedResource(resource, input, output, true, cppFolder / cppOutput->cppCompressed);
|
|
}
|
|
}
|
|
|
|
for (auto filePath : cppResourcePaths)
|
|
{
|
|
PrintSuccessMessage(L"Generating binary resource file (no script): " + filePath.GetFullPath());
|
|
WriteBinaryResource(resource, false, false, filePath, {});
|
|
}
|
|
for (auto filePath : cppCompressedPaths)
|
|
{
|
|
PrintSuccessMessage(L"Generating compressed resource file (no script): " + filePath.GetFullPath());
|
|
WriteBinaryResource(resource, true, false, filePath, {});
|
|
}
|
|
for (auto filePath : resResourcePaths)
|
|
{
|
|
PrintSuccessMessage(L"Generating binary resource files : " + filePath.GetFullPath());
|
|
WriteBinaryResource(resource, false, true, filePath, {});
|
|
}
|
|
for (auto filePath : resCompressedPaths)
|
|
{
|
|
PrintSuccessMessage(L"Generating compressed resource files : " + filePath.GetFullPath());
|
|
WriteBinaryResource(resource, true, true, filePath, {});
|
|
}
|
|
for (auto filePath : resAssemblyPaths)
|
|
{
|
|
PrintSuccessMessage(L"Generating assembly files : " + filePath.GetFullPath());
|
|
WriteBinaryResource(resource, false, false, {}, filePath);
|
|
}
|
|
|
|
if (partialMode)
|
|
{
|
|
List<WString> lines;
|
|
List<FilePath>* outputPaths[] =
|
|
{
|
|
&cppResourcePaths,
|
|
&cppCompressedPaths,
|
|
&resResourcePaths,
|
|
&resCompressedPaths,
|
|
&resAssemblyPaths,
|
|
};
|
|
|
|
for (vint i = 0; i < sizeof(outputPaths) / sizeof(*outputPaths); i++)
|
|
{
|
|
auto& paths = *outputPaths[i];
|
|
if (paths.Count() == 2)
|
|
{
|
|
lines.Add(L"copy \"" + paths[0].GetFullPath() + L"\" \"" + paths[1].GetFullPath() + L"\"");
|
|
}
|
|
}
|
|
|
|
if (lines.Count() > 0)
|
|
{
|
|
File(logFolderPath / L"Deploy.bat").WriteAllLines(lines, false, BomEncoder::Mbcs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DumpResource(FilePath inputPath, FilePath outputPath)
|
|
{
|
|
PrintSuccessMessage(L"gacgen> Dumping : " + inputPath.GetFullPath());
|
|
auto loadConfigResult = LoadConfig(inputPath);
|
|
if (!loadConfigResult.resource) return;
|
|
|
|
auto doc = Ptr(new XmlDocument);
|
|
auto xmlRoot = Ptr(new XmlElement);
|
|
xmlRoot->name.value = L"ResourceMetadata";
|
|
doc->rootElement = xmlRoot;
|
|
|
|
xmlRoot->subNodes.Add(loadConfigResult.resource->GetMetadata()->SaveToXml());
|
|
{
|
|
SortedList<WString> paths;
|
|
List<Ptr<GuiResourceFolder>> folders;
|
|
folders.Add(loadConfigResult.resource);
|
|
for (vint i = 0; i < folders.Count(); i++)
|
|
{
|
|
auto currentFolder = folders[i];
|
|
if (currentFolder->GetFileAbsolutePath() != L"" && !paths.Contains(currentFolder->GetFileAbsolutePath()))
|
|
{
|
|
paths.Add(currentFolder->GetFileAbsolutePath());
|
|
}
|
|
|
|
for (auto item : currentFolder->GetItems())
|
|
{
|
|
if (item->GetFileAbsolutePath() != L"" && !paths.Contains(item->GetFileAbsolutePath()))
|
|
{
|
|
paths.Add(item->GetFileAbsolutePath());
|
|
}
|
|
}
|
|
|
|
for (auto folder : currentFolder->GetFolders())
|
|
{
|
|
folders.Add(folder);
|
|
}
|
|
}
|
|
|
|
auto xmlInputs = Ptr(new XmlElement);
|
|
xmlInputs->name.value = L"Inputs";
|
|
xmlRoot->subNodes.Add(xmlInputs);
|
|
|
|
for (auto path : paths)
|
|
{
|
|
auto xmlInput = Ptr(new XmlElement);
|
|
xmlInput->name.value = L"Input";
|
|
xmlInputs->subNodes.Add(xmlInput);
|
|
{
|
|
auto attr = Ptr(new XmlAttribute);
|
|
attr->name.value = L"Path";
|
|
attr->value.value = path;
|
|
xmlInput->attributes.Add(attr);
|
|
}
|
|
}
|
|
}
|
|
{
|
|
SortedList<WString> paths;
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x32" / L"Resource.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x32" / L"Compressed.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x32" / L"ScriptedResource.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x32" / L"ScriptedCompressed.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x32" / L"Assembly.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x64" / L"Resource.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x64" / L"Compressed.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x64" / L"ScriptedResource.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x64" / L"ScriptedCompressed.bin").GetFullPath());
|
|
paths.Add((FilePath(inputPath.GetFullPath() + L".log") / L"x64" / L"Assembly.bin").GetFullPath());
|
|
|
|
auto xmlOutputs = Ptr(new XmlElement);
|
|
xmlOutputs->name.value = L"Outputs";
|
|
xmlRoot->subNodes.Add(xmlOutputs);
|
|
|
|
for (auto path : paths)
|
|
{
|
|
auto xmlOutput = Ptr(new XmlElement);
|
|
xmlOutput->name.value = L"Output";
|
|
xmlOutputs->subNodes.Add(xmlOutput);
|
|
{
|
|
auto attr = Ptr(new XmlAttribute);
|
|
attr->name.value = L"Path";
|
|
attr->value.value = path;
|
|
xmlOutput->attributes.Add(attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
FileStream fileStream(outputPath.GetFullPath(), FileStream::WriteOnly);
|
|
if (!fileStream.IsAvailable())
|
|
{
|
|
PrintErrorMessage(L"error> Failed to write file: " + outputPath.GetFullPath());
|
|
return;
|
|
}
|
|
|
|
BomEncoder encoder(BomEncoder::Utf8);
|
|
EncoderStream encoderStream(fileStream, encoder);
|
|
StreamWriter writer(encoderStream);
|
|
XmlPrint(doc, writer);
|
|
}
|
|
}
|
|
|
|
class GuiReflectionPlugin : public Object, public IGuiPlugin
|
|
{
|
|
public:
|
|
|
|
GUI_PLUGIN_NAME(GacUI_Instance_Reflection)
|
|
{
|
|
}
|
|
|
|
void Load(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
|
|
{
|
|
FilePath exeFolder = FilePath(executablePath).GetFolder();
|
|
FilePath metadataFolder = exeFolder;
|
|
auto binaryName32 = WString::Unmanaged(L"Reflection32.bin");
|
|
auto binaryName64 = WString::Unmanaged(L"Reflection64.bin");
|
|
{
|
|
File metadataOverride = exeFolder / L"Metadata.txt";
|
|
if (metadataOverride.Exists())
|
|
{
|
|
List<WString> lines;
|
|
metadataOverride.ReadAllLinesByBom(lines);
|
|
if (lines.Count() < 3)
|
|
{
|
|
Console::WriteLine(L"Metadata.txt should contains 3 lines for <MetadataFolder>, <Binary for x86>, <Binary for x64>.");
|
|
CHECK_FAIL(L"Metadata.txt should contains 3 lines for <MetadataFolder>, <Binary for x86>, <Binary for x64>.");
|
|
}
|
|
metadataFolder = exeFolder / lines[0];
|
|
binaryName32 = lines[1];
|
|
binaryName64 = lines[2];
|
|
}
|
|
}
|
|
|
|
const wchar_t* BINARY_NAME = nullptr;
|
|
switch (targetCpuArchitecture)
|
|
{
|
|
case GuiResourceCpuArchitecture::x86:
|
|
BINARY_NAME = binaryName32.Buffer();
|
|
break;
|
|
case GuiResourceCpuArchitecture::x64:
|
|
BINARY_NAME = binaryName64.Buffer();
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
FilePath binaryPath = metadataFolder / BINARY_NAME;
|
|
|
|
if (!File(binaryPath).Exists())
|
|
{
|
|
Console::WriteLine(L"Unable to find the GacUI type metadata file at: " + binaryPath.GetFullPath());
|
|
CHECK_FAIL(L"Unable to find the GacUI type metadata file!");
|
|
}
|
|
|
|
#define INSTALL_SERIALIZABLE_TYPE(TYPE) serializableTypes.Add(TypeInfo<TYPE>::content.typeName, Ptr(new SerializableType<TYPE>));
|
|
collections::Dictionary<WString, Ptr<ISerializableType>> serializableTypes;
|
|
REFLECTION_PREDEFINED_SERIALIZABLE_TYPES(INSTALL_SERIALIZABLE_TYPE)
|
|
INSTALL_SERIALIZABLE_TYPE(Color)
|
|
INSTALL_SERIALIZABLE_TYPE(GlobalStringKey)
|
|
INSTALL_SERIALIZABLE_TYPE(DocumentFontSize)
|
|
|
|
FileStream fileStream(binaryPath.GetFullPath(), FileStream::ReadOnly);
|
|
auto typeLoader = LoadMetaonlyTypes(fileStream, serializableTypes);
|
|
auto tm = GetGlobalTypeManager();
|
|
tm->AddTypeLoader(typeLoader);
|
|
#undef INSTALL_SERIALIZABLE_TYPE
|
|
}
|
|
|
|
void Unload(bool controllerUnrelatedPlugins, bool controllerRelatedPlugins)override
|
|
{
|
|
}
|
|
};
|
|
GUI_REGISTER_PLUGIN(GuiReflectionPlugin)
|
|
|
|
void GuiMain()
|
|
{
|
|
Console::SetTitle(L"Vczh GacUI Resource Code Generator for C++");
|
|
|
|
if (arguments->Count() > 0)
|
|
{
|
|
if (arguments->Get(0) == L"/P32" || arguments->Get(0) == L"/P64")
|
|
{
|
|
switch (arguments->Count())
|
|
{
|
|
case 2:
|
|
CompileResource(true, arguments->Get(1), {});
|
|
return;
|
|
case 3:
|
|
CompileResource(true, arguments->Get(1), { arguments->Get(2) });
|
|
return;
|
|
}
|
|
}
|
|
else if (arguments->Get(0) == L"/D32" || arguments->Get(0) == L"/D64")
|
|
{
|
|
switch (arguments->Count())
|
|
{
|
|
case 3:
|
|
DumpResource(arguments->Get(1), arguments->Get(2));
|
|
return;
|
|
}
|
|
}
|
|
else if (arguments->Get(0) == L"/C32" || arguments->Get(0) == L"/C64")
|
|
{
|
|
switch (arguments->Count())
|
|
{
|
|
case 2:
|
|
CompileResource(false, arguments->Get(1), {});
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
PrintErrorMessage(L"Usage");
|
|
PrintErrorMessage(L" Compile for x86 or x64 for GacBuild.ps1:");
|
|
PrintErrorMessage(L" GacGen.exe /P32 <input-xml> [<mapping-file>]");
|
|
PrintErrorMessage(L" GacGen.exe /P64 <input-xml> [<mapping-file>]");
|
|
PrintErrorMessage(L" Dump for x86 or x64 for GacBuild.ps1:");
|
|
PrintErrorMessage(L" GacGen.exe /D32 <input-xml> <output-xml>");
|
|
PrintErrorMessage(L" GacGen.exe /D64 <input-xml> <output-xml>");
|
|
PrintErrorMessage(L" Compile for x86 or x64 if you only want one architecture:");
|
|
PrintErrorMessage(L" GacGen.exe /C32 <input-xml>");
|
|
PrintErrorMessage(L" GacGen.exe /C64 <input-xml>");
|
|
}
|