#!/usr/bin/env python3 """Применить патч из редактора прошивки к образу. python3 apply_patch.py patch.json [--src stock-fw/rt4d_ru_batt.bin] [--out stock-fw/rt4d_custom.bin] Формат патча (его выдаёт кнопка «Скопировать патч»): {"texts":[{"va":134370285,"txt":"ОСН. НАСТР"}, ...], "logo":{"va":134500045,"b64":"..."}} Текст пишется в CP1251 и добивается пробелами ровно до исходной ширины поля — записи в прошивке фиксированной длины, сдвигать их нельзя. """ import argparse, base64, json, sys BASE = 0x08002800 # доступные глифы: ASCII + 33 заглавные кириллические буквы, дописанные при русификации CYR = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯЁ" def widths(src_len): """допустимые ширины полей — берём из таблиц редактора""" return None def main(): ap = argparse.ArgumentParser() ap.add_argument("patch") ap.add_argument("--src", default="stock-fw/rt4d_ru_batt.bin") ap.add_argument("--out", default="stock-fw/rt4d_custom.bin") ap.add_argument("--meta", default="tools/display-editor/field-widths.json", help="ширины полей (va -> max), пишется при сборке редактора") a = ap.parse_args() patch = json.load(open(a.patch, encoding="utf-8")) img = bytearray(open(a.src, "rb").read()) try: W = {int(k): v for k, v in json.load(open(a.meta, encoding="utf-8")).items()} except Exception: sys.exit(f"нет файла ширин полей {a.meta} — пересоберите редактор") bad = [] n = 0 for t in patch.get("texts", []): va, txt = t["va"], t["txt"] if va not in W: bad.append(f"неизвестный адрес 0x{va:08X}") continue w = W[va] for ch in txt: if ch not in CYR and not (0x20 <= ord(ch) <= 0x7E): bad.append(f"0x{va:08X}: нет глифа для «{ch}»") if len(txt) > w: bad.append(f"0x{va:08X}: «{txt}» длиннее поля ({len(txt)} > {w})") continue try: enc = txt.encode("cp1251") except UnicodeEncodeError as e: bad.append(f"0x{va:08X}: не кодируется в CP1251 ({e})") continue img[va - BASE: va - BASE + w] = enc.ljust(w, b" ") n += 1 lg = patch.get("logo") if lg: raw = base64.b64decode(lg["b64"]) if len(raw) != 288: bad.append(f"логотип: ожидалось 288 байт, пришло {len(raw)}") else: va = lg["va"] img[va - BASE: va - BASE + 288] = raw print("логотип обновлён (288 Б)") if bad: print("ОШИБКИ:") for b in bad: print(" " + b) if not n: sys.exit(1) open(a.out, "wb").write(bytes(img)) print(f"применено текстов: {n}") print(f"готово: {a.out}, {len(img)} Б") if __name__ == "__main__": main()