def parse_data_record(self, n, data, parent): (para, off) = rdata(data, 2, '>H') off += 2 (typ, off) = rdata(data, off, 'B') typ_str = None if int(typ) < len(plucker_type): typ_str = ' (%s)' % plucker_type[int(typ)] reciter = add_pgiter(self.page, 'Record %d%s' % (n, typ_str), 'pdb', 'plucker_record', data, parent) if typ == 0 or typ == 1: # read para headers off = 8 paraiter = add_pgiter(self.page, 'Paragraphs', 'pdb', 0, data[off:off + 4 * int(para)], reciter) for i in range(int(para)): (size, off) = rdata(data, off, '>H') (attrs, off) = rdata(data, off, '>H') add_pgiter(self.page, 'Paragraph %d' % i, 'pdb', 'plucker_para', data[off - 4:off], paraiter) text = data[off:len(data)] if typ == 0: add_pgiter(self.page, 'Text', 'pdb', 0, text, reciter) elif typ == 1: if self.version == 1: uncompressed = lz77_decompress(text) add_pgiter(self.page, 'Text', 'pdb', 0, uncompressed, reciter) elif self.version == 2: uncompressed = zlib.decompress(text) add_pgiter(self.page, 'Text', 'pdb', 0, uncompressed, reciter)
def parse_text_frame(self, data, parent): off = self._parse_object(data, 0, parent) off = self._parse_object(data, off, parent) off = self._parse_object(data, off, parent) add_pgiter(self.page, 'Bounding box', 'zmf', 'zmf2_bbox', data[off:off + 0x20], parent) off += 0x20 (count, off) = rdata(data, off, '<I') chars = [] chars_len = 0 i = 0 while i < int(count): (length, off) = rdata(data, off, '<I') i += 1 chars.append(data[off - 4:off + int(length)]) chars_len += 4 + int(length) off += int(length) charsiter = add_pgiter(self.page, 'Characters', 'zmf', 0, data[off:off + chars_len], parent) i = 0 while i != len(chars): add_pgiter(self.page, 'Character %d' % (i + 1), 'zmf', 'zmf2_character', chars[i], charsiter) i += 1 return off
def parse(self): assert len(self.data) > 0x40 add_pgiter(self.page, 'Header', 'c602', 'tc6_header', self.data[0:0x46], self.parent) off = 0x46 while off + 3 <= len(self.data): (rec, off) = rdata(self.data, off, '<B') (length, off) = rdata(self.data, off, '<H') if tc6_records.has_key(rec): assert len(tc6_records[rec]) >= 2 name = tc6_records[rec][0] handler = tc6_records[rec][1] if len(tc6_records[rec]) > 2: (id, dummy) = rdata(self.data, off, '<H') name += ' [%d]' % id else: name = 'Record %x' % rec handler = None if not handler: handler = 'tc6_record' reciter = add_pgiter(self.page, name, 'c602', handler, self.data[off - 3:off + length], self.parent) if rec == 0x23: chart = gc6_parser(self.page, self.data[off:off + length], self.parent) chart.parse_chart(3, reciter) off += length
def read_stream(self, data, parent): callback = 0 if self.stream_states[-1].stream_flags == 0x100: callback = 'compressed_stream' strmiter = add_pgiter(self.page, 'Stream', 'lrf', callback, data, parent) # data = self.decrypt_stream(self.data[start:start + length]) # add_pgiter(self.page, '[Unobfuscated]', 'lrf', 0, data, strmiter) content = data content_name = 'Content' # TODO: This is speculative. I think that actually the lower # byte contains type (e.g., image types, ToC, tags) and only the # higher byte is flags (or flag). It seems that 0x1 means # 'compressed'. if self.stream_states[-1].stream_flags == 0x100: (uncompressed_size, off) = rdata(data, 0, '<I') try: content = zlib.decompress(data[off:]) content_name = 'Uncompressed content' assert len(content) == uncompressed_size except zlib.error: pass callback = 0 if self.stream_states[-1].stream_flags == 0x51: callback = 'toc' cntiter = add_pgiter(self.page, content_name, 'lrf', callback, content, strmiter) self.stream_level += 1 if len(content) > 1 and ord(content[1]) == 0xf5: self.read_object_tags(content, cntiter) self.stream_level -= 1 self.stream_states[-1].stream_read = True
def read_thumbnail(self): start = self.header_size + self.metadata_size end = start + self.thumbnail_size typ = "Unknown" if lrf_thumbnail_types.has_key(self.thumbnail_type): typ = lrf_thumbnail_types[self.thumbnail_type] add_pgiter(self.page, 'Thumbnail (%s)' % typ, 'lrf', 0, self.data[start:end], self.parent)
def parse_data_record(self, n, data, parent): reciter = add_pgiter(self.page, "Record %d" % n, 'pdb', 0, data, parent) if self.compression == 2: uncompressed = lz77_decompress(data) add_pgiter(self.page, "Uncompressed", 'pdb', 0, uncompressed, reciter)
def parse_palette(page, data, offset, parent): (length, off) = rdata(data, offset, '<I') length = int(length) data = data[off - 4:off + length] palette_iter = add_pgiter(page, 'Color Palette', 'zbr', 'color_palette', data, parent) add_pgiter(page, 'Palette', 'zbr', 'palette', data[4:], palette_iter) return off + length
def handle_tile_row(parser, page, data, parent): data = parser.tile_row_data offsets = sorted(parser.tile_row_offsets.keys()) for (start, end) in zip(offsets, offsets[1:] + [len(data)]): add_pgiter(page, 'Column %d' % parser.tile_row_offsets[start], 'iwa', 'iwa_tile_row', data[start:end], parser.tile_row_iter) parser.tile_row_data = '' parser.tile_row_offsets = {}
def parse_configuration(self, off): (length, off) = rdata(self.data, off, '<I') length = int(length) data = self.data[off - 4:off + length] confiter = add_pgiter(self.page, 'Configuration', 'zbr', 'configuration', data, self.fileiter) add_pgiter(self.page, 'Local configuration', 'zbr', 'config_local', data[4:], confiter) return off + length
def parse_data_record(self, n, data, parent): reciter = add_pgiter(self.page, "Record %d" % n, 'pdb', 0, data, parent) if self.compression == 4: unscrambled = [(chr(ord(b) ^ 0xa5)) for b in data] add_pgiter(self.page, "Uncompressed", 'pdb', 0, unscrambled, reciter)
def do_show(self, page, data, parent): iter = self.add_pgiter(page, 'Dictionary', '', data, parent) something = data[self.start:self.start + 2 * self.count * struct.calcsize(self.something_fmt)] add_pgiter(page, 'Something', 'plist', '', something, iter) self.show_values(page, 'Keys', data, iter, self.value[0]) self.show_values(page, 'Values', data, iter, self.value[1])
def parse_preview(page, data, offset, parent): off = offset previter = add_pgiter(page, 'Preview bitmap', 'zbr', 0, data[off:off + 5264], parent) add_pgiter(page, 'DIB palette', 'zbr', 'palette', data[off:off + 64], previter) off += 64 dibiter = add_pgiter(page, 'DIB data', 'zbr', 0, data[off:off + 5200], previter) return off + 5200
def parse_configuration(page, data, offset, parent): (length, off) = rdata(data, offset, '<I') length = int(length) data = data[off - 4:off + length] confiter = add_pgiter(page, 'Configuration', 'zbr', 'configuration', data, parent) add_pgiter(page, 'Local configuration', 'zbr', 'config_local', data[4:], confiter) return off + length
def parse_data_record(self, n, data, parent): (para, off) = rdata(data, 2, '>H') off += 2 (typ, off) = rdata(data, off, 'B') typ_str = None if int(typ) < len(plucker_type): typ_str = ' (%s)' % plucker_type[int(typ)] reciter = add_pgiter(self.page, 'Record %d%s' % (n, typ_str), 'palm', 'plucker_record', data, parent) if typ == 0 or typ == 1: # read para headers off = 8 paraiter = add_pgiter(self.page, 'Paragraphs', 'palm', 0, data[off:off + 4 * int(para)], reciter) for i in range(int(para)): (size, off) = rdata(data, off, '>H') (attrs, off) = rdata(data, off, '>H') add_pgiter(self.page, 'Paragraph %d' % i, 'palm', 'plucker_para', data[off - 4:off], paraiter) text = data[off:len(data)] if typ == 0: add_pgiter(self.page, 'Text', 'palm', 0, text, reciter) elif typ == 1: if self.version == 1: uncompressed = lz77_decompress(text) add_pgiter(self.page, 'Text', 'palm', 0, uncompressed, reciter) elif self.version == 2: uncompressed = zlib.decompress(text) add_pgiter(self.page, 'Text', 'palm', 0, uncompressed, reciter)
def parse_palette(self, off): (length, off) = rdata(self.data, off, '<I') length = int(length) data = self.data[off - 4:off + length] palette_iter = add_pgiter(self.page, 'Color Palette', 'zbr', 'color_palette', data, self.fileiter) add_pgiter(self.page, 'Palette', 'zbr', 'palette', data[4:], palette_iter) return off + length
def parse_table(self, data, parent): off = self._parse_object(data, 0, parent) off = self._parse_object(data, off, parent) off = self._parse_object(data, off, parent) add_pgiter(self.page, 'Bounding box', 'zmf', 'zmf2_bbox', data[off:off + 0x20], parent) off += 0x20 add_pgiter(self.page, 'Def', 'zmf', 'zmf2_table', data[off:], parent) return off
def parse_header(self, offset): if self.page: add_pgiter(self.page, 'Header', 'bmi', 'header', self.data[offset:offset + 0x15], self.parent) (palette, off) = rdata(self.data, offset + 0xd, '<H') (depth, off) = rdata(self.data, off, '<H') off += 2 (count, off) = rdata(self.data, off, '<H') return (off, bool(palette), depth, count)
def parse_color(self, data, parent): (length, off) = rdata(data, 0xd, '<I') name_str = 'Color' if length > 1: (name, off) = rdata(data, off, '%ds' % (int(length) - 1)) name_str += ' (%s)' % unicode(name, 'cp1250') add_pgiter(self.page, name_str, 'zmf', 'zmf2_color', data, parent) return len(data)
def parse(self): add_pgiter(self.page, 'Header', 'c602', 'gc6_header', self.data[0:0x40], self.parent) off = 0x40 add_pgiter(self.page, 'Preamble', 'c602', 'gc6_preamble', self.data[off:off + 9], self.parent) off += 9 self.parse_chart(off, self.parent)
def parse_header(self): (offset, off) = rdata(self.data, 0x20, '<I') (preview, off) = rdata(self.data, off, '<I') if int(preview) != 0: self.preview_offset = int(preview) - int(offset) assert self.preview_offset == 0x20 # this is what I see in all files data = self.data[0:int(offset)] add_pgiter(self.page, 'Header', 'zmf', 'zmf4_header', data, self.parent) return offset
def parse_index_record(self, data, parent): off = 0 (self.version, off) = rdata(data, off, '>H') (self.record_count, off) = rdata(data, off, '>H') (self.text_length, off) = rdata(data, off, '>I') (self.record_size, off) = rdata(data, off, '>H') off += 8 (self.compression, off) = rdata(data, off, 'B') add_pgiter(self.page, 'Index', 'palm', 'ztxt_index', data, parent)
def handle_footnotes(page, data, parent, parser=None): (count, off) = rdata(data, 0, '<I') entry_size = 24 # FIXME: a guess off += 8 for i in range(0, count): add_pgiter(page, 'Footnote %d' % i, 'wt602', '', data[off:off + entry_size], parent) off += entry_size if off < len(data): add_pgiter(page, 'Trailer', 'wt602', '', data[off:], parent)
def handle_styles(page, data, parent, parser = None): (hdrsize, off) = rdata(data, 0, '<I') count = hdrsize / 0x20 off = 0x10 hdriter = add_pgiter(page, 'Names', 'wt602', 0, data[:hdrsize + 0x10], parent) for i in range(0, count): add_pgiter(page, 'Style %d' % i, 'wt602', 'style_header', data[off:off + 0x20], hdriter) off += 0x20 add_pgiter(page, 'Definitions', 'wt602', 0, data[hdrsize + 0x10:], parent)
def parse_streams(self): for stream in self.streams: start = stream[0] end = stream[1] tag = stream[2] if tag in stream_parsers: stream_parsers[tag](self, stream_tags[tag], start, end - start) elif tag != 0xff: add_pgiter(self.page, 'Unknown', 'bmi', '', self.data[start:end], self.parent)
def parse_index_record(self, data, parent): off = 0 (self.version, off) = rdata(data, off, '>H') (self.record_count, off) = rdata(data, off, '>H') (self.text_length, off) = rdata(data, off, '>I') (self.record_size, off) = rdata(data, off, '>H') off += 8 (self.compression, off) = rdata(data, off, 'B') add_pgiter(self.page, 'Index', 'pdb', 'ztxt_index', data, parent)
def parse_preview(self, off): previter = add_pgiter(self.page, 'Preview bitmap', 'zbr', 0, self.data[off:off + 5264], self.fileiter) add_pgiter(self.page, 'DIB palette', 'zbr', 'palette', self.data[off:off + 64], previter) off += 64 dibiter = add_pgiter(self.page, 'DIB data', 'zbr', 0, self.data[off:off + 5200], previter) return off + 5200
def parse_header(self): (count, off) = rdata(self.data, 76, '>H') hdriter = add_pgiter(self.page, 'Header', 'palm', 'palm_header', self.data[0:76 + 4 * count], self.parent) offiter = add_pgiter(self.page, 'Offset table', 'palm', 0, self.data[76:76 + 4 * count], hdriter) for i in range(0, count): add_pgiter(self.page, 'Offset %d' % i, 'palm', 'palm_offset', self.data[off:off + 8], offiter) (record, off) = rdata(self.data, off, '>I') off += 4 self.records.append(record)
def parse_header(self): (count, off) = rdata(self.data, 76, '>H') hdriter = add_pgiter(self.page, 'Header', 'pdb', 'pdb_header', self.data[0:76 + 4 * count], self.parent) offiter = add_pgiter(self.page, 'Offset table', 'pdb', 0, self.data[76:76 + 4 * count], hdriter) for i in range(0, count): add_pgiter(self.page, 'Offset %d' % i, 'pdb', 'pdb_offset', self.data[off:off + 8], offiter) (record, off) = rdata(self.data, off, '>I') off += 4 self.records.append(record)
def parse_index_record(self, data, parent): reciter = add_pgiter(self.page, 'Index', 'pdb', 'plucker_index', data, parent) off = 2 (self.version, off) = rdata(data, off, '>H') (records, off) = rdata(data, off, '>H') for i in range(int(records)): (name, off) = rdata(data, off, '>H') (ident, off) = rdata(data, off, '>H') self.reserved_records[ident] = name record_data = data[off - 4:off] add_pgiter(self.page, 'Reserved record %d' % i, 'pdb', 'plucker_record_index', record_data, reciter)
def parse_index_record(self, data, parent): reciter = add_pgiter(self.page, 'Index', 'palm', 'plucker_index', data, parent) off = 2 (self.version, off) = rdata(data, off, '>H') (records, off) = rdata(data, off, '>H') for i in range(int(records)): (name, off) = rdata(data, off, '>H') (ident, off) = rdata(data, off, '>H') self.reserved_records[ident] = name record_data = data[off - 4:off] add_pgiter(self.page, 'Reserved record %d' % i, 'palm', 'plucker_record_index', record_data, reciter)
def handle_strings(page, data, parent, parser = None): (hdrsize, off) = rdata(data, 0, '<I') off = 0x10 hdriter = add_pgiter(page, 'Definitions', 'wt602', 0, data[:hdrsize + 0x10], parent) i = 0 while off < hdrsize + 0x10: start = off (length, off) = rdata(data, off + 4, '<H') off = start + length add_pgiter(page, 'String %d' % i, 'wt602', 'string_header', data[start:off], hdriter) i += 1 add_pgiter(page, '???', 'wt602', 0, data[hdrsize + 0x10:], parent)
def handle_fonts(page, data, parent, parser = None): (count, off) = rdata(data, 0, '<I') for i in range(0, count): start = off off += 2 # read font name while off < len(data) and data[off] != '\0': off += 1 # read zeros to the next record while off < len(data) and data[off] == '\0': off += 1 add_pgiter(page, 'Font %d' % i, 'wt602', 'font', data[start:off], parent)
def zmf2_open(page, data, parent, fname): file_map = { 'BitmapDB.zmf': ZMF2Parser.parse_bitmap_db_doc, 'TextStyles.zmf': ZMF2Parser.parse_text_styles_doc, 'Callisto_doc.zmf': ZMF2Parser.parse_doc, 'Callisto_pages.zmf': ZMF2Parser.parse_pages_doc, } if fname == 'Header': add_pgiter(page, 'Header', 'zmf', 'zmf2_header', data, parent) elif file_map.has_key(fname): if data != None: parser = ZMF2Parser(data, page, parent, file_map[fname]) parser.parse()
def handle_tabs(page, data, parent, parser=None): off = 0 (count, off) = rdata(data, off, '<H') tab_size = 16 off += 8 for i in range(0, count): add_pgiter(page, 'Tabs %d' % i, 'wt602', 'tabs_def', data[off:off + tab_size], parent) off += tab_size stops_iter = add_pgiter(page, 'Tab stops', 'wt602', 'container', data[off:], parent) (stops, off) = rdata(data, off, '<H') for i in range(0, stops): end = off + 4 * (i + 1) add_pgiter(page, 'Tab stops %d' % i, 'wt602', 'tab_stop', data[off:end], stops_iter) off = end
def _parse_object(self, data, offset, parent, name=None, handler=None): off = offset (size, off) = rdata(data, offset, '<I') name_str = name # TODO: this is highly speculative (typ, off) = rdata(data, off, '<I') (subtyp, off) = rdata(data, off, '<I') count = 0 if typ == 4 and subtyp == 3: header_size = 0x18 off += 4 (obj, off) = rdata(data, off, '<I') if not handler and zmf2_handlers.has_key(int(obj)): handler = zmf2_handlers[int(obj)] if zmf2_objects.has_key(int(obj)): name_str = '%s object' % zmf2_objects[int(obj)] elif typ == 4 and subtyp == 4: header_size = 0x14 off += 4 (count, off) = rdata(data, off, '<I') name_str = name + 's' elif typ == 8 and subtyp == 5: header_size = 0x1c off += 8 (count, off) = rdata(data, off, '<I') else: header_size = 0 if not name_str: name_str = 'Unknown object' objiter = add_pgiter(self.page, name_str, 'zmf', 0, data[offset:offset + int(size)], parent) if header_size != 0: add_pgiter(self.page, 'Header', 'zmf', 'zmf2_obj_header', data[offset:offset + header_size], objiter) content_data = data[offset + header_size:offset + int(size)] if handler: content_offset = handler(self, content_data, objiter) elif int(count) > 0: content_offset = self._parse_object_list(content_data, objiter, int(count), name) else: content_offset = 0 if content_offset < len(content_data): add_pgiter(self.page, 'Unknown content', 'zmf', 0, content_data[content_offset:], objiter) return offset + int(size)
def handle_char_styles(page, data, parent, parser = None): off = 8 (count, off) = rdata(data, off, '<H') ids = [] off = len(data) - 2 * count start_ids = off - 2 while off < len(data): (id, off) = rdata(data, off, '<H') ids.append(id) off = 8 fmt_size = 28 start_styles = off + 2 + fmt_size * count attrsiter = add_pgiter(page, 'Attr. sets', 'wt602', 'container', data[off:start_styles], parent) off += 2 for (n, id) in zip(range(0, count), ids): add_pgiter(page, 'Attr. set %d (ID: %d)' % (n, id), 'wt602', 'attrset', data[off:off + fmt_size], attrsiter) off += fmt_size assert(off == start_styles) descsiter = add_pgiter(page, 'Styles', 'wt602', 'container', data[off:start_ids], parent) off += 2 n = 0 while off < start_ids: add_pgiter(page, 'Style %d' % n, 'wt602', 'style', data[off:off + 6], descsiter) off += 6 n += 1 # assert(off == start_ids) add_pgiter(page, 'ID map', 'wt602', 'attrset_ids', data[start_ids:], parent)
def handle_text_infos(page, data, parent, parser): (count, off) = rdata(data, 0, '<I') off += 6 text_section = parser.sections[27] text = parser.data[text_section[0] + 4:text_section[1]] text_begin = 0 for i in range(0, count): begin = off spaniter = add_pgiter(page, 'Span %d ' %i, 'wt602', 'text_info', data[begin:begin + 28], parent) text_length = read(data, begin + 0xe, '<H') if text_length > 0: add_pgiter(page, 'Text', 'wt602', 'span_text', text[text_begin:text_begin + text_length], spaniter) text_begin += text_length off += 28
def parse_content(self, begin): data = self.data[begin:] content_iter = add_pgiter(self.page, 'Content', 'zmf', 0, data, self.parent) if self.preview_offset == 0: self._parse_group(data, content_iter) else: self._parse_group(data[0:self.preview_offset], content_iter) (typ, off) = rdata(data, self.preview_offset, '2s') # TODO: possibly there are other types? assert typ == 'BM' (size, off) = rdata(data, off, '<I') assert int(size) < len(data) add_pgiter(self.page, 'Bitmap data', 'zmf', 'zmf4_bitmap', data[self.preview_offset:self.preview_offset + int(size)], content_iter) self._parse_group(data[self.preview_offset + int(size):], content_iter)
def read_header(self): data = self.data self.version = read(data, 8, '<H') self.pseudo_encryption_key = read(data, 0xa, '<H') self.object_count = read(data, 0x10, '<Q') self.object_index_offset = read(data, 0x18, '<Q') (self.metadata_size, off) = rdata(data, 0x4c, '<H') if (self.version > 800): (self.thumbnail_type, off) = rdata(data, off, '<H') (self.thumbnail_size, off) = rdata(data, off, '<I') self.header_size = off add_pgiter(self.page, 'Header', 'lrf', 'header', data[0:off], self.parent)
def add_pgiter(self, name, parser, data, offset, length=None): if not length: length = len(data) - offset pgiter = utils.add_pgiter(self.page, name, self.ftype, (parser, self.context), data[offset:offset + length], self.iter) view = PageView(self.page, self.ftype, pgiter, self.context, data, offset) return parser(view, data, offset, length)
def parse(self): self.fileiter = add_pgiter(self.page, 'ZBR', 'zbr', 0, self.data, self.parent) off = self.parse_header() off = self.parse_preview(off) off = self.parse_configuration(off) off = self.parse_palette(off) self.parse_objects(off)
def parse_bitmap_db_doc(self, data, parent): bitmaps_iter = add_pgiter(self.page, 'Bitmaps', 'zmf', 'zmf2_bitmap_db', data, parent) off = 4 i = 1 while off < len(data): off = self._parse_object(data, off, bitmaps_iter, 'Bitmap %d' % i) i += 1