def createFields(self): # Headers yield String(self, "header", 6, "Header (Exif\\0\\0)", charset="ASCII") if self["header"].value != "Exif\0\0": raise ParserError("Invalid EXIF signature!") yield String(self, "byte_order", 2, "Byte order", charset="ASCII") if self["byte_order"].value not in ("II", "MM"): raise ParserError("Invalid endian!") if self["byte_order"].value == "II": self.endian = LITTLE_ENDIAN else: self.endian = BIG_ENDIAN yield UInt16(self, "version", "TIFF version number") yield UInt32(self, "img_dir_ofs", "Next image directory offset") while not self.eof: addr = self.absolute_address + self.current_size tag = self.stream.readBits(addr, 16, NETWORK_ENDIAN) if tag == 0xFFD8: size = (self._size - self.current_size) // 8 yield SubFile(self, "thumbnail", size, "Thumbnail (JPEG file)", mime_type="image/jpeg") break elif tag == 0xFFFF: break yield ExifIFD(self, "ifd[]", "IFD") padding = self.seekBit(self._size) if padding is not None: yield padding
def createFields(self): addr = self.absolute_address len = self.stream.searchBytesLength(':', False, addr, addr + (MAX_STRING_LENGTH + 1) * 8) if len is None: raise ParserError("Torrent: unable to find string separator (':')") if not len: raise ParserError("Torrent: error: no string length!") val = String(self, "length", len, "String length") yield val try: len = int(val.value) except ValueError: len = -1 if len < 0: raise ParserError( "Invalid string length (%s)" % makePrintable(val.value, "ASCII", to_unicode=True)) yield String(self, "separator", 1, "String length/value separator") if not len: self.info("Empty string: len=%i" % len) return if len < 512: yield String(self, "value", len, "String value", charset="ISO-8859-1") else: # Probably raw data yield RawBytes(self, "value", len, "Raw data")
def getChain(self, start, use_sfat=False): if use_sfat: fat = self.ss_fat items_per_fat = self.items_per_ssfat err_prefix = "SFAT chain" else: fat = self.bb_fat items_per_fat = self.items_per_bbfat err_prefix = "BFAT chain" block = start block_set = set() previous = block while block != SECT.END_OF_CHAIN: if block in SECT.SPECIALS: raise ParserError( "%s: Invalid block index (0x%08x), previous=%s" % (err_prefix, block, previous)) if block in block_set: raise ParserError("%s: Found a loop (%s=>%s)" % (err_prefix, previous, block)) block_set.add(block) yield block previous = block index = block // items_per_fat try: block = fat[index]["index[%u]" % block].value except LookupError: break
def _addField(self, field): """ Add a field to the field set: * add it into _fields * update _current_size May raise a StopIteration() on error """ if not issubclass(field.__class__, Field): raise ParserError("Field type (%s) is not a subclass of 'Field'!" % field.__class__.__name__) assert isinstance(field._name, str) if field._name.endswith("[]"): self.setUniqueFieldName(field) if config.debug: self.info("[+] DBG: _addField(%s)" % field.name) # required for the msoffice parser if field._address != self._current_size: self.warning("Fix address of %s to %s (was %s)" % (field.path, self._current_size, field._address)) field._address = self._current_size ask_stop = False # Compute field size and check that there is enough place for it self.__is_feeding = True try: field_size = field.size except HACHOIR_ERRORS as err: if field.is_field_set and field.current_length and field.eof: self.warning("Error when getting size of '%s': %s" % (field.name, err)) field._stopFeeding() ask_stop = True else: self.warning("Error when getting size of '%s': delete it" % field.name) self.__is_feeding = False raise self.__is_feeding = False # No more place? dsize = self._checkSize(field._address + field.size, False) if (dsize is not None and dsize < 0) or (field.is_field_set and field.size <= 0): if self.autofix and self._current_size: self._fixFieldSize(field, field.size + dsize) else: raise ParserError("Field %s is too large!" % field.path) self._current_size += field.size try: self._fields.append(field._name, field) except UniqKeyError as err: self.warning("Duplicate field name " + unicode(err)) field._name += "[]" self.setUniqueFieldName(field) self._fields.append(field._name, field) if ask_stop: raise StopIteration()
def seekBit(self, address, relative=True): if not relative: address -= self.absolute_address if address < 0: raise ParserError("Seek below field set start (%s.%s)" % divmod(address, 8)) if not self._checkAddress(address): raise ParserError("Seek above field set end (%s.%s)" % divmod(address, 8)) self._offset = address return None
def createFields(self): yield Enum(UInt8(self, "tag"), self.root.CONSTANT_TYPES) if self["tag"].value not in self.root.CONSTANT_TYPES: raise ParserError("Java: unknown constant type (%s)" % self["tag"].value) self.constant_type = self.root.CONSTANT_TYPES[self["tag"].value] if self.constant_type == "Utf8": yield PascalString16(self, "bytes", charset="UTF-8") elif self.constant_type == "Integer": yield Int32(self, "bytes") elif self.constant_type == "Float": yield Float32(self, "bytes") elif self.constant_type == "Long": yield Int64(self, "bytes") elif self.constant_type == "Double": yield Float64(self, "bytes") elif self.constant_type == "Class": yield CPIndex(self, "name_index", "Class or interface name", target_types="Utf8") elif self.constant_type == "String": yield CPIndex(self, "string_index", target_types="Utf8") elif self.constant_type == "Fieldref": yield CPIndex(self, "class_index", "Field class or interface name", target_types="Class") yield CPIndex(self, "name_and_type_index", target_types="NameAndType") elif self.constant_type == "Methodref": yield CPIndex(self, "class_index", "Method class name", target_types="Class") yield CPIndex(self, "name_and_type_index", target_types="NameAndType") elif self.constant_type == "InterfaceMethodref": yield CPIndex(self, "class_index", "Method interface name", target_types="Class") yield CPIndex(self, "name_and_type_index", target_types="NameAndType") elif self.constant_type == "NameAndType": yield CPIndex(self, "name_index", target_types="Utf8") yield CPIndex(self, "descriptor_index", target_types="Utf8") else: raise ParserError("Not a valid constant pool element type: " + self["tag"].value)
def parseFontHeader(self): yield UInt16(self, "maj_ver", "Major version") yield UInt16(self, "min_ver", "Minor version") yield UInt16(self, "font_maj_ver", "Font major version") yield UInt16(self, "font_min_ver", "Font minor version") yield textHandler(UInt32(self, "checksum"), hexadecimal) yield Bytes(self, "magic", 4, r"Magic string (\x5F\x0F\x3C\xF5)") if self["magic"].value != "\x5F\x0F\x3C\xF5": raise ParserError("TTF: invalid magic of font header") # Flags yield Bit(self, "y0", "Baseline at y=0") yield Bit(self, "x0", "Left sidebearing point at x=0") yield Bit(self, "instr_point", "Instructions may depend on point size") yield Bit(self, "ppem", "Force PPEM to integer values for all") yield Bit(self, "instr_width", "Instructions may alter advance width") yield Bit(self, "vertical", "e laid out vertically?") yield PaddingBits(self, "reserved[]", 1) yield Bit(self, "linguistic", "Requires layout for correct linguistic rendering?") yield Bit(self, "gx", "Metamorphosis effects?") yield Bit(self, "strong", "Contains strong right-to-left glyphs?") yield Bit(self, "indic", "contains Indic-style rearrangement effects?") yield Bit(self, "lossless", "Data is lossless (Agfa MicroType compression)") yield Bit(self, "converted", "Font converted (produce compatible metrics)") yield Bit(self, "cleartype", "Optimised for ClearType") yield Bits(self, "adobe", 2, "(used by Adobe)") yield UInt16(self, "unit_per_em", "Units per em") if not(16 <= self["unit_per_em"].value <= 16384): raise ParserError("TTF: Invalid unit/em value") yield UInt32(self, "created_high") yield TimestampMac32(self, "created") yield UInt32(self, "modified_high") yield TimestampMac32(self, "modified") yield UInt16(self, "xmin") yield UInt16(self, "ymin") yield UInt16(self, "xmax") yield UInt16(self, "ymax") # Mac style yield Bit(self, "bold") yield Bit(self, "italic") yield Bit(self, "underline") yield Bit(self, "outline") yield Bit(self, "shadow") yield Bit(self, "condensed", "(narrow)") yield Bit(self, "expanded") yield PaddingBits(self, "reserved[]", 9) yield UInt16(self, "lowest", "Smallest readable size in pixels") yield Enum(UInt16(self, "font_dir", "Font direction hint"), DIRECTION_NAME) yield Enum(UInt16(self, "ofst_format"), {0: "short offsets", 1: "long"}) yield UInt16(self, "glyph_format", "(=0)")
def createFields(self): group = self["../group_desc/group[%u]" % self.uniq_id] superblock = self["/superblock"] block_size = self["/"].block_size # Read block bitmap addr = self.absolute_address + 56 * 8 self.superblock_copy = (self.stream.readBytes(addr, 2) == "\x53\xEF") if self.superblock_copy: yield SuperBlock(self, "superblock_copy") # Compute number of block and inodes block_count = superblock["blocks_per_group"].value inode_count = superblock["inodes_per_group"].value block_index = self.uniq_id * block_count inode_index = self.uniq_id * inode_count if (block_count % 8) != 0: raise ParserError("Invalid block count") if (inode_count % 8) != 0: raise ParserError("Invalid inode count") block_count = min(block_count, superblock["blocks_count"].value - block_index) inode_count = min(inode_count, superblock["inodes_count"].value - inode_index) # Read block bitmap field = self.seekByte(group["block_bitmap"].value * block_size, relative=False, null=True) if field: yield field yield BlockBitmap(self, "block_bitmap", block_index, block_count, "Block bitmap") # Read inode bitmap field = self.seekByte(group["inode_bitmap"].value * block_size, relative=False) if field: yield field yield InodeBitmap(self, "inode_bitmap", inode_index, inode_count, "Inode bitmap") # Read inode table field = self.seekByte(alignValue(self.current_size // 8, block_size)) if field: yield field yield InodeTable(self, "inode_table", inode_index, inode_count) # Add padding if needed addr = min(self.parent.size / 8, (self.uniq_id + 1) * superblock["blocks_per_group"].value * block_size) yield self.seekByte(addr, "data", relative=False)
def createFields(self): yield String(self, "start", 1, "Integer start delimiter (i)", charset="ASCII") # Find integer end addr = self.absolute_address+self.current_size len = self.stream.searchBytesLength('e', False, addr, addr+(MAX_INTEGER_SIZE+1)*8) if len is None: raise ParserError("Torrent: Unable to find integer end delimiter (e)!") if not len: raise ParserError("Torrent: error, empty integer!") yield String(self, "value", len, "Integer value", charset="ASCII") yield String(self, "end", 1, "Integer end delimiter")
def createFields(self): yield Bits(self, "sync[]", 2) # =2 if self["sync[0]"].value != 2: raise ParserError("Unknown video elementary data") yield Bits(self, "is_scrambled", 2) yield Bits(self, "priority", 1) yield Bit(self, "alignment") yield Bit(self, "is_copyrighted") yield Bit(self, "is_original") yield Bit(self, "has_pts", "Presentation Time Stamp") yield Bit(self, "has_dts", "Decode Time Stamp") yield Bit(self, "has_escr", "Elementary Stream Clock Reference") yield Bit(self, "has_es_rate", "Elementary Stream rate") yield Bit(self, "dsm_trick_mode") yield Bit(self, "has_copy_info") yield Bit(self, "has_prev_crc", "If True, previous PES packet CRC follows") yield Bit(self, "has_extension") yield UInt8(self, "size") # Time stamps if self["has_pts"].value: yield Bits(self, "sync[]", 4) # =2, or 3 if has_dts=True yield Timestamp(self, "pts") if self["has_dts"].value: if not (self["has_pts"].value): raise ParserError("Invalid PTS/DTS values") yield Bits(self, "sync[]", 4) # =1 yield Timestamp(self, "dts") if self["has_escr"].value: yield Bits(self, "sync[]", 2) # =0 yield SCR(self, "escr") if self["has_es_rate"].value: yield Bit(self, "sync[]") # =True yield Bits(self, "es_rate", 14) # in units of 50 bytes/second yield Bit(self, "sync[]") # =True if self["has_copy_info"].value: yield Bit(self, "sync[]") # =True yield Bits(self, "copy_info", 7) if self["has_prev_crc"].value: yield textHandler(UInt16(self, "prev_crc"), hexadecimal) # --- Extension --- if self["has_extension"].value: yield VideoExtension1(self, "extension") if self["extension/has_extension2"].value: yield VideoExtension2(self, "extension2")
def parseNames(self): # Read header yield UInt16(self, "format") if self["format"].value != 0: raise ParserError("TTF (names): Invalid format (%u)" % self["format"].value) yield UInt16(self, "count") yield UInt16(self, "offset") if MAX_NAME_COUNT < self["count"].value: raise ParserError("Invalid number of names (%s)" % self["count"].value) # Read name index entries = [] for index in xrange(self["count"].value): entry = NameHeader(self, "header[]") yield entry entries.append(entry) # Sort names by their offset entries.sort(key=lambda field: field["offset"].value) # Read name value last = None for entry in entries: # Skip duplicates values new = (entry["offset"].value, entry["length"].value) if last and last == new: self.warning("Skip duplicate %s %s" % (entry.name, new)) continue last = (entry["offset"].value, entry["length"].value) # Skip negative offset offset = entry["offset"].value + self["offset"].value if offset < self.current_size//8: self.warning("Skip value %s (negative offset)" % entry.name) continue # Add padding if any padding = self.seekByte(offset, relative=True, null=True) if padding: yield padding # Read value size = entry["length"].value if size: yield String(self, "value[]", size, entry.description, charset=entry.getCharset()) padding = (self.size - self.current_size) // 8 if padding: yield NullBytes(self, "padding_end", padding)
def createFields(self): yield Header(self, "header") if MAX_NAME_PER_HEADER < self["header/nb_name"].value: raise ParserError("EXE resource: invalid number of name (%s)" % self["header/nb_name"].value) if MAX_INDEX_PER_HEADER < self["header/nb_index"].value: raise ParserError("EXE resource: invalid number of index (%s)" % self["header/nb_index"].value) hdr = self["header"] for index in xrange(hdr["nb_name"].value): yield NameOffset(self, "name[]") for index in xrange(hdr["nb_index"].value): yield IndexOffset(self, "index[]", self.res_type)
def __init__(self, parent, name, description=None): Field.__init__(self, parent, name, 8, description) stream = self._parent.stream addr = self.absolute_address value = stream.readBits(addr, 8, BIG_ENDIAN) if 128 <= value: nbits = (value & 127) * 8 if not nbits: raise ParserError("ASN.1: invalid ASN integer size (zero)") if 64 < nbits: # Arbitrary limit to catch errors raise ParserError("ASN.1: ASN integer is limited to 64 bits") self._size = 8 + nbits value = stream.readBits(addr + 8, nbits, BIG_ENDIAN) self.createValue = lambda: value
def __init__(self, *args, **kw): FieldSet.__init__(self, *args, **kw) key = self["type"].value & 31 if self['class'].value == 0: # universal object if key in self.TYPE_INFO: self._name, self._handler, self._description, create_desc = self.TYPE_INFO[ key] if create_desc: self.createDescription = lambda: "%s: %s" % ( self.TYPE_INFO[key][2], create_desc(self)) self._description = None elif key == 31: raise ParserError( "ASN.1 Object: tag bigger than 30 are not supported") else: self._handler = None elif self['form'].value: # constructed: treat as sequence self._name = 'seq[]' self._handler = readSequence self._description = 'constructed object type %i' % key else: # primitive, context/private self._name = 'raw[]' self._handler = readASCIIString self._description = '%s object type %i' % (self['class'].display, key) field = self["size"] self._size = field.address + field.size + field.value * 8
def parseTuple(parent): yield Int32(parent, "count", "Item count") count = parent["count"].value if count < 0: raise ParserError("Invalid tuple/list count") for index in xrange(count): yield Object(parent, "item[]")
def __init__(self, parent, name, **kw): FieldSet.__init__(self, parent, name, **kw) code = self["bytecode"].value if code not in self.bytecode_info: raise ParserError('Unknown bytecode: "%s"' % code) self.code_info = self.bytecode_info[code] if not name: self._name = self.code_info[0] if code == "l": self.createValue = self.createValueLong elif code in ("i", "I", "f", "g"): self.createValue = lambda: self["value"].value elif code == "T": self.createValue = lambda: True elif code == "F": self.createValue = lambda: False elif code in ("x", "y"): self.createValue = self.createValueComplex elif code in ("s", "t", "u"): self.createValue = self.createValueString self.createDisplay = self.createDisplayString if code == 't': if not hasattr(self.root, 'string_table'): self.root.string_table = [] self.root.string_table.append(self) elif code == 'R': if hasattr(self.root, 'string_table'): self.createValue = self.createValueStringRef
def createFields(self): yield Bytes(self, "header", 4, r"PE header signature (PE\0\0)") if self["header"].value != "PE\0\0": raise ParserError("Invalid PE header signature") yield Enum(UInt16(self, "cpu", "CPU type"), self.cpu_name) yield UInt16(self, "nb_section", "Number of sections") yield TimestampUnix32(self, "creation_date", "Creation date") yield UInt32(self, "ptr_to_sym", "Pointer to symbol table") yield UInt32(self, "nb_symbols", "Number of symbols") yield UInt16(self, "opt_hdr_size", "Optional header size") yield Bit(self, "reloc_stripped", "If true, don't contain base relocations.") yield Bit(self, "exec_image", "Executable image?") yield Bit(self, "line_nb_stripped", "COFF line numbers stripped?") yield Bit(self, "local_sym_stripped", "COFF symbol table entries stripped?") yield Bit(self, "aggr_ws", "Aggressively trim working set") yield Bit(self, "large_addr", "Application can handle addresses greater than 2 GB") yield NullBits(self, "reserved", 1) yield Bit(self, "reverse_lo", "Little endian: LSB precedes MSB in memory") yield Bit(self, "32bit", "Machine based on 32-bit-word architecture") yield Bit(self, "is_stripped", "Debugging information removed?") yield Bit( self, "swap", "If image is on removable media, copy and run from swap file") yield PaddingBits(self, "reserved2", 1) yield Bit(self, "is_system", "It's a system file") yield Bit(self, "is_dll", "It's a dynamic-link library (DLL)") yield Bit(self, "up", "File should be run only on a UP machine") yield Bit(self, "reverse_hi", "Big endian: MSB precedes LSB in memory")
def createFields(self): # Choose the right endian depending on endian specified in header if self.stream.readBits(5 * 8, 8, BIG_ENDIAN) == ElfHeader.BIG_ENDIAN_ID: self.endian = BIG_ENDIAN else: self.endian = LITTLE_ENDIAN # Parse header and program headers yield ElfHeader(self, "header", "Header") for index in xrange(self["header/phnum"].value): yield ProgramHeader32(self, "prg_header[]") if False: raise ParserError("TODO: Parse sections...") #sections = self.array("prg_header") #size = self["header/shoff"].value - self.current_size//8 #chunk = self.doRead("data", "Data", (DeflateFilter, stream, size, Sections, sections)) #chunk.description = "Sections (use an evil hack to manage share same data on differents parts)" #assert self.current_size//8 == self["header/shoff"].value else: raw = self.seekByte(self["header/shoff"].value, "raw[]", relative=False) if raw: yield raw for index in xrange(self["header/shnum"].value): yield SectionHeader32(self, "section_header[]")
def __init__(self, *args, **kw): FieldSet.__init__(self, *args, **kw) if not self._size: frame_size = self.getFrameSize() if not frame_size: raise ParserError("MPEG audio: Invalid frame %s" % self.path) self._size = min(frame_size * 8, self.parent.size - self.address)
def __init__(self, parent, ids): FieldSet.__init__(self, parent, "?[]") # Set name id = self['id'].value self.val = ids.get(id) if not self.val: if id == 0xBF: self.val = 'CRC-32[]', Binary elif id == 0xEC: self.val = 'Void[]', Binary elif id == 0x1B538667: self.val = 'SignatureSlot[]', signature else: self.val = 'Unknown[]', Binary self._name = self.val[0] # Compute size size = self['size'] if size.value is not None: self._size = size.address + size.size + size.value * 8 elif self._parent._parent: raise ParserError( "Unknown length (only allowed for the last Level 0 element)") elif self._parent._size is not None: self._size = self._parent._size - self.address
def createFields(self): # Read chunk header yield Bytes(self, "signature", 3, r"Property signature (\x8E\xAD\xE8)") if self["signature"].value != "\x8E\xAD\xE8": raise ParserError("Invalid property signature") yield UInt8(self, "version", "Signature version") yield NullBytes(self, "reserved", 4, "Reserved") yield UInt32(self, "count", "Count") yield UInt32(self, "size", "Size") # Read item header items = [] for i in range(0, self["count"].value): item = ItemHeader(self, "item[]") yield item items.append(item) # Sort items by their offset items.sort(sortRpmItem) # Read item content start = self.current_size / 8 for item in items: offset = item["offset"].value diff = offset - (self.current_size / 8 - start) if 0 < diff: yield NullBytes(self, "padding[]", diff) yield ItemContent(self, "content[]", item) size = start + self["size"].value - self.current_size / 8 if 0 < size: yield NullBytes(self, "padding[]", size)
def __str__(self): """ Returns a human-readable string representation of the constant pool entry. It is used for pretty-printing of the CPIndex fields pointing to it. """ if self.constant_type == "Utf8": return self["bytes"].value elif self.constant_type in ("Integer", "Float", "Long", "Double"): return self["bytes"].display elif self.constant_type == "Class": class_name = str(self["name_index"].get_cp_entry()) return class_name.replace("/", ".") elif self.constant_type == "String": return str(self["string_index"].get_cp_entry()) elif self.constant_type == "Fieldref": return "%s (from %s)" % (self["name_and_type_index"], self["class_index"]) elif self.constant_type == "Methodref": return "%s (from %s)" % (self["name_and_type_index"], self["class_index"]) elif self.constant_type == "InterfaceMethodref": return "%s (from %s)" % (self["name_and_type_index"], self["class_index"]) elif self.constant_type == "NameAndType": return parse_any_descriptor( str(self["descriptor_index"].get_cp_entry()), name=str(self["name_index"].get_cp_entry())) else: # FIXME: Return "<error>" instead of raising an exception? raise ParserError("Not a valid constant pool element type: " + self["tag"].value)
def Entry(parent, name): addr = parent.absolute_address + parent.current_size tag = parent.stream.readBytes(addr, 1) if tag not in TAGS: raise ParserError("Torrent: Entry of type %r not handled" % type) cls = TAGS[tag] return cls(parent, name)
def createFields(self): # First kilobyte: boot sectors yield RawBytes(self, "boot", 1024, "Space for disklabel etc.") # Header yield UInt32(self, "version") yield UInt32(self, "last_page") yield UInt32(self, "nb_badpage") yield UUID(self, "sws_uuid") yield UUID(self, "sws_volume") yield NullBytes(self, "reserved", 117 * 4) # Read bad pages (if any) count = self["nb_badpage"].value if count: if MAX_SWAP_BADPAGES < count: raise ParserError("Invalid number of bad page (%u)" % count) yield GenericVector(self, "badpages", count, UInt32, "badpage") # Read magic padding = self.seekByte(PAGE_SIZE - 10, "padding", null=True) if padding: yield padding yield String(self, "magic", 10, charset="ASCII") # Read all pages yield GenericVector(self, "pages", self["last_page"].value, Page, "page") # Padding at the end padding = self.seekBit(self.size, "end_padding", null=True) if padding: yield padding
def seekBit(self, address, name="padding[]", description=None, relative=True, null=False): """ Create a field to seek to specified address, or None if it's not needed. May raise an (ParserError) exception if address is invalid. """ if relative: nbits = address - self._current_size else: nbits = address - (self.absolute_address + self._current_size) if nbits < 0: raise ParserError("Seek error, unable to go back!") if 0 < nbits: if null: return createNullField(self, nbits, name, description) else: return createPaddingField(self, nbits, name, description) else: return None
def paletteParse(parent): size = parent["size"].value if (size % 3) != 0: raise ParserError("Palette have invalid size (%s), should be 3*n!" % size) nb_colors = size // 3 for index in xrange(nb_colors): yield RGB(parent, "color[]")
def createFields(self): yield textHandler(UInt32(self, "magic", "File information magic (0xFEEF04BD)"), hexadecimal) if self["magic"].value != 0xFEEF04BD: raise ParserError("EXE resource: invalid file info magic") yield Version(self, "struct_ver", "Structure version (1.0)") yield Version(self, "file_ver_ms", "File version MS") yield Version(self, "file_ver_ls", "File version LS") yield Version(self, "product_ver_ms", "Product version MS") yield Version(self, "product_ver_ls", "Product version LS") yield textHandler(UInt32(self, "file_flags_mask"), hexadecimal) yield Bit(self, "debug") yield Bit(self, "prerelease") yield Bit(self, "patched") yield Bit(self, "private_build") yield Bit(self, "info_inferred") yield Bit(self, "special_build") yield NullBits(self, "reserved", 26) yield Enum(textHandler(UInt16(self, "file_os_major"), hexadecimal), MAJOR_OS_NAME) yield Enum(textHandler(UInt16(self, "file_os_minor"), hexadecimal), MINOR_OS_NAME) yield Enum(textHandler(UInt32(self, "file_type"), hexadecimal), FILETYPE_NAME) field = textHandler(UInt32(self, "file_subfile"), hexadecimal) if field.value == FILETYPE_DRIVER: field = Enum(field, DRIVER_SUBTYPE_NAME) elif field.value == FILETYPE_FONT: field = Enum(field, FONT_SUBTYPE_NAME) yield field yield TimestampUnix32(self, "date_ms") yield TimestampUnix32(self, "date_ls")
def createFields(self): offset_diff = 6 yield UInt16(self, "count", "Number of entries") entries = [] next_chunk_offset = None count = self["count"].value if not count: return while count: addr = self.absolute_address + self.current_size next = self.stream.readBits(addr, 32, NETWORK_ENDIAN) if next in (0, 0xF0000000): break entry = ExifEntry(self, "entry[]") yield entry if entry["tag"].value in (ExifEntry.EXIF_IFD_POINTER, ExifEntry.OFFSET_JPEG_SOI): next_chunk_offset = entry["value"].value + offset_diff if 32 < entry.getSizes()[0]: entries.append(entry) count -= 1 yield UInt32(self, "next", "Next IFD offset") try: entries.sort(sortExifEntry) except TypeError: raise ParserError("Unable to sort entries!") value_index = 0 for entry in entries: padding = self.seek(entry["offset"].value + offset_diff) if padding is not None: yield padding value_size, array_size = entry.getSizes() if not array_size: continue cls = entry.value_cls if 1 < array_size: name = "value_%s[]" % entry.name else: name = "value_%s" % entry.name desc = "Value of \"%s\"" % entry["tag"].display if cls is String: for index in xrange(array_size): yield cls(self, name, value_size / 8, desc, strip=" \0", charset="ISO-8859-1") elif cls is Bytes: for index in xrange(array_size): yield cls(self, name, value_size / 8, desc) else: for index in xrange(array_size): yield cls(self, name, desc) value_index += 1 if next_chunk_offset is not None: padding = self.seek(next_chunk_offset) if padding is not None: yield padding
def createFields(self): # File data self.signature = None self.central_directory = [] while not self.eof: header = textHandler(UInt32(self, "header[]", "Header"), hexadecimal) yield header header = header.value if header == FileEntry.HEADER: yield FileEntry(self, "file[]") elif header == ZipDataDescriptor.HEADER: yield ZipDataDescriptor(self, "spanning[]") elif header == 0x30304b50: yield ZipDataDescriptor(self, "temporary_spanning[]") elif header == ZipCentralDirectory.HEADER: yield ZipCentralDirectory(self, "central_directory[]") elif header == ZipEndCentralDirectory.HEADER: yield ZipEndCentralDirectory(self, "end_central_directory", "End of central directory") elif header == Zip64EndCentralDirectory.HEADER: yield Zip64EndCentralDirectory(self, "end64_central_directory", "ZIP64 end of central directory") elif header == ZipSignature.HEADER: yield ZipSignature(self, "signature", "Signature") elif header == Zip64EndCentralDirectoryLocator.HEADER: yield Zip64EndCentralDirectoryLocator(self, "end_locator", "ZIP64 Enf of central directory locator") else: raise ParserError("Error, unknown ZIP header (0x%08X)." % header)
def createFields(self): # Header yield String(self, "magic", 3, "File magic code", charset="ASCII") yield String(self, "version", 3, "GIF version", charset="ASCII") yield ScreenDescriptor(self, "screen") if self["screen/global_map"].value: bpp = (self["screen/bpp"].value+1) yield PaletteRGB(self, "color_map", 1 << bpp, "Color map") self.color_map = self["color_map"] else: self.color_map = None self.images = [] while True: code = Enum(Character(self, "separator[]", "Separator code"), self.separator_name) yield code code = code.value if code == "!": yield Extension(self, "extensions[]") elif code == ",": yield Image(self, "image[]") elif code == ";": # GIF Terminator break else: raise ParserError("Wrong GIF image separator: 0x%02X" % ord(code))