From 90a178aeb8a95048bc99c4544003a16af8a3ee94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Aug 2026 19:02:00 +0200 Subject: [PATCH] ParamSFO: make GenerateFakeID independent of char signedness The fake disc ID homebrew gets when it has no PARAM.SFO is built from the sum of the bytes of its folder name, summed through a plain char - which is signed on x86 and unsigned on ARM. So the same homebrew folder produced one ID on Windows and a different one on Android, quietly splitting its savestates and per-game config between platforms. Sum through unsigned char, which is what the ARM builds (Android, iOS, Apple Silicon) already did. Uppercasing is now explicit and ASCII-only rather than toupper(). Passing a negative char to toupper() is undefined and trips MSVC's debug CRT assert, so a folder with a non-ASCII name could stop a debug build dead, and what it did with bytes above 0x7F otherwise depended on the locale. ASCII folder names - very nearly all of them - produce exactly the same ID as before. Non-ASCII ones change on the signed-char platforms, to what the unsigned-char ones were already generating. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9 --- Core/ELF/ParamSFO.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index f3586b6b85..2e6a3fe1ad 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -369,14 +369,18 @@ std::string ParamSFOData::GenerateFakeID(const Path &filename) const { std::string file = path.GetFilename(); + // Deliberately byte-wise and ASCII-only. Filenames are UTF-8, and a plain char is signed on x86 + // and unsigned on ARM - so summing chars directly gave Windows and Android different IDs for the + // same non-ASCII folder name, and toupper() on a negative value trips MSVC's debug CRT. ASCII + // names, which is very nearly all of them, produce exactly the same ID as before either way. int sumOfAllLetters = 0; for (char &c : file) { - sumOfAllLetters += c; + sumOfAllLetters += (unsigned char)c; // Get rid of some garbage characters than can arise when opening content URIs. Well, I've only seen '%', but... - if (strchr("%() []", c) != nullptr) { + if (c && strchr("%() []", c) != nullptr) { c = 'X'; - } else { - c = toupper(c); + } else if (c >= 'a' && c <= 'z') { + c = c - 'a' + 'A'; } }