def is_date_format_string(book, fmt): # Heuristics: # Ignore "text" and [stuff in square brackets (aarrgghh -- see below)]. # Handle backslashed-escaped chars properly. # E.g. hh\hmm\mss\s should produce a display like 23h59m59s # Date formats have one or more of ymdhs (caseless) in them. # Numeric formats have # and 0. # N.B. u'General"."' hence get rid of "text" first. # TODO: Find where formats are interpreted in Gnumeric # TODO: u'[h]\\ \\h\\o\\u\\r\\s' ([h] means don't care about hours > 23) state = 0 s = '' # (to_py3): ignorable = skip_char_dict.has_key for c in fmt: if state == 0: if c == '"': state = 1 elif c in r"\_*": state = 2 elif c in skip_char_dict: # (to_py3): pass else: s += c elif state == 1: if c == '"': state = 0 elif state == 2: # Ignore char after backslash, underscore or asterisk state = 0 assert 0 <= state <= 2 if book.verbosity >= 4: print("is_date_format_string: reduced format is %r" % s) s = fmt_bracketed_sub('', s) if s in non_date_formats: return False state = 0 separator = ";" got_sep = 0 date_count = num_count = 0 for c in s: if c in date_char_dict: date_count += date_char_dict[c] elif c in num_char_dict: num_count += num_char_dict[c] elif c == separator: got_sep = 1 # print num_count, date_count, repr(fmt) if date_count and not num_count: return True if num_count and not date_count: return False if date_count: fprintf(book.logfile, 'WARNING *** is_date_format: ambiguous d=%d n=%d fmt=%r\n', date_count, num_count, fmt) elif not got_sep: fprintf(book.logfile, "WARNING *** format %r produces constant result\n", fmt) return date_count > num_count
def handle_palette(book, data): if not book.formatting_info: return verbose = DEBUG or book.verbosity >= 2 n_colours, = unpack('<H', data[:2]) expected_n_colours = (16, 56)[book.biff_version >= 50] if ((DEBUG or book.verbosity >= 1) and n_colours != expected_n_colours): fprintf(book.logfile, "NOTE *** Expected %d colours in PALETTE record, found %d\n", expected_n_colours, n_colours) elif verbose: fprintf(book.logfile, "PALETTE record with %d colours\n", n_colours) fmt = '<xx%di' % n_colours # use i to avoid long integers expected_size = 4 * n_colours + 2 actual_size = len(data) tolerance = 4 if not expected_size <= actual_size <= expected_size + tolerance: raise XLRDError('PALETTE record: expected size %d, actual size %d' % (expected_size, actual_size)) colours = unpack(fmt, data[:expected_size]) assert book.palette_record == [] # There should be only 1 PALETTE record # a colour will be 0xbbggrr # IOW, red is at the little end for i in range(n_colours): c = colours[i] red = c & 0xff green = (c >> 8) & 0xff blue = (c >> 16) & 0xff old_rgb = book.colour_map[8 + i] new_rgb = (red, green, blue) book.palette_record.append(new_rgb) book.colour_map[8 + i] = new_rgb if verbose: if new_rgb != old_rgb: print("%2d: %r -> %r" % (i, old_rgb, new_rgb), file=book.logfile)
def handle_palette(book, data): if not book.formatting_info: return verbose = DEBUG or book.verbosity >= 2 n_colours, = unpack('<H', data[:2]) expected_n_colours = (16, 56)[book.biff_version >= 50] if ((DEBUG or book.verbosity >= 1) and n_colours != expected_n_colours): fprintf(book.logfile, "NOTE *** Expected %d colours in PALETTE record, found %d\n", expected_n_colours, n_colours) elif verbose: fprintf(book.logfile, "PALETTE record with %d colours\n", n_colours) fmt = '<xx%di' % n_colours # use i to avoid long integers expected_size = 4 * n_colours + 2 actual_size = len(data) tolerance = 4 if not expected_size <= actual_size <= expected_size + tolerance: raise XLRDError('PALETTE record: expected size %d, actual size %d' % (expected_size, actual_size)) colours = unpack(fmt, data[:expected_size]) assert book.palette_record == [] # There should be only 1 PALETTE record # a colour will be 0xbbggrr # IOW, red is at the little end for i in range(n_colours): c = colours[i] red = c & 0xff green = (c >> 8) & 0xff blue = (c >> 16) & 0xff old_rgb = book.colour_map[8+i] new_rgb = (red, green, blue) book.palette_record.append(new_rgb) book.colour_map[8+i] = new_rgb if verbose: if new_rgb != old_rgb: print("%2d: %r -> %r" % (i, old_rgb, new_rgb), file=book.logfile)
def handle_format(self, data, rectype=XL_FORMAT): DEBUG = 0 bv = self.biff_version if rectype == XL_FORMAT2: bv = min(bv, 30) if not self.encoding: self.derive_encoding() strpos = 2 if bv >= 50: fmtkey = unpack('<H', data[0:2])[0] else: fmtkey = self.actualfmtcount if bv <= 30: strpos = 0 self.actualfmtcount += 1 if bv >= 80: unistrg = unpack_unicode(data, 2) else: unistrg = unpack_string(data, strpos, self.encoding, lenlen=1) verbose = DEBUG or self.verbosity >= 3 if verbose: fprintf(self.logfile, "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n", self.actualfmtcount, fmtkey, fmtkey, unistrg) is_date_s = self.is_date_format_string(unistrg) ty = [FGE, FDT][is_date_s] if not (fmtkey > 163 or bv < 50): # user_defined if fmtkey > 163 # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-( # if earlier than BIFF 5, standard info is useless std_ty = std_format_code_types.get(fmtkey, FUN) # print "std ty", std_ty is_date_c = std_ty == FDT if 0 < fmtkey < 50 and (is_date_c ^ is_date_s): DEBUG = 2 fprintf( self.logfile, "WARNING *** Conflict between " "std format key %d and its format string %r\n", fmtkey, unistrg) if DEBUG == 2: fprintf(self.logfile, "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r", ty, is_date_c, is_date_s, unistrg) fmtobj = Format(fmtkey, ty, unistrg) if verbose: fmtobj.dump(self.logfile, header="--- handle_format [%d] ---" % (self.actualfmtcount - 1, )) self.format_map[fmtkey] = fmtobj self.format_list.append(fmtobj)
def handle_format(self, data, rectype=XL_FORMAT): DEBUG = 0 bv = self.biff_version if rectype == XL_FORMAT2: bv = min(bv, 30) if not self.encoding: self.derive_encoding() strpos = 2 if bv >= 50: fmtkey = unpack('<H', data[0:2])[0] else: fmtkey = self.actualfmtcount if bv <= 30: strpos = 0 self.actualfmtcount += 1 if bv >= 80: unistrg = unpack_unicode(data, 2) else: unistrg = unpack_string(data, strpos, self.encoding, lenlen=1) verbose = DEBUG or self.verbosity >= 3 if verbose: fprintf(self.logfile, "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n", self.actualfmtcount, fmtkey, fmtkey, unistrg) is_date_s = self.is_date_format_string(unistrg) ty = [FGE, FDT][is_date_s] if not(fmtkey > 163 or bv < 50): # user_defined if fmtkey > 163 # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-( # if earlier than BIFF 5, standard info is useless std_ty = std_format_code_types.get(fmtkey, FUN) # print "std ty", std_ty is_date_c = std_ty == FDT if 0 < fmtkey < 50 and (is_date_c ^ is_date_s): DEBUG = 2 fprintf(self.logfile, "WARNING *** Conflict between " "std format key %d and its format string %r\n", fmtkey, unistrg) if DEBUG == 2: fprintf(self.logfile, "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r", ty, is_date_c, is_date_s, unistrg) fmtobj = Format(fmtkey, ty, unistrg) if verbose: fmtobj.dump(self.logfile, header="--- handle_format [%d] ---" % (self.actualfmtcount-1, )) self.format_map[fmtkey] = fmtobj self.format_list.append(fmtobj)
def handle_xf(self, data): ### self is a Book instance # DEBUG = 0 verbose = DEBUG or self.verbosity >= 3 bv = self.biff_version xf = XF() xf.alignment = XFAlignment() xf.alignment.indent_level = 0 xf.alignment.shrink_to_fit = 0 xf.alignment.text_direction = 0 xf.border = XFBorder() xf.border.diag_up = 0 xf.border.diag_down = 0 xf.border.diag_colour_index = 0 xf.border.diag_line_style = 0 # no line xf.background = XFBackground() xf.protection = XFProtection() # fill in the known standard formats if bv >= 50 and not self.xfcount: # i.e. do this once before we process the first XF record for x in list(std_format_code_types.keys()): if x not in self.format_map: ty = std_format_code_types[x] fmt_str = std_format_strings[x] fmtobj = Format(x, ty, fmt_str) self.format_map[x] = fmtobj if bv >= 80: unpack_fmt = '<HHHBBBBIiH' ( xf.font_index, xf.format_key, pkd_type_par, pkd_align1, xf.alignment.rotation, pkd_align2, pkd_used, pkd_brdbkg1, pkd_brdbkg2, pkd_brdbkg3, ) = unpack(unpack_fmt, data[0:20]) upkbits(xf.protection, pkd_type_par, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits( xf, pkd_type_par, ( (2, 0x0004, 'is_style'), # Following is not in OOo docs, but is mentioned # in Gnumeric source and also in (deep breath) # org.apache.poi.hssf.record.ExtendedFormatRecord.java (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. (4, 0xFFF0, 'parent_style_index'), )) upkbits(xf.alignment, pkd_align1, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), (4, 0x70, 'vert_align'), )) upkbits(xf.alignment, pkd_align2, ( (0, 0x0f, 'indent_level'), (4, 0x10, 'shrink_to_fit'), (6, 0xC0, 'text_direction'), )) reg = pkd_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbitsL(xf.border, pkd_brdbkg1, ( (0, 0x0000000f, 'left_line_style'), (4, 0x000000f0, 'right_line_style'), (8, 0x00000f00, 'top_line_style'), (12, 0x0000f000, 'bottom_line_style'), (16, 0x007f0000, 'left_colour_index'), (23, 0x3f800000, 'right_colour_index'), (30, 0x40000000, 'diag_down'), (31, 0x80000000, 'diag_up'), )) upkbits(xf.border, pkd_brdbkg2, ( (0, 0x0000007F, 'top_colour_index'), (7, 0x00003F80, 'bottom_colour_index'), (14, 0x001FC000, 'diag_colour_index'), (21, 0x01E00000, 'diag_line_style'), )) upkbitsL(xf.background, pkd_brdbkg2, ((26, 0xFC000000, 'fill_pattern'), )) upkbits(xf.background, pkd_brdbkg3, ( (0, 0x007F, 'pattern_colour_index'), (7, 0x3F80, 'background_colour_index'), )) elif bv >= 50: unpack_fmt = '<HHHBBIi' ( xf.font_index, xf.format_key, pkd_type_par, pkd_align1, pkd_orient_used, pkd_brdbkg1, pkd_brdbkg2, ) = unpack(unpack_fmt, data[0:16]) upkbits(xf.protection, pkd_type_par, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits( xf, pkd_type_par, ( (2, 0x0004, 'is_style'), (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. (4, 0xFFF0, 'parent_style_index'), )) upkbits(xf.alignment, pkd_align1, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), (4, 0x70, 'vert_align'), )) orientation = pkd_orient_used & 0x03 xf.alignment.rotation = [0, 255, 90, 180][orientation] reg = pkd_orient_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbitsL(xf.background, pkd_brdbkg1, ( (0, 0x0000007F, 'pattern_colour_index'), (7, 0x00003F80, 'background_colour_index'), (16, 0x003F0000, 'fill_pattern'), )) upkbitsL(xf.border, pkd_brdbkg1, ( (22, 0x01C00000, 'bottom_line_style'), (25, 0xFE000000, 'bottom_colour_index'), )) upkbits(xf.border, pkd_brdbkg2, ( (0, 0x00000007, 'top_line_style'), (3, 0x00000038, 'left_line_style'), (6, 0x000001C0, 'right_line_style'), (9, 0x0000FE00, 'top_colour_index'), (16, 0x007F0000, 'left_colour_index'), (23, 0x3F800000, 'right_colour_index'), )) elif bv >= 40: unpack_fmt = '<BBHBBHI' ( xf.font_index, xf.format_key, pkd_type_par, pkd_align_orient, pkd_used, pkd_bkg_34, pkd_brd_34, ) = unpack(unpack_fmt, data[0:12]) upkbits(xf.protection, pkd_type_par, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits( xf, pkd_type_par, ( (2, 0x0004, 'is_style'), (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. (4, 0xFFF0, 'parent_style_index'), )) upkbits(xf.alignment, pkd_align_orient, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), (4, 0x30, 'vert_align'), )) orientation = (pkd_align_orient & 0xC0) >> 6 xf.alignment.rotation = [0, 255, 90, 180][orientation] reg = pkd_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbits(xf.background, pkd_bkg_34, ( (0, 0x003F, 'fill_pattern'), (6, 0x07C0, 'pattern_colour_index'), (11, 0xF800, 'background_colour_index'), )) upkbitsL(xf.border, pkd_brd_34, ( (0, 0x00000007, 'top_line_style'), (3, 0x000000F8, 'top_colour_index'), (8, 0x00000700, 'left_line_style'), (11, 0x0000F800, 'left_colour_index'), (16, 0x00070000, 'bottom_line_style'), (19, 0x00F80000, 'bottom_colour_index'), (24, 0x07000000, 'right_line_style'), (27, 0xF8000000, 'right_colour_index'), )) elif bv == 30: unpack_fmt = '<BBBBHHI' ( xf.font_index, xf.format_key, pkd_type_prot, pkd_used, pkd_align_par, pkd_bkg_34, pkd_brd_34, ) = unpack(unpack_fmt, data[0:12]) upkbits(xf.protection, pkd_type_prot, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits( xf, pkd_type_prot, ( (2, 0x0004, 'is_style'), (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. )) upkbits(xf.alignment, pkd_align_par, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), )) upkbits(xf, pkd_align_par, ((4, 0xFFF0, 'parent_style_index'), )) reg = pkd_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbits(xf.background, pkd_bkg_34, ( (0, 0x003F, 'fill_pattern'), (6, 0x07C0, 'pattern_colour_index'), (11, 0xF800, 'background_colour_index'), )) upkbitsL(xf.border, pkd_brd_34, ( (0, 0x00000007, 'top_line_style'), (3, 0x000000F8, 'top_colour_index'), (8, 0x00000700, 'left_line_style'), (11, 0x0000F800, 'left_colour_index'), (16, 0x00070000, 'bottom_line_style'), (19, 0x00F80000, 'bottom_colour_index'), (24, 0x07000000, 'right_line_style'), (27, 0xF8000000, 'right_colour_index'), )) xf.alignment.vert_align = 2 # bottom xf.alignment.rotation = 0 elif bv == 21: #### Warning: incomplete treatment; formatting_info not fully supported. #### Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16], #### and create XF[0:16] like the standard ones in BIFF8 #### *AND* add 16 to all XF references in cell records :-( (xf.font_index, format_etc, halign_etc) = unpack('<BxBB', data) xf.format_key = format_etc & 0x3F upkbits(xf.protection, format_etc, ( (6, 0x40, 'cell_locked'), (7, 0x80, 'formula_hidden'), )) upkbits(xf.alignment, halign_etc, ((0, 0x07, 'hor_align'), )) for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')): if halign_etc & mask: colour_index, line_style = 8, 1 # black, thin else: colour_index, line_style = 0, 0 # none, none setattr(xf.border, side + '_colour_index', colour_index) setattr(xf.border, side + '_line_style', line_style) bg = xf.background if halign_etc & 0x80: bg.fill_pattern = 17 else: bg.fill_pattern = 0 bg.background_colour_index = 9 # white bg.pattern_colour_index = 8 # black xf.parent_style_index = 0 # ??????????? xf.alignment.vert_align = 2 # bottom xf.alignment.rotation = 0 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, 1) else: raise XLRDError('programmer stuff-up: bv=%d' % bv) xf.xf_index = len(self.xf_list) self.xf_list.append(xf) self.xfcount += 1 if verbose: xf.dump( self.logfile, header="--- handle_xf: xf[%d] ---" % xf.xf_index, footer=" ", ) # Now for some assertions ... if self.formatting_info: if xf.is_style and xf.parent_style_index != 0x0FFF: msg = "WARNING *** XF[%d] is a style XF but parent_style_index is 0x%04x, not 0x0fff\n" fprintf(self.logfile, msg, xf.xf_index, xf.parent_style_index) check_colour_indexes_in_obj(self, xf, xf.xf_index) if xf.format_key not in self.format_map: msg = "WARNING *** XF[%d] unknown (raw) format key (%d, 0x%04x)\n" fprintf(self.logfile, msg, xf.xf_index, xf.format_key, xf.format_key) xf.format_key = 0
def check_same(book_arg, xf_arg, parent_arg, attr): # the _arg caper is to avoid a Warning msg from Python 2.1 :-( if getattr(xf_arg, attr) != getattr(parent_arg, attr): fprintf(book_arg.logfile, "NOTE !!! XF[%d] parent[%d] %s different\n", xf_arg.xf_index, parent_arg.xf_index, attr)
def xf_epilogue(self): # self is a Book instance. self._xf_epilogue_done = 1 num_xfs = len(self.xf_list) verbose = DEBUG or self.verbosity >= 3 verbose1 = DEBUG or self.verbosity >= 1 if verbose: fprintf(self.logfile, "xf_epilogue called ...\n") def check_same(book_arg, xf_arg, parent_arg, attr): # the _arg caper is to avoid a Warning msg from Python 2.1 :-( if getattr(xf_arg, attr) != getattr(parent_arg, attr): fprintf(book_arg.logfile, "NOTE !!! XF[%d] parent[%d] %s different\n", xf_arg.xf_index, parent_arg.xf_index, attr) for xfx in range(num_xfs): xf = self.xf_list[xfx] if xf.format_key not in self.format_map: msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" fprintf(self.logfile, msg, xf.xf_index, xf.format_key, xf.format_key) xf.format_key = 0 cellty_from_fmtty = { FNU: XL_CELL_NUMBER, FUN: XL_CELL_NUMBER, FGE: XL_CELL_NUMBER, FDT: XL_CELL_DATE, FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. } fmt = self.format_map[xf.format_key] cellty = cellty_from_fmtty[fmt.type] self._xf_index_to_xl_type_map[xf.xf_index] = cellty # Now for some assertions etc if not self.formatting_info: continue if xf.is_style: continue if not (0 <= xf.parent_style_index < num_xfs): fprintf( self.logfile, "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n", xf.xf_index, xf.is_style, xf.parent_style_index) # make it conform xf.parent_style_index = 0 if self.biff_version >= 30: assert xf.parent_style_index != xf.xf_index assert self.xf_list[xf.parent_style_index].is_style if verbose1 and xf.parent_style_index > xf.xf_index: fprintf( self.logfile, "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n", xf.xf_index, xf.parent_style_index) parent = self.xf_list[xf.parent_style_index] if not xf._alignment_flag and not parent._alignment_flag: if verbose1: check_same(self, xf, parent, 'alignment') if not xf._background_flag and not parent._background_flag: if verbose1: check_same(self, xf, parent, 'background') if not xf._border_flag and not parent._border_flag: if verbose1: check_same(self, xf, parent, 'border') if not xf._protection_flag and not parent._protection_flag: if verbose1: check_same(self, xf, parent, 'protection') if not xf._format_flag and not parent._format_flag: if verbose1 and xf.format_key != parent.format_key: fprintf( self.logfile, "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n", xf.xf_index, xf.format_key, parent.xf_index, parent.format_key, self.format_map[xf.format_key].format_str, self.format_map[parent.format_key].format_str) if not xf._font_flag and not parent._font_flag: if verbose1 and xf.font_index != parent.font_index: fprintf(self.logfile, "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n", xf.xf_index, xf.font_index, parent.xf_index, parent.font_index)
def xf_epilogue(self): # self is a Book instance. self._xf_epilogue_done = 1 num_xfs = len(self.xf_list) verbose = DEBUG or self.verbosity >= 3 verbose1 = DEBUG or self.verbosity >= 1 if verbose: fprintf(self.logfile, "xf_epilogue called ...\n") def check_same(book_arg, xf_arg, parent_arg, attr): # the _arg caper is to avoid a Warning msg from Python 2.1 :-( if getattr(xf_arg, attr) != getattr(parent_arg, attr): fprintf(book_arg.logfile, "NOTE !!! XF[%d] parent[%d] %s different\n", xf_arg.xf_index, parent_arg.xf_index, attr) for xfx in range(num_xfs): xf = self.xf_list[xfx] if xf.format_key not in self.format_map: msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" fprintf(self.logfile, msg, xf.xf_index, xf.format_key, xf.format_key) xf.format_key = 0 cellty_from_fmtty = { FNU: XL_CELL_NUMBER, FUN: XL_CELL_NUMBER, FGE: XL_CELL_NUMBER, FDT: XL_CELL_DATE, FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. } fmt = self.format_map[xf.format_key] cellty = cellty_from_fmtty[fmt.type] self._xf_index_to_xl_type_map[xf.xf_index] = cellty # Now for some assertions etc if not self.formatting_info: continue if xf.is_style: continue if not(0 <= xf.parent_style_index < num_xfs): fprintf(self.logfile, "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n", xf.xf_index, xf.is_style, xf.parent_style_index) # make it conform xf.parent_style_index = 0 if self.biff_version >= 30: assert xf.parent_style_index != xf.xf_index assert self.xf_list[xf.parent_style_index].is_style if verbose1 and xf.parent_style_index > xf.xf_index: fprintf(self.logfile, "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n", xf.xf_index, xf.parent_style_index) parent = self.xf_list[xf.parent_style_index] if not xf._alignment_flag and not parent._alignment_flag: if verbose1: check_same(self, xf, parent, 'alignment') if not xf._background_flag and not parent._background_flag: if verbose1: check_same(self, xf, parent, 'background') if not xf._border_flag and not parent._border_flag: if verbose1: check_same(self, xf, parent, 'border') if not xf._protection_flag and not parent._protection_flag: if verbose1: check_same(self, xf, parent, 'protection') if not xf._format_flag and not parent._format_flag: if verbose1 and xf.format_key != parent.format_key: fprintf(self.logfile, "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n", xf.xf_index, xf.format_key, parent.xf_index, parent.format_key, self.format_map[xf.format_key].format_str, self.format_map[parent.format_key].format_str) if not xf._font_flag and not parent._font_flag: if verbose1 and xf.font_index != parent.font_index: fprintf(self.logfile, "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n", xf.xf_index, xf.font_index, parent.xf_index, parent.font_index)
def handle_xf(self, data): ### self is a Book instance # DEBUG = 0 verbose = DEBUG or self.verbosity >= 3 bv = self.biff_version xf = XF() xf.alignment = XFAlignment() xf.alignment.indent_level = 0 xf.alignment.shrink_to_fit = 0 xf.alignment.text_direction = 0 xf.border = XFBorder() xf.border.diag_up = 0 xf.border.diag_down = 0 xf.border.diag_colour_index = 0 xf.border.diag_line_style = 0 # no line xf.background = XFBackground() xf.protection = XFProtection() # fill in the known standard formats if bv >= 50 and not self.xfcount: # i.e. do this once before we process the first XF record for x in list(std_format_code_types.keys()): if x not in self.format_map: ty = std_format_code_types[x] fmt_str = std_format_strings[x] fmtobj = Format(x, ty, fmt_str) self.format_map[x] = fmtobj if bv >= 80: unpack_fmt = '<HHHBBBBIiH' (xf.font_index, xf.format_key, pkd_type_par, pkd_align1, xf.alignment.rotation, pkd_align2, pkd_used, pkd_brdbkg1, pkd_brdbkg2, pkd_brdbkg3, ) = unpack(unpack_fmt, data[0:20]) upkbits(xf.protection, pkd_type_par, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits(xf, pkd_type_par, ( (2, 0x0004, 'is_style'), # Following is not in OOo docs, but is mentioned # in Gnumeric source and also in (deep breath) # org.apache.poi.hssf.record.ExtendedFormatRecord.java (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. (4, 0xFFF0, 'parent_style_index'), )) upkbits(xf.alignment, pkd_align1, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), (4, 0x70, 'vert_align'), )) upkbits(xf.alignment, pkd_align2, ( (0, 0x0f, 'indent_level'), (4, 0x10, 'shrink_to_fit'), (6, 0xC0, 'text_direction'), )) reg = pkd_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbitsL(xf.border, pkd_brdbkg1, ( (0, 0x0000000f, 'left_line_style'), (4, 0x000000f0, 'right_line_style'), (8, 0x00000f00, 'top_line_style'), (12, 0x0000f000, 'bottom_line_style'), (16, 0x007f0000, 'left_colour_index'), (23, 0x3f800000, 'right_colour_index'), (30, 0x40000000, 'diag_down'), (31, 0x80000000, 'diag_up'), )) upkbits(xf.border, pkd_brdbkg2, ( (0, 0x0000007F, 'top_colour_index'), (7, 0x00003F80, 'bottom_colour_index'), (14, 0x001FC000, 'diag_colour_index'), (21, 0x01E00000, 'diag_line_style'), )) upkbitsL(xf.background, pkd_brdbkg2, ( (26, 0xFC000000, 'fill_pattern'), )) upkbits(xf.background, pkd_brdbkg3, ( (0, 0x007F, 'pattern_colour_index'), (7, 0x3F80, 'background_colour_index'), )) elif bv >= 50: unpack_fmt = '<HHHBBIi' (xf.font_index, xf.format_key, pkd_type_par, pkd_align1, pkd_orient_used, pkd_brdbkg1, pkd_brdbkg2, ) = unpack(unpack_fmt, data[0:16]) upkbits(xf.protection, pkd_type_par, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits(xf, pkd_type_par, ( (2, 0x0004, 'is_style'), (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. (4, 0xFFF0, 'parent_style_index'), )) upkbits(xf.alignment, pkd_align1, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), (4, 0x70, 'vert_align'), )) orientation = pkd_orient_used & 0x03 xf.alignment.rotation = [0, 255, 90, 180][orientation] reg = pkd_orient_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbitsL(xf.background, pkd_brdbkg1, ( ( 0, 0x0000007F, 'pattern_colour_index'), ( 7, 0x00003F80, 'background_colour_index'), (16, 0x003F0000, 'fill_pattern'), )) upkbitsL(xf.border, pkd_brdbkg1, ( (22, 0x01C00000, 'bottom_line_style'), (25, 0xFE000000, 'bottom_colour_index'), )) upkbits(xf.border, pkd_brdbkg2, ( ( 0, 0x00000007, 'top_line_style'), ( 3, 0x00000038, 'left_line_style'), ( 6, 0x000001C0, 'right_line_style'), ( 9, 0x0000FE00, 'top_colour_index'), (16, 0x007F0000, 'left_colour_index'), (23, 0x3F800000, 'right_colour_index'), )) elif bv >= 40: unpack_fmt = '<BBHBBHI' (xf.font_index, xf.format_key, pkd_type_par, pkd_align_orient, pkd_used, pkd_bkg_34, pkd_brd_34, ) = unpack(unpack_fmt, data[0:12]) upkbits(xf.protection, pkd_type_par, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits(xf, pkd_type_par, ( (2, 0x0004, 'is_style'), (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. (4, 0xFFF0, 'parent_style_index'), )) upkbits(xf.alignment, pkd_align_orient, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), (4, 0x30, 'vert_align'), )) orientation = (pkd_align_orient & 0xC0) >> 6 xf.alignment.rotation = [0, 255, 90, 180][orientation] reg = pkd_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbits(xf.background, pkd_bkg_34, ( ( 0, 0x003F, 'fill_pattern'), ( 6, 0x07C0, 'pattern_colour_index'), (11, 0xF800, 'background_colour_index'), )) upkbitsL(xf.border, pkd_brd_34, ( ( 0, 0x00000007, 'top_line_style'), ( 3, 0x000000F8, 'top_colour_index'), ( 8, 0x00000700, 'left_line_style'), (11, 0x0000F800, 'left_colour_index'), (16, 0x00070000, 'bottom_line_style'), (19, 0x00F80000, 'bottom_colour_index'), (24, 0x07000000, 'right_line_style'), (27, 0xF8000000, 'right_colour_index'), )) elif bv == 30: unpack_fmt = '<BBBBHHI' (xf.font_index, xf.format_key, pkd_type_prot, pkd_used, pkd_align_par, pkd_bkg_34, pkd_brd_34, ) = unpack(unpack_fmt, data[0:12]) upkbits(xf.protection, pkd_type_prot, ( (0, 0x01, 'cell_locked'), (1, 0x02, 'formula_hidden'), )) upkbits(xf, pkd_type_prot, ( (2, 0x0004, 'is_style'), (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. )) upkbits(xf.alignment, pkd_align_par, ( (0, 0x07, 'hor_align'), (3, 0x08, 'text_wrapped'), )) upkbits(xf, pkd_align_par, ( (4, 0xFFF0, 'parent_style_index'), )) reg = pkd_used >> 2 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, reg & 1) reg >>= 1 upkbits(xf.background, pkd_bkg_34, ( ( 0, 0x003F, 'fill_pattern'), ( 6, 0x07C0, 'pattern_colour_index'), (11, 0xF800, 'background_colour_index'), )) upkbitsL(xf.border, pkd_brd_34, ( ( 0, 0x00000007, 'top_line_style'), ( 3, 0x000000F8, 'top_colour_index'), ( 8, 0x00000700, 'left_line_style'), (11, 0x0000F800, 'left_colour_index'), (16, 0x00070000, 'bottom_line_style'), (19, 0x00F80000, 'bottom_colour_index'), (24, 0x07000000, 'right_line_style'), (27, 0xF8000000, 'right_colour_index'), )) xf.alignment.vert_align = 2 # bottom xf.alignment.rotation = 0 elif bv == 21: #### Warning: incomplete treatment; formatting_info not fully supported. #### Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16], #### and create XF[0:16] like the standard ones in BIFF8 #### *AND* add 16 to all XF references in cell records :-( (xf.font_index, format_etc, halign_etc) = unpack('<BxBB', data) xf.format_key = format_etc & 0x3F upkbits(xf.protection, format_etc, ( (6, 0x40, 'cell_locked'), (7, 0x80, 'formula_hidden'), )) upkbits(xf.alignment, halign_etc, ( (0, 0x07, 'hor_align'), )) for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')): if halign_etc & mask: colour_index, line_style = 8, 1 # black, thin else: colour_index, line_style = 0, 0 # none, none setattr(xf.border, side + '_colour_index', colour_index) setattr(xf.border, side + '_line_style', line_style) bg = xf.background if halign_etc & 0x80: bg.fill_pattern = 17 else: bg.fill_pattern = 0 bg.background_colour_index = 9 # white bg.pattern_colour_index = 8 # black xf.parent_style_index = 0 # ??????????? xf.alignment.vert_align = 2 # bottom xf.alignment.rotation = 0 for attr_stem in \ "format font alignment border background protection".split(): attr = "_" + attr_stem + "_flag" setattr(xf, attr, 1) else: raise XLRDError('programmer stuff-up: bv=%d' % bv) xf.xf_index = len(self.xf_list) self.xf_list.append(xf) self.xfcount += 1 if verbose: xf.dump( self.logfile, header="--- handle_xf: xf[%d] ---" % xf.xf_index, footer=" ", ) # Now for some assertions ... if self.formatting_info: if xf.is_style and xf.parent_style_index != 0x0FFF: msg = "WARNING *** XF[%d] is a style XF but parent_style_index is 0x%04x, not 0x0fff\n" fprintf(self.logfile, msg, xf.xf_index, xf.parent_style_index) check_colour_indexes_in_obj(self, xf, xf.xf_index) if xf.format_key not in self.format_map: msg = "WARNING *** XF[%d] unknown (raw) format key (%d, 0x%04x)\n" fprintf(self.logfile, msg, xf.xf_index, xf.format_key, xf.format_key) xf.format_key = 0