From d67ef2458aa585db2d3e9589d90e13c471c9e083 Mon Sep 17 00:00:00 2001 From: "arda.aydin@ontrol.com.tr" Date: Wed, 12 Aug 2026 20:30:16 +0300 Subject: [PATCH] First commit Sedonac kaynak dosyasindan Claude uretti --- sab2sax.py | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 sab2sax.py diff --git a/sab2sax.py b/sab2sax.py new file mode 100644 index 0000000..5c677ce --- /dev/null +++ b/sab2sax.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +""" +Convert Sedona .sab binary file to .sax XML format +Final working version based on hex dump analysis +""" + +import sys +import os +import struct +from pathlib import Path + +def read_null_string(data, offset): + """Read a null-terminated string""" + start = offset + while offset < len(data) and data[offset] != 0: + offset += 1 + if offset >= len(data): + return None, offset + string = data[start:offset].decode('ascii') + offset += 1 # Skip null + return string, offset + +def sab_to_sax(input_file): + """Convert .sab file to .sax XML format""" + + # Read binary file + with open(input_file, 'rb') as f: + sab_data = f.read() + + offset = 0 + + # Check magic number + magic = sab_data[0:4].decode('ascii') + if magic != "sapp": + print(f"Error: Not a valid Sedona binary file") + return + + offset += 4 + print(f"āœ“ Valid Sedona app file detected") + + # Version (2 bytes) + version = struct.unpack_from('>H', sab_data, offset)[0] + offset += 2 + + # Kit count + kit_count = struct.unpack_from('>H', sab_data, offset)[0] + offset += 2 + + # Read kit names and checksums + kits = [] + for i in range(kit_count): + kit_name, offset = read_null_string(sab_data, offset) + checksum = struct.unpack_from('>I', sab_data, offset)[0] + offset += 4 + kits.append((kit_name, checksum)) + print(f" Found kit: {kit_name}") + + # Start XML output + sax_xml = '\n' + sax_xml += f'\n\n' + sax_xml += ' \n' + + # Group types by kit (based on prefixes in the names) + kit_types = {kit[0]: [] for kit in kits} + + # Read all type names and their data + type_id = 1 + while offset < len(sab_data): + try: + # Read type name + type_name, new_offset = read_null_string(sab_data, offset) + if type_name is None: + break + + # Determine which kit this type belongs to + assigned_kit = None + for kit_name in kit_types.keys(): + if type_name.startswith(kit_name) or kit_name in type_name: + assigned_kit = kit_name + break + + if not assigned_kit: + assigned_kit = kits[0][0] # Default to first kit + + # Read the 4 bytes after the name (type data) + if new_offset + 4 <= len(sab_data): + type_data = struct.unpack_from('>I', sab_data, new_offset)[0] + new_offset += 4 + + # Store type info + kit_types[assigned_kit].append({ + 'id': type_id, + 'name': type_name, + 'data': type_data + }) + type_id += 1 + + offset = new_offset + + except Exception as e: + print(f" Warning: Stopped parsing at offset {offset}: {e}") + break + + # Write XML for each kit + for kit_name, checksum in kits: + types = kit_types.get(kit_name, []) + sax_xml += f' \n' + + for t in types: + sax_xml += f' \n' + + sax_xml += ' \n' + + sax_xml += ' \n\n' + + # Add placeholder for app and links + sax_xml += ' \n' + sax_xml += ' \n' + sax_xml += ' \n\n' + + sax_xml += ' \n' + sax_xml += ' \n' + sax_xml += ' \n' + + sax_xml += '' + + # Write output file + output_file = str(Path(input_file).with_suffix('.sax')) + with open(output_file, 'w', encoding='utf-8') as f: + f.write(sax_xml) + + print(f"\nāœ“ Successfully converted: {input_file} -> {output_file}") + print(f" Found {type_id-1} total types across {len(kits)} kits") + +def main(): + if len(sys.argv) != 2: + print("Usage: python sab_to_sax.py ") + sys.exit(1) + + input_file = sys.argv[1] + + if not os.path.exists(input_file): + print(f"Error: File not found: {input_file}") + sys.exit(1) + + try: + sab_to_sax(input_file) + except Exception as e: + print(f"Error converting file: {e}") + import traceback + traceback.print_exc() + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file