android-unlock-and-more-box/aubox/library/identify.py

93 lines
2.8 KiB
Python

"""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("<I", huawei.UPDATE_MAGIC)
def _peek(path: Path, n: int = 0x200) -> 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