"""Verify that shipping card handlers match the native regression-test handlers.""" import struct from pathlib import Path from capstone import Cs, CS_ARCH_X86, CS_MODE_32 from capstone.x86_const import X86_OP_IMM class Coff: def __init__(self, path): self.data = path.read_bytes() _, count, _, symbol_at, total, optional, _ = struct.unpack_from(" 0: self.functions[name] = (section, value) index += 1 + aux self.sections = {} for section in range(1, count + 1): at = 20 + optional + (section - 1) * 40 size, raw, reloc, _, reloc_count = struct.unpack_from(" start] or [size]) relocations = {at: (self.symbols[symbol], kind) for at, symbol, kind in entries if start <= at < end} targets = {value: symbol for symbol, (sec, value) in self.functions.items() if sec == section} decoder = Cs(CS_ARCH_X86, CS_MODE_32) decoder.detail = True result = [] for ins in decoder.disasm(self.data[raw + start:raw + end], start): code = bytearray(ins.bytes) refs = [] for at, reference in relocations.items(): if ins.address <= at < ins.address + ins.size: offset = at - ins.address code[offset:offset + 4] = b"\0" * 4 refs.append((offset, reference)) target = None if ins.mnemonic == "call" and not refs and ins.operands[0].type == X86_OP_IMM: target = targets[ins.operands[0].imm] code[ins.imm_offset:ins.imm_offset + ins.imm_size] = b"\0" * ins.imm_size result.append((bytes(code), tuple(refs), target)) assert sum(len(code) for code, _, _ in result) == end - start, name return result def main(): root = Path(__file__).resolve().parents[2] tested = Coff(root / "build/actions/actions-test.obj") shipped = Coff(root / "build/graphics/poker.obj") functions = ("CardTableMouse3D", "LeaveCardTable3D", "RequestCardExit3D", "CardTableEscape3D", "HandleCardExit3D", "RenderCardExit3D", "HandleNativePoker3D", "HandleNativeBlackjack3D", "RenderNativePoker3D", "RenderNativeBlackjack3D", "StartCasino3D", "InitNativeDurak3D", "StartNativeDurak3D", "DurakBeginBout3D", "DurakCommitFlight3D", "DurakResolveBout3D", "DurakAITurn3D", "DurakClampSelection3D", "DurakMouse3D", "HandleNativeDurak3D", "RenderNativeDurak3D") for name in functions: suffix = "@4" if name == "CardTableMouse3D" else "@0" symbol = "_" + name + suffix assert tested.signature(symbol) == shipped.signature(symbol), name for name, size in (("NativeDurakSettle3D", 4), ("DurakCanTransfer3D", 8), ("DurakCanPlay3D", 12), ("DurakPlay3D", 12), ("DurakTake3D", 4), ("DurakFinish3D", 4), ("DurakRefill3D", 4), ("DurakCardValue3D", 4), ("DurakFindMove3D", 8), ("DurakMoveSelection3D", 4), ("DurakFlightPoint3D", 8), ("DrawNativeCard3D", 20)): symbol = f"_{name}@{size}" assert tested.signature(symbol) == shipped.signature(symbol), name print("PASS: shipping engine loop and all poker/blackjack/Durak input, rules, animation and exit handlers match native-tested code") if __name__ == "__main__": main()