import re, sys, json DUMP = r"C:/Users/vikto/Documents/Claude/rt-4d/radio-spi-dump.bin" data = open(DUMP, "rb").read() assert len(data) == 4194304 REGIONS = [ ("calibration", 0x000000, 0x001000), ("main_settings", 0x002000, 0x001000), ("channels", 0x004000, 0x00C000), ("zones", 0x01C000, 0x020000), ("contacts", 0x05C000, 0x010000), ("groups", 0x07C000, 0x003000), ("dmr_keys", 0x082000, 0x003000), ("call_log", 0x088000, 0x00C000), ("default_sms", 0x094000, 0x001000), ("msg_drafts", 0x095000, 0x010000), ("msg_inbox", 0x0A5000, 0x010000), ("msg_outbox", 0x0B5000, 0x010000), ("schedules", 0x0C6000, 0x008000), ("dtmf_names", 0x0C7000, 0x000100), ("fm_settings", 0x0D6000, 0x001000), ] def region_of(addr): for name, a, s in REGIONS: if a <= addr < a+s: return name return "UNMAPPED" # printable set for ascii def is_print(b): return 0x20 <= b <= 0x7E def looks_real(s): """Filter out punctuation-run / repeated-char noise.""" s2 = s.strip() if len(s2) < 3: return False # must contain at least one letter or digit if not re.search(r"[A-Za-z0-9一-鿿]", s2): return False # count alnum ratio alnum = sum(1 for c in s2 if c.isalnum() or ord(c) > 0x2000) if alnum / len(s2) < 0.4: return False # reject if single char repeated (e.g. "7777", "((((") uniq = set(s2) if len(uniq) <= 2 and len(s2) >= 4: # allow things like "10" no; but "AA" reject; require >2 unique for long return False # reject runs of same punctuation if re.fullmatch(r"(.)\1*", s2): return False return True results = [] # (addr, encoding, region, text) # ---- ASCII runs (min 3) ---- run_start = None for i, b in enumerate(data): if is_print(b): if run_start is None: run_start = i else: if run_start is not None: s = data[run_start:i].decode("latin-1") if len(s) >= 3 and looks_real(s): results.append((run_start, "ascii", region_of(run_start), s)) run_start = None if run_start is not None: s = data[run_start:len(data)].decode("latin-1") if len(s) >= 3 and looks_real(s): results.append((run_start, "ascii", region_of(run_start), s)) # ---- UTF-16LE runs ---- # pattern: printable-ascii byte followed by 0x00, repeated i = 0 n = len(data) while i < n-1: if is_print(data[i]) and data[i+1] == 0x00: j = i chars = [] while j < n-1 and data[j+1] == 0x00 and (is_print(data[j]) or data[j]==0x00): if data[j] == 0x00: break chars.append(chr(data[j])) j += 2 s = "".join(chars) if len(s) >= 3 and looks_real(s): results.append((i, "utf16le", region_of(i), s)) i = j + 2 if j > i else i+2 else: i += 1 # ---- GBK / chinese: try decode ascii runs that had high bytes? separate scan ---- # Scan for GBK multibyte sequences (lead 0x81-0xFE, trail 0x40-0xFE) def gbk_scan(): out=[] i=0 while i < n: b=data[i] # start a candidate if ascii-print or gbk lead if is_print(b) or (0x81<=b<=0xFE and i+1