port: ProcessCRC verbatim (module introspection adapted) + XTrap mapped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6d2d262de8
commit
80c5a1e39f
@@ -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/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/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": "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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,87 @@
|
|||||||
// Platform skeleton for UserInterface/ProcessCRC.h (40250 UserInterface/ProcessCRC.cpp), generated by platform_stub.py.
|
// 40250 UserInterface/ProcessCRC.cpp, verbatim except the Win32 process introspection (see PORT below).
|
||||||
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
|
// GetExeCRC is declared in ProcessCRC.h but only __GetExeCRC is defined in 40250.
|
||||||
#include "UserInterface/StdAfx.h"
|
#include "UserInterface/StdAfx.h"
|
||||||
#include "UserInterface/ProcessCRC.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();
|
const char * t = big;
|
||||||
return mt_platform_stub_return<bool>();
|
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 0;
|
||||||
return mt_platform_stub_return<BYTE>();
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>)
|
add_test(NAME port.text_bar COMMAND $<TARGET_FILE:port_text_bar_test>)
|
||||||
set_tests_properties(port.text_bar PROPERTIES SKIP_RETURN_CODE 77)
|
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).
|
# 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)
|
add_executable(port_miles_test ${PROJECT_SOURCE_DIR}/tests/port/port_miles_test.cpp)
|
||||||
target_link_libraries(port_miles_test PRIVATE port_platform)
|
target_link_libraries(port_miles_test PRIVATE port_platform)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user