diff options
| author | kraibse <33869366+kraibse@users.noreply.github.com> | 2026-11-02 17:23:47 +0100 |
|---|---|---|
| committer | kraibse <33869366+kraibse@users.noreply.github.com> | 2026-11-02 17:23:47 +0100 |
| commit | 8185d45d5d9d16bca860542f98d8a026e286dbf6 (patch) | |
| tree | 124af4061f67e71796518e5355425919968bf80a | |
| parent | 4267169006fc4ed43f6d810e08426fb8058de9c0 (diff) | |
loader: read the display version from GameDataList.Product.NNN too
Donkey Kong Bananza names its resource size table without a version, so
no version was found for a loose dump. Its GameData/GameDataList.Product
.320.* files carry it (3.2.0), so read them as well and use the newest
tag from either source.
Assisted-by: Claude Sonnet 5.5 (wrote the GameDataList version lookup and its test)
| -rw-r--r-- | src/core/loader/deconstructed_rom_directory.cpp | 47 | ||||
| -rw-r--r-- | src/tests/core/nup_writer.cpp | 22 |
2 files changed, 52 insertions, 17 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 60cf87db14..4b1168a59b 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -117,27 +117,19 @@ FileSys::VirtualFile FindLooseRomFS(const FileSys::VirtualDir& exefs_dir) { return nullptr; } -// The display version of a dump without control data, from its RomFS: Nintendo EPD titles name -// their resource size tables after it (System/Resource/ResourceSizeTable.Product.180.* in Mario -// Kart World 1.8.0). A hotfix can keep its minor version's tables (Product.110 in a 1.1.1). -std::string RomFSProductVersion(const FileSys::VirtualDir& romfs_dir) { - if (romfs_dir == nullptr) { - return {}; - } - const auto system_dir = romfs_dir->GetSubdirectory("System"); - const auto resource_dir = system_dir != nullptr ? system_dir->GetSubdirectory("Resource") : nullptr; - if (resource_dir == nullptr) { - return {}; - } - constexpr std::string_view Prefix = "ResourceSizeTable.Product."; +// The newest three-digit tag in a directory's file names of the form <prefix>NNN.<anything>. +std::string NewestProductTag(const FileSys::VirtualDir& dir, std::string_view prefix) { std::string best; - for (const auto& file : resource_dir->GetFiles()) { + if (dir == nullptr) { + return best; + } + for (const auto& file : dir->GetFiles()) { const std::string file_name = file->GetName(); - if (!file_name.starts_with(Prefix) || file_name.size() < Prefix.size() + 4) { + if (!file_name.starts_with(prefix) || file_name.size() < prefix.size() + 4) { continue; } - const std::string_view digits = std::string_view{file_name}.substr(Prefix.size(), 3); - if (file_name[Prefix.size() + 3] != '.' || + const std::string_view digits = std::string_view{file_name}.substr(prefix.size(), 3); + if (file_name[prefix.size() + 3] != '.' || !std::all_of(digits.begin(), digits.end(), [](char c) { return c >= '0' && c <= '9'; })) { continue; } @@ -145,6 +137,27 @@ std::string RomFSProductVersion(const FileSys::VirtualDir& romfs_dir) { best = version; } } + return best; +} + +// The display version of a dump without control data, from its RomFS: Nintendo EPD titles name +// their resource size tables after it (System/Resource/ResourceSizeTable.Product.180.* in Mario +// Kart World 1.8.0), and some name their game data list instead (GameData/GameDataList.Product.320.* +// in Donkey Kong Bananza 3.2.0). A hotfix can keep its minor version's tables (Product.110 in a +// 1.1.1). +std::string RomFSProductVersion(const FileSys::VirtualDir& romfs_dir) { + if (romfs_dir == nullptr) { + return {}; + } + const auto system_dir = romfs_dir->GetSubdirectory("System"); + std::string best = NewestProductTag( + system_dir != nullptr ? system_dir->GetSubdirectory("Resource") : nullptr, + "ResourceSizeTable.Product."); + if (const auto game_data = NewestProductTag(romfs_dir->GetSubdirectory("GameData"), + "GameDataList.Product."); + game_data > best) { + best = game_data; + } if (best.empty()) { return {}; } diff --git a/src/tests/core/nup_writer.cpp b/src/tests/core/nup_writer.cpp index bb0148139b..c0230d8694 100644 --- a/src/tests/core/nup_writer.cpp +++ b/src/tests/core/nup_writer.cpp @@ -421,3 +421,25 @@ TEST_CASE("NUP writes metadata overrides to the base and the newest update", "[n REQUIRE(packages[2].display_version == "9.8.7"); REQUIRE(packages[1].display_version == "1.1.0"); } + +TEST_CASE("NUP probes the version from the game data list tag", "[nup]") { + TempDir t; + const auto root = t.path / "Game"; + Put(root / "base/exefs/main", "main"); + Put(root / "base/exefs/main.npdm", Npdm(TitleId)); + Put(root / "base/romfs/GameData/GameDataList.Product.100.byml.zs", "x"); + Put(root / "base/romfs/System/Resource/ResourceSizeTable.Product.rsizetable.zs", "x"); + Put(root / "updates/458752/exefs/main", "main"); + Put(root / "updates/458752/exefs/main.npdm", Npdm(TitleId)); + Put(root / "updates/458752/romfs/GameData/GameDataList.Product.320.byml.zs", "x"); + Put(root / "updates/458752/romfs/GameData/GameDataList.Product.320.revision.txt", "1"); + + auto probed = FileSys::Nup::ProbeMetadata(root); + REQUIRE(probed.display_version == "3.2.0"); + REQUIRE(probed.version_source == "update 458752"); + + fs::remove_all(root / "updates"); + probed = FileSys::Nup::ProbeMetadata(root); + REQUIRE(probed.display_version == "1.0.0"); + REQUIRE(probed.version_source == "base"); +} |
