port: ProcessCRC verbatim (module introspection adapted) + XTrap mapped

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-30 13:10:54 +09:00
co-authored by Claude Opus 5.5
parent 6d2d262de8
commit 80c5a1e39f
6 changed files with 246 additions and 11 deletions
+2
View File
@@ -617,3 +617,5 @@
{"date": "2026-09-30", "unit": "EterLib/TextBar.cpp", "action": "all PORTED verbatim; GetTextExtentPoint32A added to the GDI shim", "evidence": "port.text_bar"}
{"date": "2026-09-30", "unit": "EterLib/DibBar.cpp", "action": "all PORTED verbatim", "evidence": "port.text_bar"}
{"date": "2026-09-30", "unit": "EterLib/BlockTexture.cpp", "action": "Render ADAPTED (UI image of the CPU texture), rest PORTED verbatim", "evidence": "port.text_bar"}
{"date": "2026-09-30", "unit": "UserInterface/ProcessCRC.cpp", "action": "port", "evidence": "verbatim; process introspection ADAPTED (no module snapshot -> ProcCRC 0); port.process_crc"}
{"date": "2026-09-30", "unit": "UserInterface/WiseLogicXTrap.cpp", "action": "port", "evidence": "verbatim non-XTRAP build; mapped PORTED"}
@@ -0,0 +1,65 @@
{
"reference": "UserInterface/ProcessCRC.cpp",
"reference_sha256": "5d7e9065b473da7dbf043c5251087114064d8f9a3b0d77108f5a4d71ca15e41c",
"priority": "P4",
"contracts": [],
"functions": {
"stristr": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/ProcessCRC.cpp:stristr"
],
"test": [
"tests/port/port_process_crc_test.cpp"
]
},
"GetProcessInformation": {
"status": "ADAPTED",
"impl": [
"src/platform/UserInterface/ProcessCRC.cpp:GetProcessInformation"
],
"test": [
"tests/port/port_process_crc_test.cpp"
],
"note": "40250: Toolhelp32 module snapshot, returns the path/base of the module whose path contains the exe name, false if none. Port: no module snapshot on the platform, always false. Invariant: __GetExeCRC then takes the not-found path (ProcCRC = 0)."
},
"GetProcessMemoryCRC": {
"status": "ADAPTED",
"impl": [
"src/platform/UserInterface/ProcessCRC.cpp:GetProcessMemoryCRC"
],
"test": [
"tests/port/port_process_crc_test.cpp"
],
"note": "40250: CRC32 of the first 1 MB of the module image via ReadProcessMemory, 0 on failure. Port: returns 0 (no ReadProcessMemory); unreachable since GetProcessInformation is always false. Invariant: ProcCRC bytes of the magic cube are 0."
},
"__GetExeCRC": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/ProcessCRC.cpp:__GetExeCRC"
],
"test": [
"tests/port/port_process_crc_test.cpp"
],
"note": "FileCRC = GetFileCRC32(GetExcutedFileName), whose PORT returns the working folder"
},
"BuildProcessCRC": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/ProcessCRC.cpp:BuildProcessCRC"
],
"test": [
"tests/port/port_process_crc_test.cpp"
]
},
"GetProcessCRCMagicCubePiece": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/ProcessCRC.cpp:GetProcessCRCMagicCubePiece"
],
"test": [
"tests/port/port_process_crc_test.cpp"
]
}
}
}
@@ -0,0 +1,43 @@
{
"reference": "UserInterface/WiseLogicXTrap.cpp",
"reference_sha256": "429871b63fecbc1c89f2d5522fa13637103602af72c54a0b24b74cdf36a4c8ab",
"priority": "P4",
"contracts": [],
"functions": {
"XTrap_Init": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/WiseLogicXTrap.cpp:XTrap_Init"
],
"note": "the #else (no XTRAP_CLIENT_ENABLE) build: the shipped Locale_inc.h (LOCALE_SERVICE_SINGAPORE) does not define it"
},
"XTrap_CheckInit": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/WiseLogicXTrap.cpp:XTrap_CheckInit"
],
"note": "the #else (no XTRAP_CLIENT_ENABLE) build: the shipped Locale_inc.h (LOCALE_SERVICE_SINGAPORE) does not define it"
},
"XTrap_PollEvent": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/WiseLogicXTrap.cpp:XTrap_PollEvent"
],
"note": "the #else (no XTRAP_CLIENT_ENABLE) build: the shipped Locale_inc.h (LOCALE_SERVICE_SINGAPORE) does not define it"
},
"XTrap_ValidateCheckStream": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/WiseLogicXTrap.cpp:XTrap_ValidateCheckStream"
],
"note": "the #else (no XTRAP_CLIENT_ENABLE) build: the shipped Locale_inc.h (LOCALE_SERVICE_SINGAPORE) does not define it"
},
"XTrap_SetUserInfo": {
"status": "PORTED",
"impl": [
"src/platform/UserInterface/WiseLogicXTrap.cpp:XTrap_SetUserInfo"
],
"note": "the #else (no XTRAP_CLIENT_ENABLE) build: the shipped Locale_inc.h (LOCALE_SERVICE_SINGAPORE) does not define it"
}
}
}
+75 -11
View File
@@ -1,23 +1,87 @@
// Platform skeleton for UserInterface/ProcessCRC.h (40250 UserInterface/ProcessCRC.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 UserInterface/ProcessCRC.cpp, verbatim except the Win32 process introspection (see PORT below).
// GetExeCRC is declared in ProcessCRC.h but only __GetExeCRC is defined in 40250.
#include "UserInterface/StdAfx.h"
#include "UserInterface/ProcessCRC.h"
#include "../PlatformStub.h"
static BYTE abCRCMagicCube[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static BYTE abCRCXorTable[8] = { 102, 30, 188, 44, 39, 201, 43, 5 };
static BYTE bMagicCubeIdx = 0;
auto GetExeCRC(DWORD &, DWORD &) -> bool
const char * stristr(const char * big, const char * little)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
const char * t = big;
size_t len = strlen(little) - 1;
for (t = big; *t; ++t)
if (!_strnicmp(t, little, len))
return t;
return NULL;
}
auto BuildProcessCRC() -> void
// PORT: 40250 walks a Toolhelp32 module snapshot for the module whose path contains the executable name and
// returns its path and load address. The platform has no module snapshot, so the executable is never found:
// the path in which 40250 gives up the same way (then ProcCRC = 0).
bool GetProcessInformation(std::string & exeFileName, LPCVOID * ppvAddress)
{
MT_PLATFORM_STUB();
return false;
}
auto GetProcessCRCMagicCubePiece() -> BYTE
// PORT: 40250 ReadProcessMemory's the first 1 MB of the module image and CRCs it (a partial copy counts).
// Unreachable here (GetProcessInformation never finds the module); returns 0 as 40250 does on a failed read.
DWORD GetProcessMemoryCRC(LPCVOID c_pvBaseAddress)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<BYTE>();
return 0;
}
bool __GetExeCRC(DWORD & r_dwProcCRC, DWORD & r_dwFileCRC)
{
std::string exeFileName;
LPCVOID c_pvBaseAddress;
GetExcutedFileName(exeFileName);
if (GetProcessInformation(exeFileName, &c_pvBaseAddress))
r_dwProcCRC = GetProcessMemoryCRC(c_pvBaseAddress);
else
r_dwProcCRC = 0;
r_dwFileCRC = GetFileCRC32(exeFileName.c_str());
return true;
}
void BuildProcessCRC()
{
if (LocaleService_IsHONGKONG() || LocaleService_IsTAIWAN())
{
memset(abCRCMagicCube, 0, sizeof(abCRCMagicCube));
bMagicCubeIdx = 0;
return;
}
DWORD dwProcCRC, dwFileCRC;
if (__GetExeCRC(dwProcCRC, dwFileCRC))
{
abCRCMagicCube[0] = BYTE(dwProcCRC & 0x000000ff);
abCRCMagicCube[1] = BYTE(dwFileCRC & 0x000000ff);
abCRCMagicCube[2] = BYTE( (dwProcCRC & 0x0000ff00) >> 8 );
abCRCMagicCube[3] = BYTE( (dwFileCRC & 0x0000ff00) >> 8 );
abCRCMagicCube[4] = BYTE( (dwProcCRC & 0x00ff0000) >> 16 );
abCRCMagicCube[5] = BYTE( (dwFileCRC & 0x00ff0000) >> 16 );
abCRCMagicCube[6] = BYTE( (dwProcCRC & 0xff000000) >> 24 );
abCRCMagicCube[7] = BYTE( (dwFileCRC & 0xff000000) >> 24 );
bMagicCubeIdx = 0;
}
}
BYTE GetProcessCRCMagicCubePiece()
{
BYTE bPiece = BYTE(abCRCMagicCube[bMagicCubeIdx] ^ abCRCXorTable[bMagicCubeIdx]);
if (!(++bMagicCubeIdx & 7))
bMagicCubeIdx = 0;
return bPiece;
}
+4
View File
@@ -199,6 +199,10 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
add_test(NAME port.text_bar COMMAND $<TARGET_FILE:port_text_bar_test>)
set_tests_properties(port.text_bar PROPERTIES SKIP_RETURN_CODE 77)
add_executable(port_process_crc_test ${PROJECT_SOURCE_DIR}/tests/port/port_process_crc_test.cpp)
target_link_libraries(port_process_crc_test PRIVATE port_platform)
add_test(NAME port.process_crc COMMAND $<TARGET_FILE:port_process_crc_test>)
# MilesLib: the 40250 sound managers over the Miles emulation (platform/MilesLib/MilesAil.cpp).
add_executable(port_miles_test ${PROJECT_SOURCE_DIR}/tests/port/port_miles_test.cpp)
target_link_libraries(port_miles_test PRIVATE port_platform)
+57
View File
@@ -0,0 +1,57 @@
#include "UserInterface/StdAfx.h"
#include "UserInterface/ProcessCRC.h"
#include <cstdio>
#include <cstring>
#include <string>
const char * stristr(const char * big, const char * little);
bool GetProcessInformation(std::string & exeFileName, LPCVOID * ppvAddress);
bool __GetExeCRC(DWORD & r_dwProcCRC, DWORD & r_dwFileCRC);
int main()
{
int failures = 0;
auto check = [&failures](bool ok, const char *name) {
if (!ok) {
std::fprintf(stderr, "FAIL %s\n", name);
++failures;
}
};
static const BYTE xorTable[8] = { 102, 30, 188, 44, 39, 201, 43, 5 };
// stristr (40250): case-insensitive, and it compares one character less than the needle's length.
const char * hay = "C:\\Game\\METIN2.BIN";
check(stristr(hay, "metin2.bin") == hay + 8, "stristr case fold");
check(stristr(hay, "metin2.biX") == hay + 8, "stristr ignores the last needle character");
check(stristr(hay, "client.exe") == NULL, "stristr miss");
// Before BuildProcessCRC the cube is zero: the pieces are the XOR table, index cycling & 7.
bool pristine = true;
for (int i = 0; i < 16; ++i)
pristine &= GetProcessCRCMagicCubePiece() == xorTable[i & 7];
check(pristine, "pieces before BuildProcessCRC");
// ADAPTED: no module snapshot -> ProcCRC 0; FileCRC is the CRC32 of GetExcutedFileName, as in 40250.
std::string exe;
LPCVOID base = NULL;
check(!GetProcessInformation(exe, &base), "GetProcessInformation finds no module");
DWORD proc = 1, file = 0;
check(__GetExeCRC(proc, file) && proc == 0, "__GetExeCRC proc 0");
GetExcutedFileName(exe);
check(file == GetFileCRC32(exe.c_str()), "__GetExeCRC file CRC");
// BuildProcessCRC interleaves proc/file bytes low to high and restarts the index.
GetProcessCRCMagicCubePiece();
BuildProcessCRC();
BYTE expect[8];
for (int i = 0; i < 4; ++i) {
expect[2 * i] = BYTE(proc >> (8 * i));
expect[2 * i + 1] = BYTE(file >> (8 * i));
}
bool built = true;
for (int i = 0; i < 8; ++i)
built &= GetProcessCRCMagicCubePiece() == BYTE(expect[i] ^ xorTable[i]);
check(built, "pieces after BuildProcessCRC");
return failures ? 1 : 0;
}