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 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 add_style_para(hd, size, data): off = 0 (attribs, off) = rdata(data, off, '<H') # add_iter(hd, 'Changed attributes', '%s' % get_para_style(attribs), off - 2, 2, '<H') off += 2 (attrset, off) = rdata(data, off, '<H') add_iter(hd, 'Attribute set', attrset, off - 2, 2, '<H')
def add_string(hd, size, data, off, name, fmt): fmtlen = struct.calcsize(fmt) (length, off) = rdata(data, off, fmt) add_iter(hd, '%s length' % name, length, off - fmtlen, fmtlen, fmt) (text, off) = rdata(data, off, '%ds' % length) add_iter(hd, name, unicode(text, 'cp1250'), off - length, length, '%ds' % length) return off
def add_comment(hd, size, data, off): (row, off) = rdata(data, off, '<H') add_iter(hd, 'Row', format_row(row), off - 2, 2, '<H') (col, off) = rdata(data, off, '<B') add_iter(hd, 'Column', format_column(col), off - 1, 1, '<B') off += 1 add_long_string(hd, size, data, off, 'Comment')
def add_obj_rectangle(view, data, offset): off = _add_obj_shape(view, data, offset) # TODO: It's not clear if the dims are relative to canvas or to the # shape's origin. All rectangles I've seen've had offset (0, 0). (tl_x, off) = rdata(data, off, '<i') view.add_iter('Top left corner X', tl_x, off - 4, 4, '<i') (tl_y, off) = rdata(data, off, '<i') view.add_iter('Top left corner Y', tl_y, off - 4, 4, '<i') (tr_x, off) = rdata(data, off, '<i') view.add_iter('Top right corner X', tr_x, off - 4, 4, '<i') (tr_y, off) = rdata(data, off, '<i') view.add_iter('Top right corner Y', tr_y, off - 4, 4, '<i') (br_x, off) = rdata(data, off, '<i') view.add_iter('Bottom right corner X', br_x, off - 4, 4, '<i') (br_y, off) = rdata(data, off, '<i') view.add_iter('Bottom right corner Y', br_y, off - 4, 4, '<i') (bl_x, off) = rdata(data, off, '<i') view.add_iter('Bottom left corner X', bl_x, off - 4, 4, '<i') (bl_y, off) = rdata(data, off, '<i') view.add_iter('Bottom left corner Y', bl_y, off - 4, 4, '<i') corner_types = {1: 'normal', 2: 'round', 3: 'round in', 4: 'cut'} (corner, off) = rdata(data, off, '<H') view.add_iter('Corner type', key2txt(corner, corner_types), off - 2, 2, '<H') (rounding, off) = rdata(data, off, '<H') view.add_iter('Rounding', '%.3fin' % (rounding * 0.02028), off - 2, 2, '<H') off = _add_point_list(view, data, off) 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 add_cell(hd, size, data): off = add_record(hd, size, data) (col, off) = rdata(data, off, '<B') add_iter(hd, 'Column', format_column(col), off - 1, 1, '<B') (row, off) = rdata(data, off, '<H') add_iter(hd, 'Row', format_row(row), off - 2, 2, '<H') return (off, col, row)
def parse_bitmap(self, name, offset, length): bmpiter = add_pgiter(self.page, name, 'bmi', '', self.data[offset:offset + length], self.parent) uncompressed_data = bytearray() add_pgiter(self.page, 'Header', 'bmi', 'bitmap_header', self.data[offset:offset + 16], bmpiter) (width, off) = rdata(self.data, offset, '<H') (height, off) = rdata(self.data, off, '<H') (depth, off) = rdata(self.data, off, '<H') (palette, off) = rdata(self.data, off, '<H') off += 8 if depth <= 8 and bool(palette): off = self.parse_palette(off, depth, bmpiter) rawiter = add_pgiter(self.page, 'Raw data', 'bmi', 0, self.data[off:offset + length], bmpiter) i = 1 while off < offset + length: (blen, off) = rdata(self.data, off, '<H') off += 1 blockiter = add_pgiter(self.page, 'Block %d' % i, 'bmi', 'block', self.data[off - 3:off + blen], rawiter) compressed = self.data[off:off + blen] add_pgiter(self.page, 'Compressed data', 'bmi', 0, compressed, blockiter) try: uncompressed = zlib.decompress(compressed) add_pgiter(self.page, 'Uncompressed data', 'bmi', 0, uncompressed, blockiter) uncompressed_data.extend(uncompressed) except zlib.error: print('decompression of block %d failed' % i) i += 1 off += blen def parser(hd, size, data): return add_data(hd, size, data, width, height, depth) add_pgiter(self.page, 'Data', 'bmi', parser, str(uncompressed_data), bmpiter)
def add_record(hd, size, data): off = 0 (typ, off) = rdata(data, off, '<B') add_iter(hd, 'Record type', typ, off - 1, 1, '<B') (length, off) = rdata(data, off, '<H') add_iter(hd, 'Record length', length, off - 2, 2, '<H') return off
def add_text(hd, size, data, off, name='Text'): (length, off) = rdata(data, off, '<B') add_iter(hd, '%s length' % name, length, off - 1, 1, '<B') (text, off) = rdata(data, off, '%ds' % length) add_iter(hd, name, unicode(text, 'cp852'), off - length, length, '%ds' % length) return off
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 add_toc(hd, size, data): (count, off) = rdata(data, 0, '<I') add_iter(hd, 'Number of entries', count, off - 4, 4, '<I') offsets = [] for i in range(int(count)): (offset, off) = rdata(data, off, '<I') offsets.append(int(offset)) add_iter(hd, 'Offset of entry %d' % i, offset, off - 4, 4, '<I') offsets.append(size) offsets = [o + off for o in offsets] for i in range(int(count)): off = offsets[i] (page, off) = rdata(data, off, '<I') add_iter(hd, 'Page ID of entry %d' % i, '0x%x' % page, off - 4, 4, '<I') (block, off) = rdata(data, off, '<I') add_iter(hd, 'Block ID of entry %d' % i, '0x%x' % block, off - 4, 4, '<I') (length, off) = rdata(data, off, '<H') add_iter(hd, 'Text length of entry %d' % i, length, off - 2, 2, '<H') text = read_unistr(data, off, int(length)) add_iter(hd, 'Text of entry %d' % i, text, off, int(length), 's')
def add_obj_page(view, data, offset): off = offset + 17 (dimX, off) = rdata(data, off, '<I') view.add_iter('A dimension?', dimX, off - 4, 4, '<I') (dimY, off) = rdata(data, off, '<I') view.add_iter('A dimension?', dimY, off - 4, 4, '<I') # As with ZMF, the page is placed on a canvas and all dimensions are # relative to the canvas. (left_margin, off) = rdata(data, off, '<i') view.add_iter('Left page margin?', left_margin, off - 4, 4, '<i') (top_margin, off) = rdata(data, off, '<i') view.add_iter('Top page margin?', top_margin, off - 4, 4, '<i') (right_margin, off) = rdata(data, off, '<i') view.add_iter('Right page margin?', right_margin, off - 4, 4, '<i') (bottom_margin, off) = rdata(data, off, '<i') view.add_iter('Bottom page margin?', bottom_margin, off - 4, 4, '<i') (width, off) = rdata(data, off, '<I') view.add_iter('Page width', width, off - 4, 4, '<I') (height, off) = rdata(data, off, '<I') view.add_iter('Page height', height, off - 4, 4, '<I') (cwidth, off) = rdata(data, off, '<I') view.add_iter('Canvas width?', cwidth, off - 4, 4, '<I') (cheight, off) = rdata(data, off, '<I') view.add_iter('Canvas height?', cheight, off - 4, 4, '<I') off += 8 return _add_obj_list(view, data, off)
def add_data(hd, size, data, width, height, depth): assert depth in (1, 4, 8, 24) bits = (width * depth) lsize = bits / 8 if bits % 8 != 0: lsize += 1 tail = lsize % 4 padding = 0 if tail != 0: padding = 4 - tail lsize += padding shift = (8 - min(depth, 8)) mask = (0xff >> shift) << shift off = 0 for h in range(1, height + 1): lineiter = add_iter(hd, 'Line %d' % h, '', off, lsize, '%ds' % lsize) i = 1 while i < width + 1: if depth == 24: (color, off) = rdata(data, off, '3s') add_iter(hd, 'Pixel %d (BGR)' % i, d2hex(color), off - 3, 3, '3s', parent=lineiter) i += 1 else: (index, off) = rdata(data, off, '<B') for j in range(0, 8 / depth): add_iter(hd, 'Pixel %d (index)' % i, (index & mask) >> shift, off - 1, 1, '<B', parent=lineiter) index = index << depth i += 1 if i == width + 1: break if padding > 0: add_iter(hd, 'Padding', '', off, padding, '%ds' % padding, parent=lineiter) off += padding
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 add_header(hd, size, data): (sig, off) = rdata(data, 0, '<H') add_iter(hd, 'Signature', '0x%x' % sig, off - 2, 2, '<H') (version, off) = rdata(data, off, '<H') add_iter(hd, 'Version', version, off - 2, 2, '<H') (comment, off) = rdata(data, off, '100s') add_iter(hd, 'Comment', comment, off - 100, 100, '100s') assert off == 104
def add_comment(hd, size, data): off = 2 (comment_len, off) = rdata(data, off, '<I') add_iter(hd, 'Comment length', comment_len, off - 4, 4, '<I') off += 2 (comment, off) = rdata(data, off, '%ds' % (comment_len - 1)) # skip trailing 0 off += 1 add_iter(hd, 'Comment', comment, off - comment_len, comment_len, '%ds' % comment_len)
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 chop_tag_f55c(hd, size, data): (count, off) = rdata(data, 2, '<H') add_iter(hd, 'Page count', count, off - 2, 2, '<H') i = 0 while i != int(count): (pid, off) = rdata(data, off, '<I') add_iter(hd, 'Page %d' % i, '0x%x' % pid, off - 4, 4, '<I') i += 1
def add_page_breaks(hd, size, data, off): (count, off) = rdata(data, off, '<H') add_iter(hd, 'Number of breaks', count, off - 2, 2, '<H') i = 0 while off + 2 <= size: (row, off) = rdata(data, off, '<H') add_iter(hd, 'Break before row [%d]' % i, format_row(row), off - 2, 2, '<H') i += 1
def add_address(off): (row, off) = rdata(data, off, '<H') add_iter(hd, 'Row', format_row(row & 0x3fff), off - 2, 2, '<H') rel = (row >> 14) & 0x3 add_iter(hd, 'Relative', key2txt(rel, rel_map), off - 1, 1, '<B') (col, off) = rdata(data, off, '<B') add_iter(hd, 'Column', format_column(col), off - 1, 1, '<B') return off
def add_string(hd, size, data): off = 0 (c, off) = rdata(data, off, '>B') sz = c & 0xf if sz == 0xf: (sz, off) = read_int(data, off) (string, off) = rdata(data, off, '%ds' % sz) add_iter(hd, 'Value', string, off - sz, sz, '%ds' % sz)
def add_string(hd, size, data): off = 0 (c, off) = rdata(data, off, ">B") sz = c & 0xF if sz == 0xF: (sz, off) = read_int(data, off) (string, off) = rdata(data, off, "%ds" % sz) add_iter(hd, "Value", string, off - sz, sz, "%ds" % sz)
def add_zmf4_obj_text(hd, size, data): _zmf4_obj_common(hd, size, data) off = 0x3c (count, off) = rdata(data, off, '<I') add_iter(hd, 'Length', count, off - 4, 4, '<I') off += 8 length = 2 * int(count) (text, off) = rdata(data, off, '%ds' % length) add_iter(hd, 'Text', unicode(text, 'utf-16le'), off - length, length, '%ds' % length)
def add_row_height(hd, size, data, off): (row, off) = rdata(data, off, '<H') add_iter(hd, 'Row', format_row(row), off - 2, 2, '<H') off += 2 flags_map = {1: 'visible', 2: 'autofilter'} (flags, off) = rdata(data, off, '<H') add_iter(hd, 'Flags', bflag2txt(flags, flags_map), off - 2, 2, '<H') (height, off) = rdata(data, off, '<H') add_iter(hd, 'Height', '%.2fpt' % (height / 20.0), off - 2, 2, '<H')
def add_obj_point(view, data, offset): (x, off) = rdata(data, offset, '<i') view.add_iter('X', x, off - 4, 4, '<i') (y, off) = rdata(data, off, '<i') view.add_iter('Y', y, off - 4, 4, '<i') type_map = {1: 'Line point?', 2: 'Curve point?', 3: 'Curve control point?',} (typ, off) = rdata(data, off, '<B') view.add_iter('Type?', key2txt(typ, type_map), off - 1, 1, '<B') return off
def add_color(hd, size, data): (r, off) = rdata(data, 0, '<B') add_iter(hd, 'Red', r, off - 1, 1, '<B') (g, off) = rdata(data, off, '<B') add_iter(hd, 'Green', g, off - 1, 1, '<B') (b, off) = rdata(data, off, '<B') add_iter(hd, 'Blue', b, off - 1, 1, '<B') (a, off) = rdata(data, off, '<B') add_iter(hd, 'Alpha', a, off - 1, 1, '<B')
def add_utf16(hd, size, data): off = 0 (c, off) = rdata(data, off, ">B") sz = c & 0xF if sz == 0xF: (sz, off) = read_int(data, off) sz = 2 * sz (utf16, off) = rdata(data, off, "%ds" % sz) add_iter(hd, "Value", unicode(utf16, "utf-16be"), off - sz, sz, "%ds" % sz)
def chop_tag_f54a(hd, size, data): (left, off) = rdata(data, 2, '<H') add_iter(hd, 'Left', left, off - 2, 2, '<H') (top, off) = rdata(data, off, '<H') add_iter(hd, 'Top', top, off - 2, 2, '<H') (right, off) = rdata(data, off, '<H') add_iter(hd, 'Right', right, off - 2, 2, '<H') (bottom, off) = rdata(data, off, '<H') add_iter(hd, 'Bottom', bottom, off - 2, 2, '<H')
def add_categories(hd, size, data): off = add_section(hd, size, data) (axis_dir, off) = rdata(data, off, '<B') add_iter(hd, 'Reversed axis direction', bool(axis_dir), off - 1, 1, '<B') (axis_label, off) = rdata(data, off, '<B') add_iter(hd, 'Vertical axis label', bool(axis_label), off - 1, 1, '<B') raster_flags = {1: 'fine', 2: 'coarse'} (raster, off) = rdata(data, off, '<B') add_iter(hd, 'Raster', bflag2txt(raster, raster_flags), off - 1, 1, '<B')
def _add_string(view, data, offset, name): (length, off) = rdata(data, offset, '<I') view.add_iter('%s length' % name, length, off - 4, 4, '<I') if length > 1: (text, off) = rdata(data, off, '%ds' % (length - 1)) view.add_iter(name, unicode(text, 'cp1250'), off - length + 1, length, '%ds' % length) else: view.add_iter(name, '', off, 1, '1s') return off + 1
def add_3d(hd, size, data): off = 0 (desc, off) = rdata(data, off, '<B') add_iter(hd, 'Double description of values', bool(desc), off - 1, 1, '<B') (raster, off) = rdata(data, off, '<B') add_iter(hd, 'Series raster', bool(raster), off - 1, 1, '<B') depth_map = {0: 'small', 1: 'medium', 2: 'large'} (depth, off) = rdata(data, off, '<B') add_iter(hd, 'Series depth', key2txt(depth, depth_map), off - 1, 1, '<B')
def add_autofilter(hd, size, data, off): (start_row, off) = rdata(data, off, '<H') add_iter(hd, 'Start row', format_row(start_row), off - 2, 2, '<H') (start_col, off) = rdata(data, off, '<H') add_iter(hd, 'Start column', format_column(start_col), off - 2, 2, '<H') (end_row, off) = rdata(data, off, '<H') add_iter(hd, 'End row', format_row(end_row), off - 2, 2, '<H') (end_col, off) = rdata(data, off, '<H') add_iter(hd, 'End column', format_column(end_col), off - 2, 2, '<H')
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 add_named_range(hd, size, data): off = add_record(hd, size, data) (id, off) = rdata(data, off, '<H') add_iter(hd, 'ID', id, off - 2, 2, '<H') off = add_text(hd, size, data, off, 'Name') (ordinal, off) = rdata(data, off, '<H') add_iter(hd, 'Ordinal number', ordinal, off - 2, 2, '<H') off += 2 add_formula(hd, size, data, off)
def add_utf16(hd, size, data): off = 0 (c, off) = rdata(data, off, '>B') sz = c & 0xf if sz == 0xf: (sz, off) = read_int(data, off) sz = 2 * sz (utf16, off) = rdata(data, off, '%ds' % sz) add_iter(hd, 'Value', unicode(utf16, 'utf-16be'), off - sz, sz, '%ds' % sz)
def add_cell(hd, size, data, off): (row, off) = rdata(data, off, '<H') add_iter(hd, 'Row', format_row(row), off - 2, 2, '<H') (col, off) = rdata(data, off, '<B') add_iter(hd, 'Column', format_column(col), off - 1, 1, '<B') off += 1 (style, off) = rdata(data, off, '<H') add_iter(hd, 'Style', style, off - 2, 2, '<H') return off
def add_attrset_ids(hd, size, data): off = 0 (count, off) = rdata(data, off, '<H') add_iter(hd, 'Number of attr. sets', count, off - 2, 2, '<H') n = 0 while off < len(data): (id, off) = rdata(data, off, '<H') add_iter(hd, 'ID of attr. set %d' % n, id, off - 2, 2, '<H') n += 1