import struct, warnings try: import lz4 except ImportError: lz4 = None else: import lz4.block # old scheme for VERSION < 0.9 otherwise use lz4.block def decompress(data): (compression,) = struct.unpack(">L", data[4:8]) scheme = compression >> 27 size = compression & 0x07FFFFFF if scheme == 0: pass elif scheme == 1 and lz4: res = lz4.block.decompress(struct.pack("L", (scheme << 27) + (len(data) & 0x07FFFFFF)) if scheme == 0: return data elif scheme == 1 and lz4: res = lz4.block.compress( data, mode="high_compression", compression=16, store_size=False ) return hdr + res else: warnings.warn("Table failed to compress by unsupported compression scheme") return data def _entries(attrs, sameval): ak = 0 vals = [] lastv = 0 for k, v in attrs: if len(vals) and (k != ak + 1 or (sameval and v != lastv)): yield (ak - len(vals) + 1, len(vals), vals) vals = [] ak = k vals.append(v) lastv = v yield (ak - len(vals) + 1, len(vals), vals) def entries(attributes, sameval=False): g = _entries(sorted(attributes.items(), key=lambda x: int(x[0])), sameval) return g def bininfo(num, size=1): if num == 0: return struct.pack(">4H", 0, 0, 0, 0) srange = 1 select = 0 while srange <= num: srange *= 2 select += 1 select -= 1 srange //= 2 srange *= size shift = num * size - srange return struct.pack(">4H", num, srange, select, shift) def num2tag(n): if n < 0x200000: return str(n) else: return ( struct.unpack("4s", struct.pack(">L", n))[0].replace(b"\000", b"").decode() ) def tag2num(n): try: return int(n) except ValueError: n = (n + " ")[:4] return struct.unpack(">L", n.encode("ascii"))[0]