diff --git a/README.md b/README.md index c7a9c2848..5006f8d4b 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,9 @@ ZAPD also accepts the following list of extra parameters: - `both`: `CS_FLOAT(0x42280000, 42.0f)` - `hex-commented-left`: `/* 42.0f */ 0x42280000` - `hex-commented-right`: `0x42280000 /* 42.0f */` +- `--base-address ADDRESS`: Override base virtual address for input files. +- `--start-offset OFFSET`: Override start offset for input files. +- `--end-offset OFFSET`: Override end offset for input files. - `-W...`: warning flags, see below Additionally, you can pass the flag `--version` to see the current ZAPD version. If that flag is passed, ZAPD will ignore any other parameter passed. diff --git a/ZAPD/Globals.h b/ZAPD/Globals.h index 6f603e7a5..2cc9c2d4d 100644 --- a/ZAPD/Globals.h +++ b/ZAPD/Globals.h @@ -41,6 +41,9 @@ class Globals fs::path baseRomPath, inputPath, outputPath, sourceOutputPath, cfgPath; TextureType texType; CsFloatType floatType = CsFloatType::FloatOnly; + int64_t baseAddress = -1; + int64_t startOffset = -1; + int64_t endOffset = -1; ZGame game; GameConfig cfg; bool verboseUnaccounted = false; diff --git a/ZAPD/Main.cpp b/ZAPD/Main.cpp index 75529119a..19d10d7d9 100644 --- a/ZAPD/Main.cpp +++ b/ZAPD/Main.cpp @@ -37,6 +37,9 @@ void Arg_EnableGCCCompat(int& i, char* argv[]); void Arg_ForceStatic(int& i, char* argv[]); void Arg_ForceUnaccountedStatic(int& i, char* argv[]); void Arg_CsFloatMode(int& i, char* argv[]); +void Arg_BaseAddress(int& i, char* argv[]); +void Arg_StartOffset(int& i, char* argv[]); +void Arg_EndOffset(int& i, char* argv[]); int main(int argc, char* argv[]); @@ -254,6 +257,9 @@ void ParseArgs(int& argc, char* argv[]) {"-us", &Arg_ForceUnaccountedStatic}, {"--unaccounted-static", &Arg_ForceUnaccountedStatic}, {"--cs-float", &Arg_CsFloatMode}, + {"--base-address", &Arg_BaseAddress}, + {"--start-offset", &Arg_StartOffset}, + {"--end-offset", &Arg_EndOffset}, }; for (int32_t i = 2; i < argc; i++) @@ -429,6 +435,27 @@ void Arg_CsFloatMode([[maybe_unused]] int& i, [[maybe_unused]] char* argv[]) } } +uint32_t ParseU32Hex(char* str) +{ + static_assert(sizeof(uint32_t) <= sizeof(unsigned long)); + return (uint32_t)std::stoul(str, nullptr, 16); +} + +void Arg_BaseAddress(int& i, char* argv[]) +{ + Globals::Instance->baseAddress = ParseU32Hex(argv[++i]); +} + +void Arg_StartOffset(int& i, char* argv[]) +{ + Globals::Instance->startOffset = ParseU32Hex(argv[++i]); +} + +void Arg_EndOffset(int& i, char* argv[]) +{ + Globals::Instance->endOffset = ParseU32Hex(argv[++i]); +} + int HandleExtract(ZFileMode fileMode, ExporterSet* exporterSet) { bool procFileModeSuccess = false; diff --git a/ZAPD/ZFile.cpp b/ZAPD/ZFile.cpp index 0b2a4d631..db2d251a5 100644 --- a/ZAPD/ZFile.cpp +++ b/ZAPD/ZFile.cpp @@ -120,6 +120,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) if (reader->Attribute("BaseAddress") != nullptr) baseAddress = StringHelper::StrToL(reader->Attribute("BaseAddress"), 16); + if (mode == ZFileMode::Extract && Globals::Instance->baseAddress != -1) + baseAddress = Globals::Instance->baseAddress; + if (reader->Attribute("RangeStart") != nullptr) rangeStart = StringHelper::StrToL(reader->Attribute("RangeStart"), 16); @@ -197,6 +200,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) } rawData = File::ReadAllBytes((basePath / name).string()); + if (mode == ZFileMode::Extract && Globals::Instance->startOffset != -1 && Globals::Instance->endOffset != -1) + rawData = std::vector(rawData.begin() + Globals::Instance->startOffset, + rawData.begin() + Globals::Instance->endOffset); if (reader->Attribute("RangeEnd") == nullptr) rangeEnd = rawData.size(); @@ -585,6 +591,12 @@ Declaration* ZFile::AddDeclarationIncludeArray(offset_t address, std::string& in includePath = "assets/" + StringHelper::Split(includePath, "assets/extracted/")[1]; if (StringHelper::StartsWith(includePath, "assets/custom/")) includePath = "assets/" + StringHelper::Split(includePath, "assets/custom/")[1]; + // Hack for OOT: don't prefix include paths with extracted/VERSION/ + if (StringHelper::StartsWith(includePath, "extracted/")) { + std::vector parts = StringHelper::Split(includePath, "/"); + parts.erase(parts.begin(), parts.begin() + 2); + includePath = StringHelper::Join(parts, "/"); + } Declaration* decl = GetDeclaration(address); if (decl == nullptr) @@ -621,6 +633,12 @@ Declaration* ZFile::AddDeclarationIncludeArray(offset_t address, std::string& in includePath = "assets/" + StringHelper::Split(includePath, "assets/extracted/")[1]; if (StringHelper::StartsWith(includePath, "assets/custom/")) includePath = "assets/" + StringHelper::Split(includePath, "assets/custom/")[1]; + // Hack for OOT: don't prefix include paths with extracted/VERSION/ + if (StringHelper::StartsWith(includePath, "extracted/")) { + std::vector parts = StringHelper::Split(includePath, "/"); + parts.erase(parts.begin(), parts.begin() + 2); + includePath = StringHelper::Join(parts, "/"); + } Declaration* decl = GetDeclaration(address); if (decl == nullptr) diff --git a/ZAPDUtils/Utils/StringHelper.h b/ZAPDUtils/Utils/StringHelper.h index c4e012eb0..942d0bcc9 100644 --- a/ZAPDUtils/Utils/StringHelper.h +++ b/ZAPDUtils/Utils/StringHelper.h @@ -30,6 +30,21 @@ class StringHelper return result; } + static std::string Join(const std::vector parts, const std::string& delimiter) + { + std::string result; + + for (size_t i = 0; i < parts.size(); i++) + { + result += parts[i]; + + if (i != parts.size() - 1) + result += delimiter; + } + + return result; + } + static std::string Strip(std::string s, const std::string& delimiter) { size_t pos = 0;