"""Format-Erkennung. Dispatcher: schaut auf Magic + Dateinamen, leitet an den passenden Parser weiter. Liefert ein einheitliches Dict mit den Feldern, die in die DB gehen. Aktuell unterstützt: - Huawei update.app (vollständig) Geplant (Stubs als Hinweis): - MediaTek scatter (txt + bin) - Samsung Odin (.tar.md5 mit AP/BL/CP/CSC) - Qualcomm rawprogram*.xml """ from __future__ import annotations import json import struct from pathlib import Path from . import huawei HUAWEI_MAGIC = struct.pack(" bytes: try: with path.open("rb") as f: return f.read(n) except OSError: return b"" def identify(path: Path, root: Path) -> dict: """Rückgabe: dict für db.upsert. Enthält mindestens rel_path, size, mtime, format. Erkennungs-Misserfolg -> format='unknown'.""" rel = str(path.resolve().relative_to(root.resolve())).replace("\\", "/") stat = path.stat() base: dict = { "rel_path": rel, "size": stat.st_size, "mtime": stat.st_mtime, "sha256": None, "format": "unknown", "vendor": None, "model": None, "soc": None, "version": None, "region": None, "extra_json": None, } head = _peek(path) # Huawei update.app — Magic taucht innerhalb der ersten 0x100 Bytes auf if HUAWEI_MAGIC in head[:0x200]: info = huawei.parse(path) if info is not None: base.update( format="huawei-update.app", vendor="Huawei", model=info.hardware_id or None, soc=huawei.soc_for(info.hardware_id) if info.hardware_id else None, version=info.earliest_date, # bessere Quelle wenn verfügbar region=_region_from_filename(path.name), extra_json=json.dumps({ "section_count": info.section_count, "has_boot": info.has_boot, "has_system": info.has_system, "first_sections": [ s.type for s in info.sections[:10] ], }), ) return base # Fallback: Filename-Heuristik (MTK scatter etc. — TODO) name = path.name.lower() if name.startswith("mt") and name.endswith(".txt"): base["format"] = "mtk-scatter-candidate" elif name.endswith(".tar.md5"): base["format"] = "samsung-odin-candidate" base["vendor"] = "Samsung" return base def _region_from_filename(name: str) -> str | None: """Huawei-Region oft im Filename: '...C432B198...' -> 'C432'.""" upper = name.upper() for marker in ("C432", "C636", "C185", "C233", "C605", "C10", "C461"): if marker in upper: return marker return None