44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
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)
|