import sys
STRIP_EXTRA = False
def opts(byte):
if byte is None:
return []
return [
byte | (byte << 1) & 0xFF,
byte & (byte << 1),
byte | (byte >> 1) & 0xFF,
byte & (byte >> 1),
]
def pb12_encode(data):
data = iter(data)
literals = bytearray()
bits = 0
control = 0
prev = [None, None]
while True:
try:
byte = next(data)
except StopIteration:
if bits == 0:
break
byte = 0
if byte in prev:
bits += 2
control <<= 1
control |= 1
control <<= 1
if byte == prev[1]:
control |= 1 else:
bits += 2
control <<= 2
options = opts(prev[1])
if byte in options:
control |= 1
bits += 2
control <<= 2
control |= options.index(byte)
else:
literals.append(byte)
prev = [prev[1], byte]
if bits >= 8:
outctl = control >> (bits - 8)
assert outctl != 1 yield bytes([outctl]) + literals
bits -= 8
control &= (1 << bits) - 1
literals = bytearray()
yield b"\x01"
def pb12_decode(data):
data = iter(data)
output = bytearray()
prev = [None, None]
while True:
try:
control = next(data)
if control == 0x01:
break except StopIteration:
break
control_bits = 8
while control_bits > 0:
if control_bits < 2:
break
control_bits -= 2
ctl = (control >> control_bits) & 0b11
if ctl == 0b10:
output.append(prev[0])
elif ctl == 0b11:
output.append(prev[1])
elif ctl == 0b01:
if control_bits < 2:
control = next(data)
control_bits = 8
control_bits -= 2
modify_ctl = (control >> control_bits) & 0b11
options = opts(prev[1])
output.append(options[modify_ctl])
else: try:
literal = next(data)
except StopIteration:
break
output.append(literal)
prev = [prev[1], output[-1]]
yield bytes(output)
if __name__ == "__main__":
if not len(sys.argv) > 3:
print("Usage: pb12.py <mode> <infile> <outfile>")
sys.exit(1)
mode, infile, outfile = sys.argv[1:]
if mode in ("encode", "compress"):
operation = pb12_encode
elif mode in ("decode", "decompress"):
operation = pb12_decode
else:
raise ValueError("Invalid mode")
with open(infile, "rb") as file:
data = file.read()
if STRIP_EXTRA and mode in ("encode", "compress"):
data = data.rstrip(b"\x00")
with open(outfile, "wb") as file:
file.writelines(operation(data))