60 lines
1.6 KiB
Python
60 lines
1.6 KiB
Python
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Iterable
|
|
|
|
SCALE_NATIVE = {
|
|
"Z": 20_000_000,
|
|
"A": 3_000_000,
|
|
"B": 1_000_000,
|
|
"C": 200_000,
|
|
"D": 100_000,
|
|
"E": 50_000,
|
|
"F": 20_000,
|
|
"G": 7_500,
|
|
}
|
|
|
|
@dataclass(frozen=True)
|
|
class CellFile:
|
|
path: Path
|
|
relative_path: Path
|
|
scale_code: str
|
|
native_scale: int
|
|
|
|
@dataclass(frozen=True)
|
|
class ScanResult:
|
|
root: Path
|
|
cells: tuple[CellFile, ...]
|
|
object_dictionary: Path | None
|
|
attribute_dictionary: Path | None
|
|
|
|
def _find_case_insensitive(root: Path, names: set[str]) -> Path | None:
|
|
lowers = {n.lower() for n in names}
|
|
for p in root.rglob("*"):
|
|
if p.is_file() and p.name.lower() in lowers:
|
|
return p
|
|
return None
|
|
|
|
def scan_cm93(root: Path) -> ScanResult:
|
|
root = root.resolve()
|
|
if not root.exists():
|
|
raise FileNotFoundError(root)
|
|
cells = []
|
|
for p in root.rglob("*"):
|
|
if not p.is_file():
|
|
continue
|
|
ext = p.suffix.upper().lstrip(".")
|
|
if ext in SCALE_NATIVE:
|
|
cells.append(
|
|
CellFile(
|
|
path=p,
|
|
relative_path=p.relative_to(root),
|
|
scale_code=ext,
|
|
native_scale=SCALE_NATIVE[ext],
|
|
)
|
|
)
|
|
cells.sort(key=lambda c: (c.scale_code, str(c.relative_path).lower()))
|
|
obj = _find_case_insensitive(root, {"CM93OBJ.DIC"})
|
|
attr = _find_case_insensitive(root, {"ATTRLUT.DIC", "CM93ATTR.DIC"})
|
|
return ScanResult(root, tuple(cells), obj, attr)
|