93 lines
2.8 KiB
Python
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
|