From 62a80eab303243f69e8d3994e6b39c1f9b29a8ff Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Sat, 25 Jul 2026 20:49:55 -0700 Subject: [PATCH] fix(mods): fingerprint CUE data track only --- runtime/CMakeLists.txt | 2 + runtime/src/mod_runtime.cpp | 74 +++++++----------------------- runtime/tests/test_mod_runtime.cpp | 12 ++++- 3 files changed, 29 insertions(+), 59 deletions(-) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index bbe2fa23..1f358628 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -125,6 +125,8 @@ if(BUILD_TESTING) tests/test_mod_runtime.cpp src/mod_runtime.cpp src/mod_packages.cpp + src/disc_path.cpp + src/cue_sheet.cpp src/crc32.c src/psx_sha256.c) target_include_directories(mod_runtime_test PRIVATE diff --git a/runtime/src/mod_runtime.cpp b/runtime/src/mod_runtime.cpp index f8cad498..c1e651cd 100644 --- a/runtime/src/mod_runtime.cpp +++ b/runtime/src/mod_runtime.cpp @@ -1,5 +1,6 @@ #include "mod_runtime.h" +#include "disc_path.h" #include "mod_packages.h" #include "psx_sha256.h" @@ -17,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -119,66 +119,24 @@ bool sha256_file(const std::filesystem::path& path, std::string& out, std::string* error) { out.clear(); if (path.empty()) return true; - std::vector inputs{path}; - std::string extension = path.extension().string(); - std::transform(extension.begin(), extension.end(), extension.begin(), - [](unsigned char c) { return (char)std::tolower(c); }); - if (extension == ".cue") { - std::ifstream cue(path); - if (!cue) { - if (error) *error = "cannot fingerprint image: " + path.string(); - return false; - } - inputs.clear(); - std::set seen; - std::string line; - while (std::getline(cue, line)) { - size_t at = line.find_first_not_of(" \t"); - if (at == std::string::npos || line.size() - at < 4) continue; - std::string keyword = line.substr(at, 4); - std::transform(keyword.begin(), keyword.end(), keyword.begin(), - [](unsigned char c) { return (char)std::toupper(c); }); - if (keyword != "FILE") continue; - at += 4; - at = line.find_first_not_of(" \t", at); - if (at == std::string::npos) continue; - std::string name; - if (line[at] == '"') { - const size_t end = line.find('"', at + 1); - if (end == std::string::npos) continue; - name = line.substr(at + 1, end - at - 1); - } else { - const size_t end = line.find_first_of(" \t", at); - name = line.substr(at, end - at); - } - const std::filesystem::path input = - (path.parent_path() / name).lexically_normal(); - if (seen.insert(input).second) inputs.push_back(input); - } - if (inputs.empty()) { - if (error) *error = "CUE has no FILE entries: " + path.string(); - return false; - } - } + const std::filesystem::path input = resolve_disc_path(path).data; psx_sha256_ctx hash; psx_sha256_init(&hash); std::array buffer{}; - for (const std::filesystem::path& input : inputs) { - std::ifstream file(input, std::ios::binary); - if (!file) { - if (error) *error = "cannot fingerprint image: " + input.string(); - return false; - } - while (file) { - file.read((char*)buffer.data(), (std::streamsize)buffer.size()); - const std::streamsize got = file.gcount(); - if (got > 0) psx_sha256_update(&hash, buffer.data(), (size_t)got); - } - if (!file.eof()) { - if (error) *error = - "cannot finish fingerprinting image: " + input.string(); - return false; - } + std::ifstream file(input, std::ios::binary); + if (!file) { + if (error) *error = "cannot fingerprint image: " + input.string(); + return false; + } + while (file) { + file.read((char*)buffer.data(), (std::streamsize)buffer.size()); + const std::streamsize got = file.gcount(); + if (got > 0) psx_sha256_update(&hash, buffer.data(), (size_t)got); + } + if (!file.eof()) { + if (error) *error = + "cannot finish fingerprinting image: " + input.string(); + return false; } uint8_t digest[32]; psx_sha256_final(&hash, digest); diff --git a/runtime/tests/test_mod_runtime.cpp b/runtime/tests/test_mod_runtime.cpp index daaa2938..caa39199 100644 --- a/runtime/tests/test_mod_runtime.cpp +++ b/runtime/tests/test_mod_runtime.cpp @@ -65,6 +65,15 @@ int main() { overlay[i] = (uint8_t)(i * 17u + 3u); const fs::path stock_path = root / "stock.bin"; write_bytes(stock_path, stock); + write_bytes(root / "audio.bin", std::vector(2 * 2352, 0x5a)); + const fs::path cue_path = root / "stock.cue"; + write_text(cue_path, + "FILE \"stock.bin\" BINARY\n" + " TRACK 01 MODE2/2352\n" + " INDEX 01 00:00:00\n" + "FILE \"audio.bin\" BINARY\n" + " TRACK 02 AUDIO\n" + " INDEX 01 00:00:00\n"); write_bytes(root / "packages/runtime.test/1.0.0/assets/overlay.bin", overlay); write_text(root / "packages/runtime.test/1.0.0/manifest.toml", @@ -168,7 +177,8 @@ int main() { check(PSXRecompV4::mod_runtime_initialize( root, "SLUS-RUNTIME", 0x80002000, {}, &error), error.c_str()); - check(PSXRecompV4::mod_runtime_commit(stock_path, &error), error.c_str()); + check(PSXRecompV4::mod_runtime_commit(cue_path, &error), + "CUE and its data-track BIN must have the same mod target identity"); ram[0x1000] = 1; ram[0x1001] = 2; ram[0x1002] = 3; ram[0x1003] = 4; ram[0x1100] = 0; ram[0x1101] = 0;