#!/usr/bin/env python3 """Debug script to examine raw bytes of action mapping at offset 277187""" import sys sys.path.insert(0, r'C:\DEV\COPILOT\geutebruck-api\src\api') import grpc from protos import configuration_pb2 from protos import configuration_pb2_grpc import json def debug_parse(): """Examine raw bytes to understand parsing issue""" print("Connecting to SDK Bridge...") with grpc.insecure_channel('localhost:50051') as channel: stub = configuration_pb2_grpc.ConfigurationServiceStub(channel) # Export full config export_req = configuration_pb2.ExportJsonRequest() export_resp = stub.ExportConfigurationJson(export_req) config = json.loads(export_resp.json_data) # Find node at offset 277187 nodes = [n for n in config['rootNodes'] if n['startOffset'] == 277187] if not nodes: print("Node not found!") return node = nodes[0] # The marker name contains the raw binary data # Let's examine it byte by byte name = node.get('name', '') print(f"Marker at offset {node['startOffset']}") print(f"Marker name length: {len(name)} bytes") print(f"Node type: {node.get('nodeType')}") print() # Convert string back to bytes (this is what C# is doing) # But note: UTF-8 encoding/decoding corrupts binary data! name_bytes_utf8 = name.encode('utf-8') print(f"After UTF-8 round-trip: {len(name_bytes_utf8)} bytes") print() # Show first 100 bytes in hex print("First 100 bytes (hex):") for i in range(0, min(100, len(name)), 16): hex_line = ' '.join(f'{ord(name[i+j]):02X}' if i+j < len(name) else ' ' for j in range(16)) ascii_line = ''.join(name[i+j] if 32 <= ord(name[i+j]) < 127 else '.' for j in range(16) if i+j < len(name)) print(f" {i:3d}: {hex_line:<48} {ascii_line}") print() print("Parsing simulation (starting from byte 4 after 'ules'):") pos = 4 # Skip "ules" prop_count = 0 action_count = 0 while pos + 2 < len(name): b = ord(name[pos]) # Property marker: 01 if b == 0x01 and pos + 1 < len(name): name_len = ord(name[pos + 1]) if name_len > 0 and name_len < 100 and pos + 2 + name_len < len(name): prop_name_bytes = name[pos + 2:pos + 2 + name_len] if prop_name_bytes.startswith('.'): prop_count += 1 print(f" [{pos:3d}] Property: {prop_name_bytes}") pos += 2 + name_len # Try to parse value if pos < len(name): val_marker = ord(name[pos]) if val_marker == 0x01 and pos + 1 < len(name): val = ord(name[pos + 1]) print(f" Value: boolean = {val != 0}") pos += 2 elif val_marker == 0x00: print(f" Value: null") pos += 1 else: print(f" Value marker: 0x{val_marker:02X} (not handled)") pos += 1 continue # Action marker: 07 01 40 if pos + 4 < len(name): if ord(name[pos]) == 0x07 and ord(name[pos+1]) == 0x01 and ord(name[pos+2]) == 0x40: action_len = ord(name[pos+3]) | (ord(name[pos+4]) << 8) print(f" [{pos:3d}] Action marker found! Length: {action_len}") if action_len > 0 and action_len < 500 and pos + 5 + action_len <= len(name): action = name[pos + 5:pos + 5 + action_len] print(f" Action: {action}") action_count += 1 pos += 5 + action_len continue # Unknown byte, advance pos += 1 if pos > 90: # Safety limit break print() print(f"Summary: Found {prop_count} properties, {action_count} actions") if __name__ == '__main__': debug_parse()