def createFields(self): yield UInt16(self, "signature", "PE optional header signature (0x010b)") # TODO: Support PE32+ (signature=0x020b) if self["signature"].value != 0x010b: raise ParserError("Invalid PE optional header signature") yield UInt8(self, "maj_lnk_ver", "Major linker version") yield UInt8(self, "min_lnk_ver", "Minor linker version") yield filesizeHandler(UInt32(self, "size_code", "Size of code")) yield filesizeHandler(UInt32(self, "size_init_data", "Size of initialized data")) yield filesizeHandler(UInt32(self, "size_uninit_data", "Size of uninitialized data")) yield textHandler(UInt32(self, "entry_point", "Address (RVA) of the code entry point"), hexadecimal) yield textHandler(UInt32(self, "base_code", "Base (RVA) of code"), hexadecimal) yield textHandler(UInt32(self, "base_data", "Base (RVA) of data"), hexadecimal) yield textHandler(UInt32(self, "image_base", "Image base (RVA)"), hexadecimal) yield filesizeHandler(UInt32(self, "sect_align", "Section alignment")) yield filesizeHandler(UInt32(self, "file_align", "File alignment")) yield UInt16(self, "maj_os_ver", "Major OS version") yield UInt16(self, "min_os_ver", "Minor OS version") yield UInt16(self, "maj_img_ver", "Major image version") yield UInt16(self, "min_img_ver", "Minor image version") yield UInt16(self, "maj_subsys_ver", "Major subsystem version") yield UInt16(self, "min_subsys_ver", "Minor subsystem version") yield NullBytes(self, "reserved", 4) yield filesizeHandler(UInt32(self, "size_img", "Size of image")) yield filesizeHandler(UInt32(self, "size_hdr", "Size of headers")) yield textHandler(UInt32(self, "checksum"), hexadecimal) yield Enum(UInt16(self, "subsystem"), self.SUBSYSTEM_NAME) yield UInt16(self, "dll_flags") yield filesizeHandler(UInt32(self, "size_stack_reserve")) yield filesizeHandler(UInt32(self, "size_stack_commit")) yield filesizeHandler(UInt32(self, "size_heap_reserve")) yield filesizeHandler(UInt32(self, "size_heap_commit")) yield UInt32(self, "loader_flags") yield UInt32(self, "nb_directory", "Number of RVA and sizes") for index in xrange(self["nb_directory"].value): try: name = self.DIRECTORY_NAME[index] except KeyError: name = "data_dir[%u]" % index yield DataDirectory(self, name)
def __init__(self, parent, name, desc=None): Field.__init__(self, parent, name, description=desc) if parent.stream.readBytes(self.absolute_address, 1) != b'/': raise ParserError( "Unknown PDFName '%s'" % parent.stream.readBytes(self.absolute_address, 10)) size = getElementEnd(parent, offset=1) # other_size = getElementEnd(parent, '[')-1 # if size is None or (other_size is not None and other_size < size): # size = other_size for limit in self.LIMITS: other_size = getElementEnd(parent, limit, 1) if other_size is not None: other_size -= 1 if size is None or other_size < size: # self.info("New size: %u" % other_size) size = other_size self._size = 8 * (size + 1) # Value should be without the initial '/' and final ' ' self.createValue = lambda: parent.stream.readBytes( self.absolute_address + 8, size).strip(b' ')
def _createFields(self, field_generator): if self._first is None: for field in field_generator: if self._first is not None: break yield field else: raise ParserError("Fragment.setLinks not called") else: field = None if self._first is not self: link = Link(self, "first", None) link._getValue = lambda: self._first yield link if self._next: link = Link(self, "next", None) link.createValue = self._getNext yield link if field: yield field for field in field_generator: yield field
def __init__(self, parent, name, description=None): FieldSet.__init__(self, parent, name, description) self._size = (self["size"].value + 3 * 4) * 8 if MAX_CHUNK_SIZE < (self._size // 8): raise ParserError("PNG: Chunk is too big (%s)" % humanFilesize(self._size // 8)) tag = self["tag"].value self.desc_func = None self.value_func = None if tag in self.TAG_INFO: self._name, self.parse_func, desc, value_func = self.TAG_INFO[tag] if value_func: self.value_func = value_func self.createValue = self.createValueFunc if desc: if isinstance(desc, str): self._description = desc else: self.desc_func = desc else: self._description = "" self.parse_func = None
def createFields(self): yield UInt32(self, "unknown", description="Always 1") yield BudHeader(self, "header") self.seekByte(self['header/allocator_offset'].value + 4) yield BudAllocator(self, "allocator", size=self['header/allocator_size'].value * 8) for dir in self['allocator'].array('dir'): if dir['name'].value == 'DSDB': break else: raise ParserError("DSDB not found.") offs, size = self.getBlock(dir['block'].value) self.seekByte(offs + 4) yield DSDB(self, "dsdb", size=size * 8) blocks = [self['dsdb/root_block'].value] while blocks: block = blocks.pop() offs, size = self.getBlock(block) self.seekByte(offs + 4) node = BTNode(self, "node[%d]" % block, size=size * 8) yield node if node['last_block'].value != 0: new_blocks = [] for block in node.array('child_block'): new_blocks.append(block.value) new_blocks.append(node['last_block'].value) blocks.extend(reversed(new_blocks)) # dfs # blocks = new_blocks[::-1] + blocks # bfs for i, fl in enumerate(self['allocator'].array('freelist')): if fl['count'].value == 0: continue for offs in fl.array('offset'): size = min(1 << i, self.size // 8 - offs.value - 4) if size > 0: self.seekByte(offs.value + 4) yield RawBytes(self, "free[]", size)
def createFields(self): yield UInt32(self, "width", "Width in pixel") yield UInt32(self, "height", "Height in pixel") yield UInt32(self, "offset", "Offset") offset = self["offset"].value if offset == 0: return data_offsets = [] while (self.absolute_address + self.current_size) // 8 < offset: chunk = UInt32(self, "data_offset[]", "Data offset") yield chunk if chunk.value == 0: break data_offsets.append(chunk) if (self.absolute_address + self.current_size) // 8 != offset: raise ParserError("Problem with level offset.") previous = offset for chunk in data_offsets: data_offset = chunk.value size = data_offset - previous yield RawBytes(self, "data[]", size, "Data content of %s" % chunk.name) previous = data_offset
def createFields(self): yield PropID(self, "id") yield PropID(self, "folder_marker") assert self['folder_marker'].value == kFolder yield SZUInt64(self, "num_folders") # Get generic info num = self["num_folders"].value self.info("%u folders" % num) yield UInt8(self, "is_external") if self['is_external'].value: yield SZUInt64(self, "folder_data_offset", "Offset to folder data within data stream") else: # Read folder items for folder_index in range(num): yield Folder(self, "folder[]") yield PropID(self, "unpacksize_marker") assert self['unpacksize_marker'].value == kCodersUnPackSize for folder_index in range(num): folder = self["folder[%u]" % folder_index] for index in range(folder.out_streams): yield SZUInt64(self, "unpack_size[%d][%d]" % (folder_index, index)) # Extract digests while not self.eof: uid = ReadNextByte(self) if uid == kEnd: yield PropID(self, "end_marker") break elif uid == kCRC: yield Digests(self, "digests", num) else: raise ParserError("Unexpected ID (%i)" % uid)
def parseAVIStreamHeader(self): if self["size"].value != 56: raise ParserError("Invalid stream header size") yield String(self, "stream_type", 4, "Stream type four character code", charset="ASCII") field = String(self, "fourcc", 4, "Stream four character code", strip=" \0", charset="ASCII") if self["stream_type"].value == "vids": yield Enum(field, video_fourcc_name, lambda text: text.upper()) else: yield field yield UInt32(self, "flags", "Stream flags") yield UInt16(self, "priority", "Stream priority") yield String(self, "language", 2, "Stream language", charset="ASCII", strip="\0") yield UInt32(self, "init_frames", "InitialFrames") yield UInt32(self, "scale", "Time scale") yield UInt32(self, "rate", "Divide by scale to give frame rate") yield UInt32(self, "start", "Stream start time (unit: rate/scale)") yield UInt32(self, "length", "Stream length (unit: rate/scale)") yield UInt32(self, "buf_size", "Suggested buffer size") yield UInt32(self, "quality", "Stream quality") yield UInt32(self, "sample_size", "Size of samples") yield UInt16(self, "left", "Destination rectangle (left)") yield UInt16(self, "top", "Destination rectangle (top)") yield UInt16(self, "right", "Destination rectangle (right)") yield UInt16(self, "bottom", "Destination rectangle (bottom)")
def createFields(self): yield UInt16(self, "count", "Number of entries") count = self["count"].value if count == 0: raise ParserError("IFDs cannot be empty.") for i in range(count): yield self.EntryClass(self, "entry[]") yield UInt32(self, "next", "Offset to next IFD") for i in range(count): entry = self['entry[%d]' % i] if 'offset' not in entry: continue self.seekByte(entry['offset'].value + self.base_addr // 8, relative=False) count = entry['count'].value name = "value[%s]" % i if issubclass(entry.value_cls, Bytes): yield entry.value_cls(self, name, count) else: if count > 1: name += "[]" for i in range(count): yield entry.value_cls(self, name)
def createFields(self): yield String(self, "signature", 4, "8BIM signature", charset="ASCII") if self["signature"].value != "8BIM": raise ParserError( "Stream doesn't look like 8BIM item (wrong signature)!") yield textHandler(UInt16(self, "tag"), hexadecimal) if self.stream.readBytes(self.absolute_address + self.current_size, 4) != b"\0\0\0\0": yield PascalString8(self, "name") size = 2 + (self["name"].size // 8) % 2 yield NullBytes(self, "name_padding", size) else: yield String(self, "name", 4, strip="\0") yield UInt16(self, "size") size = alignValue(self["size"].value, 2) if not size: return if self.handler: if issubclass(self.handler, FieldSet): yield self.handler(self, "content", size=size * 8) else: yield self.handler(self, "content") else: yield RawBytes(self, "content", size)
def writeFieldsIn(self, old_field, address, new_fields): """ Can only write in existing fields (address < self._current_size) """ # Check size total_size = sum(field.size for field in new_fields) if old_field.size < total_size: raise ParserError( \ "Unable to write fields at address %s " \ "(too big)!" % (address)) # Need padding before? replace = [] size = address - old_field.address assert 0 <= size if 0 < size: padding = createPaddingField(self, size) padding._address = old_field.address replace.append(padding) # Set fields address for field in new_fields: field._address = address address += field.size replace.append(field) # Need padding after? size = (old_field.address + old_field.size) - address assert 0 <= size if 0 < size: padding = createPaddingField(self, size) padding._address = address replace.append(padding) self.replaceField(old_field.name, replace)
def _feedLinks(self): while self._first is None and self.readMoreFields(1): pass if self._first is None: raise ParserError("first is None") return self
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)
def createFields(self): yield textHandler(Bits(self, "blockheader", 48, "Block header"), hexadecimal) if self["blockheader"].value != 0x314159265359: # pi raise ParserError("Invalid block header!") yield textHandler(UInt32(self, "crc32", "CRC32 for this block"), hexadecimal) yield Bit(self, "randomized", "Is this block randomized?") yield Bits(self, "orig_bwt_pointer", 24, "Starting pointer into BWT after untransform") yield GenericVector( self, "huffman_used_map", 16, Bit, 'block_used', "Bitmap showing which blocks (representing 16 literals each) are in use" ) symbols_used = [] for index, block_used in enumerate( self["huffman_used_map"].array('block_used')): if block_used.value: start_index = index * 16 field = Bzip2Bitmap( self, "huffman_used_bitmap[%i]" % index, 16, start_index, "Bitmap for block %i (literals %i to %i) showing which symbols are in use" % (index, start_index, start_index + 15)) yield field for i, used in enumerate(field): if used.value: symbols_used.append(start_index + i) yield Bits(self, "huffman_groups", 3, "Number of different Huffman tables in use") yield Bits(self, "selectors_used", 15, "Number of times the Huffman tables are switched") yield Bzip2Selectors(self, "selectors_list", self["huffman_groups"].value) trees = [] for group in range(self["huffman_groups"].value): field = Bzip2Lengths(self, "huffman_lengths[]", len(symbols_used) + 2) yield field trees.append(field.tree) counter = 0 rle_run = 0 selector_tree = None while True: if counter % 50 == 0: select_id = self["selectors_list"].array("selector_list")[ counter // 50].realvalue selector_tree = trees[select_id] field = HuffmanCode(self, "huffman_code[]", selector_tree) if field.realvalue in [0, 1]: # RLE codes if rle_run == 0: rle_power = 1 rle_run += (field.realvalue + 1) * rle_power rle_power <<= 1 field._description = "RLE Run Code %i (for %r); Total accumulated run %i (Huffman Code %i)" % ( field.realvalue, chr( symbols_used[0]), rle_run, field.value) elif field.realvalue == len(symbols_used) + 1: field._description = "Block Terminator (%i) (Huffman Code %i)" % ( field.realvalue, field.value) yield field break else: rle_run = 0 move_to_front(symbols_used, field.realvalue - 1) field._description = "Literal %r (value %i) (Huffman Code %i)" % ( chr(symbols_used[0]), field.realvalue, field.value) yield field if field.realvalue == len(symbols_used) + 1: break counter += 1
def readBoolean(self, content_size): if content_size != 1: raise ParserError("Overlong boolean: got %s bytes, expected 1 byte" % content_size) yield textHandler(UInt8(self, "value"), lambda field: str(bool(field.value)))
def createFields(self): superblock = self["/superblock"] # Compute number of block and inodes block_count = superblock["blocks_per_group"].value inode_count = superblock["inodes_per_group"].value block_index = self.descriptor.uniq_id * block_count inode_index = self.descriptor.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) bitmap_block_size = self.root.block_size * 8 block_bitmap_size = (block_count + bitmap_block_size - 1) // bitmap_block_size * bitmap_block_size inode_bitmap_size = (inode_count + bitmap_block_size - 1) // bitmap_block_size * bitmap_block_size self.seekBlock(self.descriptor["block_bitmap"].value) yield BlockBitmap(self, "block_bitmap", block_index, block_count, block_bitmap_size, "Block bitmap") self.seekBlock(self.descriptor["inode_bitmap"].value) yield InodeBitmap(self, "inode_bitmap", inode_index, inode_count, inode_bitmap_size, "Inode bitmap") self.seekBlock(self.descriptor["inode_table"].value) yield InodeTable(self, "inode_table", inode_index, inode_count) inode_bitmap = self['inode_bitmap'] for i, inode in enumerate(self['inode_table'].array('inode')): if not inode_bitmap['item[%d]' % i].value: continue if inode['blocks'].value == 0: continue blocks = inode.array('block') if inode['mode/file_type'].display == 'Directory': parser = Directory else: parser = None group = FragmentGroup(parser=parser) for b in range(12): if not blocks[b].value: continue self.seekBlock(blocks[b].value) yield CustomFragment(self, "inode[%d]block[]" % i, self.root.block_size * 8, None, group=group) if blocks[12].value: # indirect block self.seekBlock(blocks[12].value) indirect = IndirectBlock(self, "inode[%d]indirect" % i, self.root.block_size) yield indirect for b in indirect.array('block'): if not b.value: continue self.seekBlock(b.value) yield CustomFragment(self, "inode[%d]block[]" % i, self.root.block_size * 8, None, group=group) if blocks[13].value: # TODO: double-indirect block pass if blocks[14].value: # TODO: triple-indirect block pass
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 padding = paddingSize(self.current_size + self.absolute_address, 8) # align on byte boundary 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!") if self["len"].value: # null stored blocks produced by some encoders (e.g. PIL) 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 xrange(144): length_tree[(8, i + 48)] = i for i in xrange(144, 256): length_tree[(9, i + 256)] = i for i in xrange(256, 280): length_tree[(7, i - 256)] = i for i in xrange(280, 288): length_tree[(8, i - 88)] = i for i in xrange(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 getCharset(field): try: key = field.value return ID3_StringCharset.charset_name[key] except KeyError: raise ParserError("ID3v2: Invalid charset (%s)." % key)