import inspect import re from .exception import CheckFailed def assert_true(check, reason, exc=CheckFailed): if not check: line = inspect.stack()[1].code_context print() print("\n".join(line)) raise exc(reason) def py_encoding(name): if name.startswith("shift-jis"): return "shift-jis" return name def parse_model(model): # e.g. KFC:J:A:A:2019020600 gamecode, dest, spec, rev, version = re.match(r"([A-Z0-9]{3}):([A-Z]):([A-Z]):([A-Z])(?::(\d{8}))?", model).groups() return gamecode, dest, spec, rev, version def pack(data, width): assert_true(1 <= width <= 8, "Invalid pack size") assert_true(all(i < (1 << width) for i in data), "Data too large for packing") bit_buf = in_buf = 0 output = bytearray() for i in data: bit_buf |= i << (8 - width) shift = min(8 - in_buf, width) bit_buf <<= shift in_buf += shift if in_buf == 8: output.append(bit_buf >> 8) in_buf = width - shift bit_buf = (bit_buf & 0xff) << in_buf if in_buf: output.append(bit_buf >> in_buf) return bytes(output) def unpack(data, width): assert_true(1 <= width <= 8, "Invalid pack size") bit_buf = in_buf = 0 output = bytearray() for i in data: bit_buf |= i bit_buf <<= width - in_buf in_buf += 8 while in_buf >= width: output.append(bit_buf >> 8) in_buf -= width bit_buf = (bit_buf & 0xff) << min(width, in_buf) if in_buf: output.append(bit_buf >> (8 + in_buf - width)) return bytes(output) __all__ = ("assert_true", "py_encoding", "parse_model", "pack", "unpack")