def createFields(self): dictionary = {} self.nbits = self.startbits CLEAR_CODE = 2**self.nbits END_CODE = CLEAR_CODE + 1 compress_code = CLEAR_CODE + 2 obuf = [] output = [] while True: if compress_code >= 2**self.nbits: self.nbits += 1 code = Bits(self, "code[]", self.nbits) if code.value == CLEAR_CODE: if compress_code == 2**(self.nbits - 1): # this fixes a bizarre edge case where the reset code could # appear just after the bits incremented. Apparently, the # correct behaviour is to express the reset code with the # old number of bits, not the new... code = Bits(self, "code[]", self.nbits - 1) self.nbits = self.startbits + 1 dictionary = {} compress_code = CLEAR_CODE + 2 obuf = [] code._description = "Reset Code (LZW code %i)" % code.value yield code continue elif code.value == END_CODE: code._description = "End of Information Code (LZW code %i)" % code.value yield code break if code.value < CLEAR_CODE: # literal if obuf: chain = obuf + [code.value] dictionary[compress_code] = chain compress_code += 1 obuf = [code.value] output.append(code.value) code._description = "Literal Code %i" % code.value elif code.value >= CLEAR_CODE + 2: if code.value in dictionary: chain = dictionary[code.value] code._description = "Compression Code %i (found in dictionary as %s)" % ( code.value, rle_repr(chain)) else: chain = obuf + [obuf[0]] code._description = "Compression Code %i (not found in dictionary; guessed to be %s)" % ( code.value, rle_repr(chain)) dictionary[compress_code] = obuf + [chain[0]] compress_code += 1 obuf = chain output += chain code._description += "; Current Decoded Length %i" % len(output) yield code padding = paddingSize(self.current_size, 8) if padding: yield NullBits(self, "padding[]", padding)
def createFields(self): for i in range(20): yield Bits(self, "pretree_lengths[]", 4) pre_tree = build_tree( [self['pretree_lengths[%d]' % x].value for x in range(20)]) if not hasattr(self.root, "lzx_tree_lengths_" + self.name): self.lengths = [0] * self.num_elements setattr(self.root, "lzx_tree_lengths_" + self.name, self.lengths) else: self.lengths = getattr(self.root, "lzx_tree_lengths_" + self.name) i = 0 while i < self.num_elements: field = HuffmanCode(self, "tree_code[]", pre_tree) if field.realvalue <= 16: self.lengths[i] = (self.lengths[i] - field.realvalue) % 17 field._description = "Literal tree delta length %i (new length value %i for element %i)" % ( field.realvalue, self.lengths[i], i) i += 1 yield field elif field.realvalue == 17: field._description = "Tree Code 17: Zeros for 4-19 elements" yield field extra = Bits(self, "extra[]", 4) zeros = 4 + extra.value extra._description = "Extra bits: zeros for %i elements (elements %i through %i)" % ( zeros, i, i + zeros - 1) yield extra self.lengths[i:i + zeros] = [0] * zeros i += zeros elif field.realvalue == 18: field._description = "Tree Code 18: Zeros for 20-51 elements" yield field extra = Bits(self, "extra[]", 5) zeros = 20 + extra.value extra._description = "Extra bits: zeros for %i elements (elements %i through %i)" % ( zeros, i, i + zeros - 1) yield extra self.lengths[i:i + zeros] = [0] * zeros i += zeros elif field.realvalue == 19: field._description = "Tree Code 19: Same code for 4-5 elements" yield field extra = Bits(self, "extra[]", 1) run = 4 + extra.value extra._description = "Extra bits: run for %i elements (elements %i through %i)" % ( run, i, i + run - 1) yield extra newfield = HuffmanCode(self, "tree_code[]", pre_tree) assert newfield.realvalue <= 16 newfield._description = "Literal tree delta length %i (new length value %i for elements %i through %i)" % ( newfield.realvalue, self.lengths[i], i, i + run - 1) self.lengths[i:i + run] = [ (self.lengths[i] - newfield.realvalue) % 17 ] * run i += run yield newfield
def createFields(self): field = HuffmanCode(self, "dc_data", self.dc_tree) field._description = "DC Code %i (Huffman Code %i)" % ( field.realvalue, field.value) + field._description yield field if field.realvalue != 0: extra = Bits(self, "dc_data_extra", field.realvalue) if extra.value < 2**(field.realvalue - 1): corrected_value = extra.value + (-1 << field.realvalue) + 1 else: corrected_value = extra.value extra._description = "Extra Bits: Corrected DC Value %i" % corrected_value yield extra data = [] while len(data) < 63: field = HuffmanCode(self, "ac_data[]", self.ac_tree) value_r = field.realvalue >> 4 if value_r: data += [0] * value_r value_s = field.realvalue & 0x0F if value_r == value_s == 0: field._description = "AC Code Block Terminator (0, 0) (Huffman Code %i)" % field.value + \ field._description yield field return field._description = "AC Code %i, %i (Huffman Code %i)" % ( value_r, value_s, field.value) + field._description yield field if value_s != 0: extra = Bits(self, "ac_data_extra[%s" % field.name.split('[')[1], value_s) if extra.value < 2**(value_s - 1): corrected_value = extra.value + (-1 << value_s) + 1 else: corrected_value = extra.value extra._description = "Extra Bits: Corrected AC Value %i" % corrected_value data.append(corrected_value) yield extra else: data.append(0)
def createFields(self): values = [[], []] for i in (0, 1): yield Bits(self, "blue[]", 5) yield Bits(self, "green[]", 6) yield Bits(self, "red[]", 5) values[i] = [ self["red[%i]" % i].value, self["green[%i]" % i].value, self["blue[%i]" % i].value ] if values[0] > values[1] or self.dxt2_mode: values += interp_avg(values[0], values[1], 3) else: values += interp_avg(values[0], values[1], 2) values.append(None) # transparent for i in range(16): pixel = Bits(self, "pixel[%i][%i]" % divmod(i, 4), 2) color = values[pixel.value] if color is None: pixel._description = "Transparent" else: pixel._description = "RGB color: %s" % color_name( color, [5, 6, 5]) yield pixel
def createFields(self): values = [] yield UInt8(self, "alpha_val[0]", "First alpha value") values.append(self["alpha_val[0]"].value) yield UInt8(self, "alpha_val[1]", "Second alpha value") values.append(self["alpha_val[1]"].value) if values[0] > values[1]: values += interp_avg(values[0], values[1], 7) else: values += interp_avg(values[0], values[1], 5) values += [0, 255] for i in range(16): pixel = Bits(self, "alpha[%i][%i]" % divmod(i, 4), 3) alpha = values[pixel.value] pixel._description = "Alpha value: %i" % alpha yield pixel
def createFields(self): yield Bit(self, "final", "Is this the final block?") # BFINAL yield Enum( Bits(self, "compression_type", 2), # BTYPE { 0: "None", 1: "Fixed Huffman", 2: "Dynamic Huffman", 3: "Reserved" }) if self["compression_type"].value == 0: # no compression # align on byte boundary padding = paddingSize(self.current_size + self.absolute_address, 8) if padding: yield PaddingBits(self, "padding[]", padding) yield Int16(self, "len") yield Int16(self, "nlen", "One's complement of len") if self["len"].value != ~self["nlen"].value: raise ParserError( "len must be equal to the one's complement of nlen!") # null stored blocks produced by some encoders (e.g. PIL) if self["len"].value: yield RawBytes(self, "data", self["len"].value, "Uncompressed data") return elif self["compression_type"].value == 1: # Fixed Huffman length_tree = {} # (size, huffman code): value distance_tree = {} for i in range(144): length_tree[(8, i + 48)] = i for i in range(144, 256): length_tree[(9, i + 256)] = i for i in range(256, 280): length_tree[(7, i - 256)] = i for i in range(280, 288): length_tree[(8, i - 88)] = i for i in range(32): distance_tree[(5, i)] = i elif self["compression_type"].value == 2: # Dynamic Huffman yield Bits(self, "huff_num_length_codes", 5, "Number of Literal/Length Codes, minus 257") yield Bits(self, "huff_num_distance_codes", 5, "Number of Distance Codes, minus 1") yield Bits(self, "huff_num_code_length_codes", 4, "Number of Code Length Codes, minus 4") code_length_code_lengths = [0] * 19 # confusing variable name... for i in self.CODE_LENGTH_ORDER[:self["huff_num_code_length_codes"] .value + 4]: field = Bits(self, "huff_code_length_code[%i]" % i, 3, "Code lengths for the code length alphabet") yield field code_length_code_lengths[i] = field.value code_length_tree = build_tree(code_length_code_lengths) length_code_lengths = [] distance_code_lengths = [] for numcodes, name, lengths in ( (self["huff_num_length_codes"].value + 257, "length", length_code_lengths), (self["huff_num_distance_codes"].value + 1, "distance", distance_code_lengths)): while len(lengths) < numcodes: field = HuffmanCode(self, "huff_%s_code[]" % name, code_length_tree) value = field.realvalue if value < 16: prev_value = value field._description = "Literal Code Length %i (Huffman Code %i)" % ( value, field.value) yield field lengths.append(value) else: info = { 16: (3, 6, 2), 17: (3, 10, 3), 18: (11, 138, 7) }[value] if value == 16: repvalue = prev_value else: repvalue = 0 field._description = "Repeat Code %i, Repeating value (%i) %i to %i times (Huffman Code %i)" % ( value, repvalue, info[0], info[1], field.value) yield field extrafield = Bits( self, "huff_%s_code_extra[%s" % (name, field.name.split('[')[1]), info[2]) num_repeats = extrafield.value + info[0] extrafield._description = "Repeat Extra Bits (%i), total repeats %i" % ( extrafield.value, num_repeats) yield extrafield lengths += [repvalue] * num_repeats length_tree = build_tree(length_code_lengths) distance_tree = build_tree(distance_code_lengths) else: raise ParserError("Unsupported compression type 3!") while True: field = HuffmanCode(self, "length_code[]", length_tree) value = field.realvalue if value < 256: field._description = "Literal Code %r (Huffman Code %i)" % ( chr(value), field.value) yield field self.uncomp_data += chr(value) if value == 256: field._description = "Block Terminator Code (256) (Huffman Code %i)" % field.value yield field break elif value > 256: info = self.LENGTH_SYMBOLS[value] if info[2] == 0: field._description = "Length Code %i, Value %i (Huffman Code %i)" % ( value, info[0], field.value) length = info[0] yield field else: field._description = "Length Code %i, Values %i to %i (Huffman Code %i)" % ( value, info[0], info[1], field.value) yield field extrafield = Bits( self, "length_extra[%s" % field.name.split('[')[1], info[2]) length = extrafield.value + info[0] extrafield._description = "Length Extra Bits (%i), total length %i" % ( extrafield.value, length) yield extrafield field = HuffmanCode(self, "distance_code[]", distance_tree) value = field.realvalue info = self.DISTANCE_SYMBOLS[value] if info[2] == 0: field._description = "Distance Code %i, Value %i (Huffman Code %i)" % ( value, info[0], field.value) distance = info[0] yield field else: field._description = "Distance Code %i, Values %i to %i (Huffman Code %i)" % ( value, info[0], info[1], field.value) yield field extrafield = Bits( self, "distance_extra[%s" % field.name.split('[')[1], info[2]) distance = extrafield.value + info[0] extrafield._description = "Distance Extra Bits (%i), total length %i" % ( extrafield.value, distance) yield extrafield self.uncomp_data = extend_data(self.uncomp_data, length, distance)
def createFields(self): yield Bits(self, "block_type", 3) yield Bits(self, "block_size", 24) self.uncompressed_size = self["block_size"].value self.compression_level = self.root.compr_level self.window_size = self.WINDOW_SIZE[self.compression_level] self.block_type = self["block_type"].value curlen = len(self.parent.uncompressed_data) if self.block_type in (1, 2): # Verbatim or aligned offset block if self.block_type == 2: for i in range(8): yield Bits(self, "aligned_len[]", 3) aligned_tree = build_tree( [self['aligned_len[%d]' % i].value for i in range(8)]) yield LZXPreTreeEncodedTree(self, "main_tree_start", 256) yield LZXPreTreeEncodedTree(self, "main_tree_rest", self.window_size * 8) main_tree = build_tree(self["main_tree_start"].lengths + self["main_tree_rest"].lengths) yield LZXPreTreeEncodedTree(self, "length_tree", 249) length_tree = build_tree(self["length_tree"].lengths) current_decoded_size = 0 while current_decoded_size < self.uncompressed_size: if (curlen + current_decoded_size) % 32768 == 0 and ( curlen + current_decoded_size) != 0: padding = paddingSize(self.address + self.current_size, 16) if padding: yield PaddingBits(self, "padding[]", padding) field = HuffmanCode(self, "main_code[]", main_tree) if field.realvalue < 256: field._description = "Literal value %r" % chr( field.realvalue) current_decoded_size += 1 self.parent.uncompressed_data += chr(field.realvalue) yield field continue position_header, length_header = divmod( field.realvalue - 256, 8) info = self.POSITION_SLOTS[position_header] if info[2] == 0: if info[0] == 0: position = self.parent.r0 field._description = "Position Slot %i, Position [R0] (%i)" % ( position_header, position) elif info[0] == 1: position = self.parent.r1 self.parent.r1 = self.parent.r0 self.parent.r0 = position field._description = "Position Slot %i, Position [R1] (%i)" % ( position_header, position) elif info[0] == 2: position = self.parent.r2 self.parent.r2 = self.parent.r0 self.parent.r0 = position field._description = "Position Slot %i, Position [R2] (%i)" % ( position_header, position) else: position = info[0] - 2 self.parent.r2 = self.parent.r1 self.parent.r1 = self.parent.r0 self.parent.r0 = position field._description = "Position Slot %i, Position %i" % ( position_header, position) else: field._description = "Position Slot %i, Positions %i to %i" % ( position_header, info[0] - 2, info[1] - 2) if length_header == 7: field._description += ", Length Values 9 and up" yield field length_field = HuffmanCode(self, "length_code[]", length_tree) length = length_field.realvalue + 9 length_field._description = "Length Code %i, total length %i" % ( length_field.realvalue, length) yield length_field else: field._description += ", Length Value %i (Huffman Code %i)" % ( length_header + 2, field.value) yield field length = length_header + 2 if info[2]: if self.block_type == 1 or info[2] < 3: # verbatim extrafield = Bits( self, "position_extra[%s" % field.name.split('[')[1], info[2]) position = extrafield.value + info[0] - 2 extrafield._description = "Position Extra Bits (%i), total position %i" % ( extrafield.value, position) yield extrafield else: # aligned offset position = info[0] - 2 if info[2] > 3: extrafield = Bits( self, "position_verbatim[%s" % field.name.split('[')[1], info[2] - 3) position += extrafield.value * 8 extrafield._description = "Position Verbatim Bits (%i), added position %i" % ( extrafield.value, extrafield.value * 8) yield extrafield if info[2] >= 3: extrafield = HuffmanCode( self, "position_aligned[%s" % field.name.split('[')[1], aligned_tree) position += extrafield.realvalue extrafield._description = "Position Aligned Bits (%i), total position %i" % ( extrafield.realvalue, position) yield extrafield self.parent.r2 = self.parent.r1 self.parent.r1 = self.parent.r0 self.parent.r0 = position self.parent.uncompressed_data = extend_data( self.parent.uncompressed_data, length, position) current_decoded_size += length elif self.block_type == 3: # Uncompressed block padding = paddingSize(self.address + self.current_size, 16) if padding: yield PaddingBits(self, "padding[]", padding) else: yield PaddingBits(self, "padding[]", 16) self.endian = LITTLE_ENDIAN yield UInt32(self, "r[]", "New value of R0") yield UInt32(self, "r[]", "New value of R1") yield UInt32(self, "r[]", "New value of R2") self.parent.r0 = self["r[0]"].value self.parent.r1 = self["r[1]"].value self.parent.r2 = self["r[2]"].value yield RawBytes(self, "data", self.uncompressed_size) self.parent.uncompressed_data += self["data"].value if self["block_size"].value % 2: yield PaddingBits(self, "padding", 8) else: raise ParserError("Unknown block type %d!" % self.block_type)