Files
tdkpin/original/reconstructed/tests/test_sound.c
T
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
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
2026-08-23 16:41:17 +02:00

452 lines
14 KiB
C

#include "../tdkpin_sound.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
enum {
DGROUP_SOUND_LENGTHS = 0x03ea,
DGROUP_INI_SUFFIX = 0x0442,
DGROUP_INI_SECTION = 0x0446,
DGROUP_INI_KEY = 0x044f,
DGROUP_WAVE_TYPE = 0x0455,
DGROUP_GAME_TILTED = 0x07c6,
DGROUP_WAVE_CAPS = 0x43be,
DGROUP_DEVICE_COUNT = 0x43ee,
DGROUP_DEVICE_ID = 0x43f0,
DGROUP_SOUND_BASE = 0x43f2,
DGROUP_SOUND_ENABLED = 0x43f2,
DGROUP_SOUND_PLAYING = 0x43f3,
DGROUP_VOLUME_STEP = 0x43f4,
CODE2_DOT = 0x0f2c,
SOUND_COUNT = 22,
};
static uint8_t g_dgroup[0x5000];
static uint8_t g_code2[0x1000];
HINSTANCE16 g_win16_instance;
Win16FarPtr g_borland_command_line;
static UINT16 g_profile_value;
static unsigned g_profile_calls;
static UINT16 g_wave_device_count;
static UINT16 g_wave_caps_result;
static uint32_t g_wave_support;
static uint32_t g_wave_volume;
static unsigned g_wave_count_calls;
static unsigned g_wave_caps_calls;
static unsigned g_wave_volume_calls;
static uint16_t g_current_sound;
static unsigned g_resource_stage;
static uint16_t g_loaded_sounds[SOUND_COUNT];
static unsigned g_loaded_count;
static unsigned g_stop_calls;
static Win16FarPtr g_played_sound;
static UINT16 g_play_flags;
static BOOL16 g_play_result;
static Win16FarPtr g_freed_sounds[SOUND_COUNT];
static unsigned g_free_count;
static Win16FarPtr dgroup_at(uint16_t offset)
{
return win16_make_far_pointer(0x5000, offset);
}
static bool far_string_equals(Win16FarPtr string, const char *expected)
{
size_t index = 0;
do {
if (win16_read_u8(win16_far_add_offset(string, (uint16_t)index)) !=
(uint8_t)expected[index]) {
return false;
}
} while (expected[index++] != '\0');
return true;
}
static uint16_t sound_index_offset(uint16_t sound_number)
{
return (uint16_t)(sound_number << 2);
}
static Win16FarPtr sound_buffer(uint16_t sound_number)
{
return win16_read_far_pointer(
dgroup_at(DGROUP_SOUND_BASE), sound_index_offset(sound_number));
}
static void set_sound_buffer(uint16_t sound_number, Win16FarPtr value)
{
win16_write_u32(
dgroup_at(DGROUP_SOUND_BASE), sound_index_offset(sound_number), value);
}
static void initialize_image_data(void)
{
memset(g_dgroup, 0, sizeof(g_dgroup));
memset(g_code2, 0, sizeof(g_code2));
memcpy(&g_dgroup[DGROUP_INI_SUFFIX], "INI", 4);
memcpy(&g_dgroup[DGROUP_INI_SECTION], "Settings", 9);
memcpy(&g_dgroup[DGROUP_INI_KEY], "Sound", 6);
memcpy(&g_dgroup[DGROUP_WAVE_TYPE], "WAV", 4);
g_code2[CODE2_DOT] = 1;
g_code2[CODE2_DOT + 1] = '.';
/* 03e6 belongs to the preceding object but is read for sound number zero. */
win16_write_u32(dgroup_at(0x03e6), 0, 0x00007070);
for (uint16_t index = 0; index < SOUND_COUNT; index++) {
win16_write_u32(
dgroup_at(DGROUP_SOUND_LENGTHS),
(uint16_t)(index * 4),
g_sound_resource_byte_counts[index]);
}
}
static void reset_calls(void)
{
g_profile_calls = 0;
g_wave_count_calls = 0;
g_wave_caps_calls = 0;
g_wave_volume_calls = 0;
g_current_sound = 0;
g_resource_stage = 0;
g_loaded_count = 0;
g_stop_calls = 0;
g_played_sound = 0;
g_play_flags = 0;
g_free_count = 0;
}
static void reset_sound_state(void)
{
memset(&g_dgroup[DGROUP_WAVE_CAPS], 0, 0x90);
reset_calls();
}
UINT16 GetModuleFileNameFar16(
HINSTANCE16 module, Win16FarPtr buffer, UINT16 size)
{
static const char module_name[] = "C:\\GAMES\\TDKPIN.EXE";
assert(module == g_win16_instance && size == 0xff);
size_t length = strlen(module_name);
for (size_t index = 0; index < length; index++) {
win16_write_u8(
win16_far_add_offset(buffer, (uint16_t)index),
(uint8_t)module_name[index]);
}
win16_write_u8(win16_far_add_offset(buffer, (uint16_t)length), 0);
return (UINT16)length;
}
UINT16 GetPrivateProfileInt16(
Win16FarPtr section,
Win16FarPtr key,
INT16 default_value,
Win16FarPtr file_name)
{
assert(section == dgroup_at(DGROUP_INI_SECTION));
assert(key == dgroup_at(DGROUP_INI_KEY));
assert(default_value == 1);
assert(far_string_equals(file_name, "C:\\GAMES\\TDKPIN.INI"));
g_profile_calls++;
return g_profile_value;
}
UINT16 WaveOutGetNumDevs16(void)
{
g_wave_count_calls++;
return g_wave_device_count;
}
UINT16 WaveOutGetDevCaps16(
UINT16 device_id, Win16FarPtr capabilities, UINT16 byte_count)
{
assert(device_id == win16_read_u16(dgroup_at(DGROUP_DEVICE_ID)));
assert(capabilities == dgroup_at(DGROUP_WAVE_CAPS));
assert(byte_count == 48);
win16_write_u32(capabilities, 44, g_wave_support);
g_wave_caps_calls++;
return g_wave_caps_result;
}
UINT16 WaveOutGetVolume16(UINT16 device_id, Win16FarPtr volume)
{
assert(device_id == win16_read_u16(dgroup_at(DGROUP_DEVICE_ID)));
win16_write_u32(volume, 0, g_wave_volume);
g_wave_volume_calls++;
return 0;
}
HRSRC16 FindResource16(
HINSTANCE16 instance, Win16FarPtr name, Win16FarPtr type)
{
assert(g_resource_stage == 0 && instance == g_win16_instance);
assert(win16_far_selector(name) == 0);
assert(type == dgroup_at(DGROUP_WAVE_TYPE));
g_current_sound = (uint16_t)(win16_far_offset(name) - 2000);
assert(g_current_sound >= 1 && g_current_sound <= SOUND_COUNT);
assert(g_sound_resource_byte_counts[g_current_sound - 1] != 0);
g_resource_stage = 1;
return (HRSRC16)(0x1000 + g_current_sound);
}
HGLOBAL16 LoadResource16(HINSTANCE16 instance, HRSRC16 resource)
{
assert(g_resource_stage == 1 && instance == g_win16_instance);
assert(resource == (HRSRC16)(0x1000 + g_current_sound));
g_resource_stage = 2;
return (HGLOBAL16)(0x2000 + g_current_sound);
}
Win16FarPtr tdkpin_global_allocate_locked(UINT16 flags, uint32_t bytes)
{
assert(g_resource_stage == 2 && flags == 0x42);
assert(bytes == g_sound_resource_byte_counts[g_current_sound - 1]);
g_resource_stage = 3;
return win16_make_far_pointer(
(uint16_t)(0x7000 + g_current_sound), 0x0100);
}
Win16FarPtr LockResource16(HGLOBAL16 resource)
{
assert(g_resource_stage == 3);
assert(resource == (HGLOBAL16)(0x2000 + g_current_sound));
g_resource_stage = 4;
return win16_make_far_pointer(
(uint16_t)(0x6000 + g_current_sound), 0x0200);
}
void borland_move_bytes(
Win16FarPtr destination, Win16FarPtr source, uint16_t count)
{
assert(g_resource_stage == 4);
assert(destination == sound_buffer(g_current_sound));
assert(destination == win16_make_far_pointer(
(uint16_t)(0x7000 + g_current_sound), 0x0100));
assert(source == win16_make_far_pointer(
(uint16_t)(0x6000 + g_current_sound), 0x0200));
assert(count == g_sound_resource_byte_counts[g_current_sound - 1]);
g_resource_stage = 5;
}
BOOL16 GlobalUnlock16(HGLOBAL16 resource)
{
assert(g_resource_stage == 5);
assert(resource == (HGLOBAL16)(0x2000 + g_current_sound));
g_resource_stage = 6;
return 1;
}
BOOL16 FreeResource16(HGLOBAL16 resource)
{
assert(g_resource_stage == 6);
assert(resource == (HGLOBAL16)(0x2000 + g_current_sound));
g_loaded_sounds[g_loaded_count++] = g_current_sound;
g_resource_stage = 0;
return 1;
}
BOOL16 SndPlaySound16(Win16FarPtr sound, UINT16 flags)
{
if (sound == 0) {
assert(flags == 0);
g_stop_calls++;
return 1;
}
g_played_sound = sound;
g_play_flags = flags;
return g_play_result;
}
void tdkpin_global_unlock_and_free(Win16FarPtr block)
{
assert(g_free_count < SOUND_COUNT);
g_freed_sounds[g_free_count++] = block;
}
static void test_initializer_disabled_and_probe_failures(void)
{
reset_sound_state();
win16_write_u8(dgroup_at(DGROUP_SOUND_ENABLED), 0xaa);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 0xbb);
win16_write_u8(dgroup_at(DGROUP_VOLUME_STEP), 0x55);
win16_write_u16(dgroup_at(DGROUP_DEVICE_COUNT), 0, 0xcccc);
g_profile_value = 0;
tdkpin_initialize_sounds();
assert(g_profile_calls == 1 && g_wave_count_calls == 0);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_ENABLED)) == 0);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_PLAYING)) == 0);
assert(win16_read_u16(dgroup_at(DGROUP_DEVICE_COUNT)) == 0);
assert(win16_read_u8(dgroup_at(DGROUP_VOLUME_STEP)) == 0x55);
reset_sound_state();
g_profile_value = 1;
g_wave_device_count = 0;
tdkpin_initialize_sounds();
assert(g_wave_count_calls == 1 && g_wave_caps_calls == 0);
assert(win16_read_u16(dgroup_at(DGROUP_DEVICE_COUNT)) == 0);
reset_sound_state();
g_wave_device_count = 2;
g_wave_caps_result = 1;
tdkpin_initialize_sounds();
assert(g_wave_caps_calls == 1 && g_loaded_count == 0);
assert(win16_read_u16(dgroup_at(DGROUP_DEVICE_COUNT)) == 0);
}
static void prime_sound_buffers(void)
{
for (uint16_t sound = 1; sound <= SOUND_COUNT; sound++) {
set_sound_buffer(
sound, win16_make_far_pointer(0x5555, sound));
}
}
static void assert_loaded_resource_set(void)
{
unsigned loaded = 0;
for (uint16_t sound = 1; sound <= SOUND_COUNT; sound++) {
uint32_t bytes = g_sound_resource_byte_counts[sound - 1];
if (bytes == 0) {
assert(sound_buffer(sound) ==
win16_make_far_pointer(0x5555, sound));
continue;
}
assert(g_loaded_sounds[loaded++] == sound);
assert(sound_buffer(sound) == win16_make_far_pointer(
(uint16_t)(0x7000 + sound), 0x0100));
}
assert(loaded == 16 && g_loaded_count == loaded && g_resource_stage == 0);
}
static void test_initializer_success(void)
{
reset_sound_state();
prime_sound_buffers();
g_profile_value = 1;
g_wave_device_count = 2;
g_wave_caps_result = 0;
g_wave_support = 0;
tdkpin_initialize_sounds();
assert(win16_read_u16(dgroup_at(DGROUP_DEVICE_COUNT)) == 2);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_ENABLED)) == 1);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_PLAYING)) == 0);
assert(win16_read_u8(dgroup_at(DGROUP_VOLUME_STEP)) == 0xff);
assert(g_wave_volume_calls == 0);
assert_loaded_resource_set();
reset_sound_state();
prime_sound_buffers();
g_wave_support = 4;
g_wave_volume = 0x1234abcd;
tdkpin_initialize_sounds();
assert(g_wave_volume_calls == 1);
assert(win16_read_u8(dgroup_at(DGROUP_VOLUME_STEP)) == 170);
assert_loaded_resource_set();
}
static void test_stop_unload_and_play(void)
{
win16_set_indeterminate_u16(0xbeef);
reset_calls();
win16_write_u16(dgroup_at(DGROUP_DEVICE_COUNT), 0, 0);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 1);
assert(tdkpin_stop_sound_if_active() == 0xbeef);
assert(g_stop_calls == 0);
win16_write_u16(dgroup_at(DGROUP_DEVICE_COUNT), 0, 1);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 0);
assert(tdkpin_stop_sound_if_active() == 0xbeef);
assert(g_stop_calls == 0);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 1);
assert(tdkpin_stop_sound_if_active() == 0xbeef);
assert(g_stop_calls == 1);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_PLAYING)) == 1);
reset_calls();
for (uint16_t sound = 1; sound <= SOUND_COUNT; sound++) {
set_sound_buffer(sound, win16_make_far_pointer(0x7100, sound));
}
tdkpin_unload_sounds();
assert(g_stop_calls == 1 && g_free_count == SOUND_COUNT);
for (uint16_t index = 0; index < SOUND_COUNT; index++) {
assert(g_freed_sounds[index] ==
win16_make_far_pointer(0x7100, (uint16_t)(index + 1)));
}
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_PLAYING)) == 0);
reset_calls();
win16_write_u16(dgroup_at(DGROUP_DEVICE_COUNT), 0, 0);
tdkpin_unload_sounds();
assert(g_free_count == 0);
reset_calls();
win16_write_u16(dgroup_at(DGROUP_DEVICE_COUNT), 0, 1);
win16_write_u8(dgroup_at(DGROUP_SOUND_ENABLED), 1);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 1);
set_sound_buffer(4, win16_make_far_pointer(0x7200, 0x4444));
g_play_result = 1;
assert(tdkpin_play_sound(4) == 0xbeef);
assert(g_stop_calls == 1);
assert(g_played_sound == win16_make_far_pointer(0x7200, 0x4444));
assert(g_play_flags == 5);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_PLAYING)) == 1);
g_play_result = 0;
assert(tdkpin_play_sound(4) == 0xbeef);
assert(win16_read_u8(dgroup_at(DGROUP_SOUND_PLAYING)) == 0);
g_played_sound = 0;
(void)tdkpin_play_sound(3); /* Absent resource: exact size-table gate. */
assert(g_played_sound == 0);
/* The binary does not range-check: number zero reads the preceding dword. */
win16_write_u8(dgroup_at(DGROUP_SOUND_ENABLED), 1);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 0);
win16_write_u8(dgroup_at(DGROUP_VOLUME_STEP), 0xaa);
g_play_result = 1;
(void)tdkpin_play_sound(0);
assert(g_played_sound == win16_make_far_pointer(0x00aa, 0x0001));
}
static void test_gameplay_sound_dispatcher(void)
{
reset_calls();
win16_write_u16(dgroup_at(DGROUP_DEVICE_COUNT), 0, 1);
win16_write_u8(dgroup_at(DGROUP_SOUND_ENABLED), 1);
win16_write_u8(dgroup_at(DGROUP_SOUND_PLAYING), 0);
win16_write_u8(dgroup_at(DGROUP_GAME_TILTED), 1);
set_sound_buffer(4, win16_make_far_pointer(0x7300, 0x4444));
g_play_result = 1;
tdkpin_play_sound_if_not_tilted(4);
assert(g_played_sound == 0);
win16_write_u8(dgroup_at(DGROUP_GAME_TILTED), 0);
win16_write_u8(dgroup_at(DGROUP_SOUND_ENABLED), 0);
tdkpin_play_sound_if_not_tilted(4);
assert(g_played_sound == 0);
win16_write_u8(dgroup_at(DGROUP_SOUND_ENABLED), 1);
tdkpin_play_sound_if_not_tilted(4);
assert(g_played_sound == win16_make_far_pointer(0x7300, 0x4444));
assert(g_play_flags == 5);
}
int main(void)
{
uint8_t stack_marker;
uintptr_t stack_base = (uintptr_t)&stack_marker - 0x8000;
win16_reset_segment_bindings();
win16_bind_segment(0x5000, g_dgroup, sizeof(g_dgroup), true);
win16_bind_ne_segment(2, 0x5100, g_code2, sizeof(g_code2), false);
win16_bind_segment(0x9000, (void *)stack_base, 0x10000, true);
win16_set_dgroup_selector(0x5000);
g_win16_instance = 0x4444;
initialize_image_data();
test_initializer_disabled_and_probe_failures();
test_initializer_success();
test_stop_unload_and_play();
test_gameplay_sound_dispatcher();
return 0;
}