import struct from pathlib import Path from data.field_tree import FieldTree class CobolBinaryReader: def read(self, path: str, tree: FieldTree) -> list[dict]: d = Path(path).read_bytes() rs = self._record_size(tree) if rs == 0 or len(d) == 0: return [] return [self._parse(d[o:o + rs], tree) for o in range(0, len(d), rs) if len(d[o:o + rs]) >= rs] def _record_size(self, tree): return max((f.offset + f.length for f in tree.fields), default=0) def _parse(self, r, tree): out = {} for n, f in tree.flatten().items(): if f.length == 0 or f.offset + f.length > len(r): continue raw = r[f.offset:f.offset + f.length] if f.usage == "COMP-3": out[n] = self._comp3(raw, f.signed, f.decimal) elif f.usage in ("COMP", "COMP-5"): out[n] = int.from_bytes(raw, "big", signed=f.signed) else: out[n] = raw.decode("ascii", errors="replace").strip() return out def _comp3(self, raw, signed, dec): if not raw: return "0" nib = [] for b in raw: nib.append((b >> 4) & 0xF) nib.append(b & 0xF) s = nib.pop() v = sum(n * (10 ** (len(nib) - i)) for i, n in zip(range(len(nib)), nib)) if signed and s in (0xD, 0xB): v = -v d = 10 ** dec return f"{float(v) / d:.{dec}f}" if dec else str(v)