Replace the partial mechanics transcriptions with a separate, readable C11 reconstruction of the complete Win16 image while preserving the original raw Ghidra export as immutable evidence. Cover all ordinary and overlapping entry points, Borland runtime behavior, Win16 imports, segmented data, callbacks, resources, indirect control flow, physics, rendering, persistence, and startup/shutdown lifecycles. Add deterministic extraction and audit tooling plus address-linked ledgers for functions, imports, DGROUP ranges and objects, relocations, resources, and callbacks. The final gate records zero raw, partial, restored, unknown, blocked, or unclassified required units. Keep the semantic-fidelity boundary explicit: the portable C is not claimed to reproduce a byte-identical Borland NE build. Add strict focused harnesses for every reconstructed C unit, exact resource round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source or Cargo metadata is changed in this phase. Test Plan: - `bash original/tools/test_reconstructed_c.sh` -- passed - `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit - `python3 original/tools/audit_reconstruction.py --require-complete` -- passed - `git diff --cached --check` -- passed - `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
170 lines
6.1 KiB
C
170 lines
6.1 KiB
C
#include "../tdkpin_object_windows.h"
|
|
|
|
#include <assert.h>
|
|
|
|
Win16FarPtr g_object_windows_creating_object;
|
|
uint16_t g_object_windows_thunk_code_selector;
|
|
Win16FarPtr g_object_windows_free_thunk;
|
|
Win16FarPtr g_object_windows_dispatch_proc;
|
|
Win16FarPtr g_object_windows_message_hook;
|
|
|
|
static Win16FarPtr g_expected_handler;
|
|
static Win16FarPtr g_expected_object;
|
|
static unsigned g_handler_calls;
|
|
static unsigned g_hook_calls;
|
|
static ObjectWindowsMessage g_hook_message;
|
|
static Win16FarPtr g_event_pointer;
|
|
|
|
void win16_call_object_message_handler(
|
|
Win16FarPtr procedure,
|
|
Win16FarPtr object,
|
|
ObjectWindowsMessage *message)
|
|
{
|
|
assert(procedure == g_expected_handler);
|
|
assert(object == g_expected_object);
|
|
assert(message->window == 0x77);
|
|
assert(message->wparam == 0x3344);
|
|
assert(message->lparam == (LPARAM16)0x89abcdefu);
|
|
message->result = (LRESULT16)0x12345678u;
|
|
g_handler_calls++;
|
|
}
|
|
|
|
void win16_call_object_message_hook(
|
|
Win16FarPtr procedure,
|
|
Win16FarPtr object,
|
|
Win16FarPtr handler,
|
|
HWND16 window,
|
|
UINT16 message,
|
|
WPARAM16 wparam,
|
|
LPARAM16 lparam)
|
|
{
|
|
assert(procedure == g_object_windows_message_hook);
|
|
assert(object == g_expected_object && handler == g_expected_handler);
|
|
g_hook_message = (ObjectWindowsMessage){
|
|
window, message, wparam, lparam, 0};
|
|
g_hook_calls++;
|
|
}
|
|
|
|
void win16_call_object_event_handler(
|
|
Win16FarPtr procedure, Win16FarPtr object, Win16FarPtr event)
|
|
{
|
|
assert(procedure == g_expected_handler);
|
|
assert(object == g_expected_object);
|
|
g_event_pointer = event;
|
|
}
|
|
|
|
static void write_far(uint16_t offset, Win16FarPtr pointer)
|
|
{
|
|
win16_write_u16(
|
|
win16_dgroup_pointer(offset), 0, win16_far_offset(pointer));
|
|
win16_write_u16(
|
|
win16_dgroup_pointer((uint16_t)(offset + 2)),
|
|
0,
|
|
win16_far_selector(pointer));
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
static uint8_t dgroup[0x1000];
|
|
static uint8_t object_bytes[64];
|
|
static uint8_t event_bytes[32];
|
|
win16_reset_segment_bindings();
|
|
win16_bind_segment(0x5000, dgroup, sizeof(dgroup), true);
|
|
win16_set_dgroup_selector(0x5000);
|
|
win16_bind_segment(
|
|
0x7000, object_bytes, sizeof(object_bytes), true);
|
|
win16_bind_segment(
|
|
0x7100, event_bytes, sizeof(event_bytes), true);
|
|
|
|
const uint16_t vmt = 0x0100;
|
|
const uint16_t derived_table = 0x0200;
|
|
const uint16_t parent_table = 0x0300;
|
|
Win16FarPtr fallback = win16_make_far_pointer(0x6100, 0x1111);
|
|
Win16FarPtr derived = win16_make_far_pointer(0x6200, 0x2222);
|
|
Win16FarPtr parent = win16_make_far_pointer(0x6300, 0x3333);
|
|
write_far((uint16_t)(vmt + 0x0c), fallback);
|
|
win16_write_u16(
|
|
win16_dgroup_pointer((uint16_t)(vmt + 4)), 0, derived_table);
|
|
|
|
win16_write_u16(win16_dgroup_pointer(derived_table), 0, parent_table);
|
|
win16_write_u16(win16_dgroup_pointer(derived_table + 2), 0, 0xffff);
|
|
win16_write_u16(win16_dgroup_pointer(derived_table + 4), 0, 0xffff);
|
|
win16_write_u16(win16_dgroup_pointer(derived_table + 6), 0, 1);
|
|
win16_write_u16(win16_dgroup_pointer(derived_table + 8), 0, 0x0100);
|
|
write_far((uint16_t)(derived_table + 10), derived);
|
|
|
|
win16_write_u16(win16_dgroup_pointer(parent_table), 0, 0);
|
|
win16_write_u16(win16_dgroup_pointer(parent_table + 2), 0, 0xffff);
|
|
win16_write_u16(win16_dgroup_pointer(parent_table + 4), 0, 0xffff);
|
|
win16_write_u16(win16_dgroup_pointer(parent_table + 6), 0, 1);
|
|
win16_write_u16(win16_dgroup_pointer(parent_table + 8), 0, 0x0200);
|
|
write_far((uint16_t)(parent_table + 10), parent);
|
|
|
|
assert(object_windows_resolve_message_handler(vmt, 0x0100, 0x0c) ==
|
|
win16_dgroup_pointer(derived_table + 10));
|
|
assert(object_windows_resolve_message_handler(vmt, 0x0200, 0x0c) ==
|
|
win16_dgroup_pointer(parent_table + 10));
|
|
assert(win16_read_u16(win16_dgroup_pointer(derived_table + 2)) ==
|
|
0x0200);
|
|
assert(win16_read_u16(win16_dgroup_pointer(derived_table + 4)) ==
|
|
parent_table + 10);
|
|
/* Cache lookup still works after the table contents become unusable. */
|
|
win16_write_u16(win16_dgroup_pointer(derived_table + 6), 0, 0xffff);
|
|
assert(object_windows_resolve_message_handler(vmt, 0x0200, 0x0c) ==
|
|
win16_dgroup_pointer(parent_table + 10));
|
|
win16_write_u16(win16_dgroup_pointer(derived_table + 6), 0, 1);
|
|
assert(object_windows_resolve_message_handler(vmt, 0x0999, 0x0c) ==
|
|
win16_dgroup_pointer(vmt + 0x0c));
|
|
|
|
Win16FarPtr object = win16_make_far_pointer(0x7000, 4);
|
|
win16_write_u16(object, 0, vmt);
|
|
g_expected_object = object;
|
|
g_object_windows_message_hook =
|
|
win16_make_far_pointer(0x6400, 0x4444);
|
|
g_expected_handler = parent;
|
|
g_handler_calls = 0;
|
|
g_hook_calls = 0;
|
|
LRESULT16 result = object_dispatch_window_or_dialog_proc(
|
|
object,
|
|
0x77,
|
|
0x0200,
|
|
0x3344,
|
|
(LPARAM16)0x89abcdefu);
|
|
assert(result == (LRESULT16)0x12345678u);
|
|
assert(win16_read_u16(win16_far_add_offset(object, 4)) == 0x77);
|
|
assert(g_handler_calls == 1 && g_hook_calls == 1);
|
|
assert(g_hook_message.message == 0x0200);
|
|
assert(g_hook_message.lparam == (LPARAM16)0x89abcdefu);
|
|
|
|
g_object_windows_message_hook = win16_make_far_pointer(0, 0x9999);
|
|
g_expected_handler = fallback;
|
|
g_hook_calls = 0;
|
|
(void)object_dispatch_window_or_dialog_proc(
|
|
object,
|
|
0x77,
|
|
0xffff,
|
|
0x3344,
|
|
(LPARAM16)0x89abcdefu);
|
|
assert(g_hook_calls == 0);
|
|
|
|
Win16FarPtr event = win16_make_far_pointer(0x7100, 2);
|
|
win16_write_u16(event, 0, 0x77);
|
|
win16_write_u16(event, 2, 0x0100);
|
|
win16_write_u16(event, 4, 0x3344);
|
|
win16_write_u16(event, 6, 0xcdef);
|
|
win16_write_u16(event, 8, 0x89ab);
|
|
g_object_windows_message_hook =
|
|
win16_make_far_pointer(0x6400, 0x4444);
|
|
g_expected_handler = derived;
|
|
g_hook_calls = 0;
|
|
g_event_pointer = 0;
|
|
object_windows_dispatch_event(0x0c, 0x0100, event, object);
|
|
assert(g_event_pointer == event);
|
|
assert(g_hook_calls == 1);
|
|
assert(g_hook_message.window == 0x77);
|
|
assert(g_hook_message.message == 0x0100);
|
|
assert(g_hook_message.wparam == 0x3344);
|
|
assert(g_hook_message.lparam == (LPARAM16)0x89abcdefu);
|
|
return 0;
|
|
}
|