v1: executing-plans 模式生成,54 文件 1320 行 Python
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import struct
|
||||
from pathlib import Path
|
||||
from data.field_tree import FieldTree
|
||||
|
||||
|
||||
class CobolBinaryReader:
|
||||
def read(self, binary_path: str, tree: FieldTree) -> list[dict]:
|
||||
data = Path(binary_path).read_bytes()
|
||||
record_size = self._compute_record_size(tree)
|
||||
if record_size == 0 or len(data) == 0:
|
||||
return []
|
||||
records = []
|
||||
for offset in range(0, len(data), record_size):
|
||||
record = data[offset:offset + record_size]
|
||||
if len(record) >= record_size:
|
||||
records.append(self._parse_record(record, tree))
|
||||
return records
|
||||
|
||||
def _compute_record_size(self, tree: FieldTree) -> int:
|
||||
max_end = 0
|
||||
for f in tree.fields:
|
||||
end = f.offset + f.length
|
||||
if end > max_end:
|
||||
max_end = end
|
||||
return max_end
|
||||
|
||||
def _parse_record(self, record: bytes, tree: FieldTree) -> dict:
|
||||
result = {}
|
||||
for name, field in tree.flatten().items():
|
||||
if field.length == 0 or field.offset + field.length > len(record):
|
||||
continue
|
||||
raw = record[field.offset:field.offset + field.length]
|
||||
if field.usage == "COMP-3":
|
||||
result[name] = self._parse_comp3(raw, field.signed, field.decimal)
|
||||
elif field.usage == "COMP" or field.usage == "COMP-5":
|
||||
result[name] = int.from_bytes(raw, "big", signed=field.signed)
|
||||
else:
|
||||
result[name] = raw.decode("ascii", errors="replace").strip()
|
||||
return result
|
||||
|
||||
def _parse_comp3(self, raw: bytes, signed: bool, decimal: int) -> str:
|
||||
if not raw:
|
||||
return "0"
|
||||
nibbles = []
|
||||
for b in raw:
|
||||
nibbles.append((b >> 4) & 0x0F)
|
||||
nibbles.append(b & 0x0F)
|
||||
sign = nibbles.pop()
|
||||
value = 0
|
||||
for n in nibbles:
|
||||
value = value * 10 + n
|
||||
if signed and sign in (0x0D, 0x0B):
|
||||
value = -value
|
||||
divisor = 10 ** decimal
|
||||
result = float(value) / divisor
|
||||
return f"{result:.{decimal}f}" if decimal else str(value)
|
||||
Reference in New Issue
Block a user