def __init__(self, parent, name, tree, description=""): Field.__init__(self, parent, name, 0, description) endian = self.parent.endian stream = self.parent.stream addr = self.absolute_address value = 0 met_ff = False while (self.size, value) not in tree: if addr % 8 == 0: last_byte = stream.readBytes(addr - 8, 1) if last_byte == b'\xFF': next_byte = stream.readBytes(addr, 1) if next_byte != b'\x00': raise FieldError("Unexpected byte sequence %r!" % (last_byte + next_byte)) addr += 8 # hack hack hack met_ff = True self._description = "[skipped 8 bits after 0xFF] " bit = stream.readBits(addr, 1, endian) value <<= 1 value += bit self._size += 1 addr += 1 self.createValue = lambda: value self.realvalue = tree[(self.size, value)] if met_ff: self._size += 8
def createRawField(parent, size, name="raw[]", description=None): if size <= 0: raise FieldError("Unable to create raw field of %s bits" % size) if (size % 8) == 0: return RawBytes(parent, name, size // 8, description) else: return RawBits(parent, name, size, description)
def createNullField(parent, nbits, name="padding[]", description=None): if nbits <= 0: raise FieldError("Unable to create null padding of %s bits" % nbits) if (nbits % 8) == 0: return NullBytes(parent, name, nbits // 8, description) else: return NullBits(parent, name, nbits, description)
def __init__(self, parent, name, length, description="Raw data"): assert issubclass(parent.__class__, Field) if not (0 < length <= MAX_LENGTH): raise FieldError("Invalid RawBytes length (%s)!" % length) Field.__init__(self, parent, name, length * 8, description) self._display = None
def __init__(self, parent, name, signed, size, description=None): if not (8 <= size <= 16384): raise FieldError( "Invalid integer size (%s): have to be in 8..16384" % size) Bits.__init__(self, parent, name, size, description) self.signed = signed
def createFields(self): if self.frame["../type"].value in [0xC0, 0xC1]: # yay, huffman coding! if not hasattr(self, "huffman_tables"): self.huffman_tables = {} for huffman in self.parent.array("huffman"): for table in huffman["content"].array("huffman_table"): for _dummy_ in table: # exhaust table, so the huffman tree is built pass self.huffman_tables[table["table_class"].value, table["index"].value] = table.tree components = [] # sos_comp, samples max_vert = 0 max_horiz = 0 for component in self.scan.array("component"): for sof_comp in self.frame.array("component"): if sof_comp["component_id"].value == component[ "component_id"].value: vert = sof_comp["vert_sample"].value horiz = sof_comp["horiz_sample"].value components.append((component, vert * horiz)) max_vert = max(max_vert, vert) max_horiz = max(max_horiz, horiz) mcu_height = alignValue(self.frame["height"].value, 8 * max_vert) // (8 * max_vert) mcu_width = alignValue(self.frame["width"].value, 8 * max_horiz) // (8 * max_horiz) if self.restart_interval and self.restart_offset > 0: mcu_number = self.restart_interval * self.restart_offset else: mcu_number = 0 initial_mcu = mcu_number while True: if (self.restart_interval and mcu_number != initial_mcu and mcu_number % self.restart_interval == 0) or\ mcu_number == mcu_height * mcu_width: padding = paddingSize(self.current_size, 8) if padding: yield PaddingBits(self, "padding[]", padding) # all 1s last_byte = self.stream.readBytes( self.absolute_address + self.current_size - 8, 1) if last_byte == b'\xFF': next_byte = self.stream.readBytes( self.absolute_address + self.current_size, 1) if next_byte != b'\x00': raise FieldError("Unexpected byte sequence %r!" % (last_byte + next_byte)) yield NullBytes(self, "stuffed_byte[]", 1) break for sos_comp, num_units in components: for interleave_count in range(num_units): yield JpegHuffmanImageUnit( self, "block[%i]component[%i][]" % (mcu_number, sos_comp["component_id"].value), self.huffman_tables[ 0, sos_comp["dc_coding_table"].value], self.huffman_tables[ 1, sos_comp["ac_coding_table"].value]) mcu_number += 1 else: self.warning( "Sorry, only supporting Baseline & Extended Sequential JPEG images so far!" ) return
def __init__(self, parent, name, format, description=None, strip=None, charset=None, nbytes=None, truncate=None): Bytes.__init__(self, parent, name, 1, description) # Is format valid? assert format in self.VALID_FORMATS # Store options self._format = format self._strip = strip self._truncate = truncate # Check charset and compute character size in bytes # (or None when it's not possible to guess character size) if not charset or charset in self.CHARSET_8BIT: self._character_size = 1 # one byte per character elif charset in self.UTF_CHARSET: self._character_size = None else: raise FieldError("Invalid charset for %s: \"%s\"" % (self.path, charset)) self._charset = charset # It is a fixed string? if nbytes is not None: assert self._format == "fixed" # Arbitrary limits, just to catch some bugs... if not (1 <= nbytes <= 0xffff): raise FieldError("Invalid string size for %s: %s" % (self.path, nbytes)) self._content_size = nbytes # content length in bytes self._size = nbytes * 8 self._content_offset = 0 else: # Format with a suffix: Find the end of the string if self._format in self.SUFFIX_FORMAT: self._content_offset = 0 # Choose the suffix suffix = self.suffix_str # Find the suffix length = self._parent.stream.searchBytesLength( suffix, False, self.absolute_address) if length is None: raise FieldError( "Unable to find end of string %s (format %s)!" % (self.path, self._format)) if 1 < len(suffix): # Fix length for little endian bug with UTF-xx charset: # u"abc" -> "a\0b\0c\0\0\0" (UTF-16-LE) # search returns length=5, whereas real lenght is 6 length = alignValue(length, len(suffix)) # Compute sizes self._content_size = length # in bytes self._size = (length + len(suffix)) * 8 # Format with a prefix: Read prefixed length in bytes else: assert self._format in self.PASCAL_FORMATS # Get the prefix size prefix_size = self.PASCAL_FORMATS[self._format] self._content_offset = prefix_size # Read the prefix and compute sizes value = self._parent.stream.readBits(self.absolute_address, prefix_size * 8, self._parent.endian) self._content_size = value # in bytes self._size = (prefix_size + value) * 8 # For UTF-16 and UTF-32, choose the right charset using BOM if self._charset in self.UTF_CHARSET: # Charset requires a BOM? bomsize, endian = self.UTF_CHARSET[self._charset] if endian == "BOM": # Read the BOM value nbytes = bomsize // 8 bom = self._parent.stream.readBytes(self.absolute_address, nbytes) # Choose right charset using the BOM bom_endian = self.UTF_BOM[bomsize] if bom not in bom_endian: raise FieldError("String %s has invalid BOM (%s)!" % (self.path, repr(bom))) self._charset = bom_endian[bom] self._content_size -= nbytes self._content_offset += nbytes # Compute length in character if possible if self._character_size: self._length = self._content_size // self._character_size else: self._length = None