def decompress(data: bytes) -> bytes: rdr = BinaryReader(data) wtr = BinaryWriter() compression_type = rdr.read_uint8() if compression_type == 0x24: blocksize = 4 elif compression_type == 0x28: blocksize = 8 else: raise Exception( "Tried to decompress something as huffman that isn't huffman") ds = rdr.read_uint24() if ds == 0: rdr.read_uint32() # Read the tree treesize = (rdr.read_uint8() + 1) * 2 tree_end = (rdr.c - 1) + treesize rootNode = HuffTreeNode.from_rdr(rdr, False, 5, tree_end) rdr.c = tree_end # Decompress with the tree bitsleft = 0 # amount of bits left to read from {commands} current_size = 0 currentNode = rootNode cashedbyte = -1 while current_size < ds: # Find next refrence to commands node while not currentNode.is_data: if bitsleft == 0: data = rdr.read_uint32() bitsleft = 32 bitsleft -= 1 nextIsOne = (data & (1 << bitsleft)) != 0 if nextIsOne: currentNode = currentNode.child1 else: currentNode = currentNode.child0 if blocksize == 8: current_size += 1 wtr.write_uint8(currentNode.data) elif blocksize == 4: if cashedbyte < 0: cashedbyte = currentNode.data else: cashedbyte |= currentNode.data << 4 wtr.write_uint8(cashedbyte) current_size += 1 cashedbyte = -1 currentNode = rootNode return wtr.data
def from_rdr(cls, rdr: BinaryReader, is_data: bool, relative_offset, max_stream_pos, parent=None): self = cls(is_data, parent=parent) if rdr.c >= max_stream_pos: return self.data = rdr.read_uint8() if not is_data: offset = self.data & 0x3F zeroIsData = (self.data & 0x80) > 0 oneIsData = (self.data & 0x40) > 0 # off AND NOT == off XOR (off AND 1) zeroRelOffset = (relative_offset ^ (relative_offset & 1)) + offset * 2 + 2 currStreamPos = rdr.c rdr.c += (zeroRelOffset - relative_offset) - 1 # Node after 0 self.child0 = HuffTreeNode.from_rdr(rdr, zeroIsData, zeroRelOffset, max_stream_pos, parent=self) # Node after 1 directly located after the node after 0 self.child1 = HuffTreeNode.from_rdr(rdr, oneIsData, zeroRelOffset + 1, max_stream_pos, parent=self) # reset stream rdr.c = currStreamPos return self