Files
python-owen/owen/converter.py
2026-01-14 21:33:17 +03:00

230 lines
6.1 KiB
Python

#! /usr/bin/env python3
"""Функции для упаковки и распаковки разных типов данных."""
from binascii import hexlify, unhexlify
from decimal import Decimal
from struct import pack, unpack
def pack_str(value: str) -> bytes:
"""Упаковка данных типа STR."""
return bytes(value[::-1], encoding="cp1251")
def unpack_str(value: bytes, index: int) -> str:
"""Распаковка данных типа STR."""
return bytes(value[::-1]).decode("cp1251")
def pack_u24(value: tuple[int, int]) -> bytes:
"""Упаковка данных типа U24."""
return pack(">BH", *value)[:3]
def unpack_u24(value: bytes, index: int) -> tuple[int, int]:
"""Распаковка данных типа U24."""
return unpack(">BH", value[:3])
def pack_i8(value: int) -> bytes:
"""Упаковка данных типа I8."""
return pack(">b", value)[:1]
def unpack_i8(value: bytes, index: int) -> int:
"""Распаковка данных типа I8."""
return unpack(">b", value[:1])[0]
def pack_u8(value: int) -> bytes:
"""Упаковка данных типа U8."""
return pack(">B", value)[:1]
def unpack_u8(value: bytes, index: int) -> int:
"""Распаковка данных типа U8."""
return unpack(">B", value[:1])[0]
def pack_i16(value: int) -> bytes:
"""Упаковка данных типа I16."""
return pack(">h", value)[:2]
def unpack_i16(value: bytes, index: int) -> int:
"""Распаковка данных типа I16."""
return unpack(">h", value[:2])[0]
def pack_u16(value: int) -> bytes:
"""Упаковка данных типа U16."""
return pack(">H", value)[:2]
def unpack_u16(value: bytes, index: int) -> int:
"""Распаковка данных типа U16."""
return unpack(">H", value[:2])[0]
def pack_f24(value: float) -> bytes:
"""Упаковка данных типа F24."""
return pack(">f", value)[:3]
def unpack_f24(value: bytes, index: int) -> float:
"""Распаковка данных типа F24."""
return unpack(">f", value[:3] + b"\x00")[0]
def pack_f32(value: float) -> bytes:
"""Упаковка данных типа F32."""
return pack(">f", value)[:4]
def unpack_f32(value: bytes, index: int) -> float:
"""Распаковка данных типа F32."""
return unpack(">f", value[:4])[0]
def pack_f32t(value: tuple[float, int]) -> bytes:
"""Упаковка данных типа F32+T."""
return pack(">fH", *value)[:6]
def unpack_f32t(value: bytes, index: int) -> tuple[float, int]:
"""Распаковка данных типа F32+T."""
return unpack(">fH", value[:6])
def pack_i32(value: int) -> bytes:
"""Упаковка данных типа I32."""
return pack(">i", value)[:4]
def unpack_i32(value: bytes, index: int) -> int:
"""Распаковка данных типа I32."""
return unpack(">i", value[:4])[0]
def pack_u32(value: int) -> bytes:
"""Упаковка данных типа U32."""
return pack(">I", value)[:4]
def unpack_u32(value: bytes, index: int) -> int:
"""Распаковка данных типа U32."""
return unpack(">I", value[:4])[0]
def pack_sdot(value: float) -> bytes:
"""Упаковка данных типа STORED_DOT."""
sign, digits, exponent = Decimal(str(value)).as_tuple()
mantissa = int("".join(map(str, digits)))
frmt, size, chunk = {mantissa < 16: (">B", 4, slice(1)),
mantissa >= 4096: (">I", 20, slice(1, 4)),
}.get(True, (">H", 12, slice(2)))
bin_str = f"{sign:1b}{abs(exponent):03b}{mantissa:0{size}b}"
return pack(frmt, int(bin_str, 2))[chunk]
def unpack_sdot(value: bytes, index: int) -> float:
"""Распаковка данных типа STORED_DOT."""
if index is not None:
value = value[:-2]
data = int.from_bytes(value, "big")
shift = len(value) * 8 - 4
sign = data >> (shift + 3) & 1
exponent = data >> shift & 7
mantissa = data & (2 ** shift - 1)
return (-1) ** sign * 10 ** (-exponent) * mantissa
def _encode_dot_u(value: float) -> bytes:
"""Упаковка данных типа DEC_DOTi."""
value = int(value)
length = len(str(value))
length += length % 2
hexstr = f"{value:0{length}d}"
return unhexlify(hexstr)
def pack_dot0(value: float) -> bytes:
"""Упаковка данных типа DEC_DOT0."""
return _encode_dot_u(value)
def pack_dot3(value: float) -> bytes:
"""Упаковка данных типа DEC_DOT3."""
return _encode_dot_u(value * 1000)
def _decode_dot_u(value: bytes, index: int) -> int:
"""Распаковка данных типа DEC_DOTi."""
if index is not None:
value = value[:-2]
return int(hexlify(value).decode())
def unpack_dot0(value: bytes, index: int) -> int:
"""Распаковка данных типа DEC_DOT0."""
return _decode_dot_u(value, index)
def unpack_dot3(value: bytes, index: int) -> float:
"""Распаковка данных типа DEC_DOT3."""
return _decode_dot_u(value, index) / 1000.0
OWEN_TYPE = {"F32+T": {"pack": pack_f32t, "unpack": unpack_f32t},
"SDOT": {"pack": pack_sdot, "unpack": unpack_sdot},
"DOT0": {"pack": pack_dot0, "unpack": unpack_dot0},
"DOT3": {"pack": pack_dot3, "unpack": unpack_dot3},
"F32": {"pack": pack_f32, "unpack": unpack_f32},
"F24": {"pack": pack_f24, "unpack": unpack_f24},
"U16": {"pack": pack_u16, "unpack": unpack_u16},
"I16": {"pack": pack_i16, "unpack": unpack_i16},
"U32": {"pack": pack_u32, "unpack": unpack_u32},
"I32": {"pack": pack_i32, "unpack": unpack_i32},
"U8": {"pack": pack_u8, "unpack": unpack_u8},
"I8": {"pack": pack_i8, "unpack": unpack_i8},
"U24": {"pack": pack_u24, "unpack": unpack_u24}, # для N.err
"STR": {"pack": pack_str, "unpack": unpack_str}}