public function handleXF($data) { ### self is a Book instance $bv = $this->biff_version; $xf = new XF(); $xf->alignment = new XFAlignment(); $xf->alignment->indent_level = 0; $xf->alignment->shrink_to_fit = 0; $xf->alignment->text_direction = 0; $xf->border = new 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 = new XFBackground(); $xf->protection = new XFProtection(); # fill in the known standard formats if ($bv >= 50 and !$this->xfcount) { # i.e. do this once before we process the first XF record $this->fillInStandardFormats(); } if ($bv >= 80) { # <HHHBBBBIiH $unpack_fmt = "v3a/C4b/Vc/id/ve"; list($xf->font_index, $xf->format_key, $pkd_type_par, $pkd_align1, $xf->alignment_rotation, $pkd_align2, $pkd_used, $pkd_brdbkg1, $pkd_brdbkg2, $pkd_brdbkg3) = array_values(unpack($unpack_fmt, substr($data, 0, 20))); Helper::upkbits($xf->protection, $pkd_type_par, [[0, 0x1, 'cell_locked'], [1, 0x2, 'formula_hidden']]); Helper::upkbits($xf, $pkd_type_par, [[2, 0x4, 'is_style'], [3, 0x8, 'lotus_123_prefix'], [4, 0xfff0, 'parent_style_index']]); Helper::upkbits($xf->alignment, $pkd_align1, [[0, 0x7, 'hor_align'], [3, 0x8, 'text_wrapped'], [4, 0x70, 'vert_align']]); Helper::upkbits($xf->alignment, $pkd_align2, [[0, 0xf, 'indent_level'], [4, 0x10, 'shrink_to_fit'], [6, 0xc0, 'text_direction']]); $reg = $pkd_used >> 2; foreach (['format', 'font', 'alignment', 'border', 'background', 'protection'] as $attr_stem) { $attr = "_" . $attr_stem . "_flag"; $xf->{$attr} = $reg & 1; $reg >>= 1; } Helper::upkbitsL($xf->border, $pkd_brdbkg1, [[0, 0xf, 'left_line_style'], [4, 0xf0, 'right_line_style'], [8, 0xf00, 'top_line_style'], [12, 0xf000, 'bottom_line_style'], [16, 0x7f0000, 'left_colour_index'], [23, 0x3f800000, 'right_colour_index'], [30, 0x40000000, 'diag_down'], [31, 2147483648.0, 'diag_up']]); Helper::upkbits($xf->border, $pkd_brdbkg2, [[0, 0x7f, 'top_colour_index'], [7, 0x3f80, 'bottom_colour_index'], [14, 0x1fc000, 'diag_colour_index'], [21, 0x1e00000, 'diag_line_style']]); Helper::upkbitsL($xf->background, $pkd_brdbkg2, [[26, 4227858432.0, 'fill_pattern']]); Helper::upkbits($xf->background, $pkd_brdbkg3, [[0, 0x7f, 'pattern_colour_index'], [7, 0x3f80, 'background_colour_index']]); } elseif ($bv >= 50) { # <HHHBBIi $unpack_fmt = "v3a/C2b/Vc/id"; list($xf->font_index, $xf->format_key, $pkd_type_par, $pkd_align1, $pkd_orient_used, $pkd_brdbkg1, $pkd_brdbkg2) = array_values(unpack($unpack_fmt, substr($data, 0, 16))); Helper::upkbits($xf->protection, $pkd_type_par, [[0, 0x1, 'cell_locked'], [1, 0x2, 'formula_hidden']]); Helper::upkbits($xf, $pkd_type_par, [[2, 0x4, 'is_style'], [3, 0x8, 'lotus_123_prefix'], [4, 0xfff0, 'parent_style_index']]); Helper::upkbits($xf->alignment, $pkd_align1, [[0, 0x7, 'hor_align'], [3, 0x8, 'text_wrapped'], [4, 0x70, 'vert_align']]); $orientation = $pkd_orient_used & 0x3; $rotations = [0, 255, 90, 180]; $xf->alignment->rotation = $rotations[$orientation]; $reg = $pkd_orient_used >> 2; foreach (['format', 'font', 'alignment', 'border', 'background', 'protection'] as $attr_stem) { $attr = "_{$attr_stem}_flag"; $xf->{$attr} = $reg & 1; $reg >>= 1; } Helper::upkbitsL($xf->background, $pkd_brdbkg1, [[0, 0x7f, 'pattern_colour_index'], [7, 0x3f80, 'background_colour_index'], [16, 0x3f0000, 'fill_pattern']]); Helper::upkbitsL($xf->border, $pkd_brdbkg1, [[22, 0x1c00000, 'bottom_line_style'], [25, 0.0, 'bottom_colour_index']]); Helper::upkbits($xf->border, $pkd_brdbkg2, [[0, 0x7, 'top_line_style'], [3, 0x38, 'left_line_style'], [6, 0x1c0, 'right_line_style'], [9, 0xfe00, 'top_colour_index'], [16, 0x7f0000, 'left_colour_index'], [23, 0x3f800000, 'right_colour_index']]); // @TODO } elseif ($bv >= 40) { # <BBHBBHI list($xf->font_index, $xf->format_key, $pkd_type_par, $pkd_align_orient, $pkd_used, $pkd_bkg_34, $pkd_brd_34) = array_values(unpack('C2a/vb/C2c/vd/Ve', substr($data, 0, 12))); Helper::upkbits($xf->protection, $pkd_type_par, [[0, 0x1, 'cell_locked'], [1, 0x2, 'formula_hidden']]); Helper::upkbits($xf, $pkd_type_par, [[2, 0x4, 'is_style'], [3, 0x8, 'lotus_123_prefix'], [4, 0xfff0, 'parent_style_index']]); Helper::upkbits($xf->{$alignment}, $pkd_align_orient, [[0, 0x7, 'hor_align'], [3, 0x8, 'text_wrapped'], [4, 0x30, 'vert_align']]); $orientation = ($pkd_align_orient & 0xc0) >> 6; $rotations = [0, 255, 90, 180]; $xf->alignment->rotation = $rotations[$orientation]; $reg = $pkd_used >> 2; foreach (['format', 'font', 'alignment', 'border', 'background', 'protection'] as $attr_stem) { $attr = "_{$attr_stem}_flag"; $xf->{$attr} = $reg & 1; $reg >>= 1; } Helper::upkbits($xf->background, $pkd_bkg_34, [[0, 0x3f, 'fill_pattern'], [6, 0x7c0, 'pattern_colour_index'], [11, 0xf800, 'background_colour_index']]); Helper::upkbitsL($xf->border, $pkd_brd_34, [[0, 0x7, 'top_line_style'], [3, 0xf8, 'top_colour_index'], [8, 0x700, 'left_line_style'], [11, 0xf800, 'left_colour_index'], [16, 0x70000, 'bottom_line_style'], [19, 0xf80000, 'bottom_colour_index'], [24, 0x7000000, 'right_line_style'], [27, 4160749568.0, 'right_colour_index']]); } elseif ($bv == 30) { # <BBBBHHI list($xf->font_index, $xf->format_key, $pkd_type_prot, $pkd_used, $pkd_align_par, $pkd_bkg_34, $pkd_brd_34) = array_values(unpack('C4a/v2b/Vc', substr($data, 0, 12))); Helper::upkbits($xf->protection, $pkd_type_prot, [[0, 0x1, 'cell_locked'], [1, 0x2, 'formula_hidden']]); Helper::upkbits($xf, $pkd_type_prot, [[2, 0x4, 'is_style'], [3, 0x8, 'lotus_123_prefix']]); Helper::upkbits($xf->alignment, $pkd_align_par, [[0, 0x7, 'hor_align'], [3, 0x8, 'text_wrapped']]); Helper::upkbits($xf, $pkd_align_par, [[4, 0xfff0, 'parent_style_index']]); $reg = $pkd_used >> 2; foreach (['format', 'font', 'alignment', 'border', 'background', 'protection'] as $attr_stem) { $attr = "_{$attr_stem}_flag"; $xf->{$attr} = $reg & 1; $reg >>= 1; } Helper::upkbits($xf->background, $pkd_bkg_34, [[0, 0x3f, 'fill_pattern'], [6, 0x7c0, 'pattern_colour_index'], [11, 0xf800, 'background_colour_index']]); Helper::upkbitsL($xf->border, $pkd_brd_34, [[0, 0x7, 'top_line_style'], [3, 0xf8, 'top_colour_index'], [8, 0x700, 'left_line_style'], [11, 0xf800, 'left_colour_index'], [16, 0x70000, 'bottom_line_style'], [19, 0xf80000, 'bottom_colour_index'], [24, 0x7000000, 'right_line_style'], [27, 4160749568.0, 'right_colour_index']]); $xf->alignment->vert_align = 2; # bottom $xf->alignment->rotation = 0; } elseif ($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 :-( # <BxBB list($xf->font_index, , $format_etc, $halign_etc) = array_values(unpack('C4', $data)); $xf->format_key = $format_etc & 0x3f; Helper::upkbits($xf->protection, $format_etc, [[6, 0x40, 'cell_locked'], [7, 0x80, 'formula_hidden']]); Helper::upkbits($xf->alignment, $halign_etc, [[0, 0x7, 'hor_align']]); foreach ([[0x8, 'left'], [0x10, 'right'], [0x20, 'top'], [0x40, 'bottom']] as $row) { list($mask, $side) = $row; if ($halign_etc && $mask) { $colour_index = 8; # black $line_style = 1; # thin } else { $colour_index = 0; # none $line_style = 0; # none } $xf->border->{"{$side}_colour_index"} = $colour_index; $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; foreach (['format', 'font', 'alignment', 'border', 'background', 'protection'] as $attr_stem) { $attr = "_{$attr_stem}_flag"; $xf->{$attr} = 1; } } else { throw new XLSParserException("programmer stuff-up: bv={$bv}"); } $xf->xf_index = count($this->xf_list); $this->xf_list[] = $xf; $this->xfcount++; $fmt = $cellty = null; if (isset($this->format_map[$xf->format_key])) { $fmt = $this->format_map[$xf->format_key]; $cellty = isset(Defs::$cellty_from_fmtty[$fmt->type]) ? Defs::$cellty_from_fmtty[$fmt->type] : false; } if (!$fmt || !$cellty) { $cellty = XL_CELL_NUMBER; } $this->xf_index_to_xl_type_map[$xf->xf_index] = $cellty; # Now for some assertions ... if ($this->formatting_info) { $this->checkColourIndexesInObj($xf, $xf->xf_index); } if (!isset($this->format_map[$xf->format_key])) { $xf->format_key = 0; } }
public function handle_txo($data) { if ($this->biff_version < 80) { return; } $o = new MSTxo(); $data_len = strlen($data); # <HH6sHHH list($option_flags, $o->rot, $cchText, $cbRuns, $o->ifntEmpty) = array_values(unpack('v2a/x6/v3b', substr($data, 0, 16))); $controlInfo = substr($data, 4, 6); $o->fmla = substr($data, 16); Helper::upkbits($o, $option_flags, [[3, 0xe, 'horz_align'], [6, 0x70, 'vert_align'], [9, 0x200, 'lock_text'], [14, 0x4000, 'just_last'], [15, 0x8000, 'secret_edit']]); $totchars = 0; $o->text = ''; while ($totchars < $cchText) { list($rc2, $data2_len, $data2) = $this->book->readRecordParts(); assert($rc2 == XL_CONTINUE); $nb = ord($data2[0]); $nchars = $data2_len - 1; if ($nb) { assert($nchars % 2 == 0); $nchars = (int) $nchars / 2; } list($utext, $endpos) = Helper::unpack_unicode_update_pos($data2, 0, 2, $nchars); assert($endpos == $data2_len); $o->text .= $utext; $totchars += $nchars; } $o->rich_text_runlist = []; $totruns = 0; while ($totruns < $cbRuns) { # counts of BYTES, not runs list($rc3, $data3_len, $data3) = $this->book->readRecordParts(); assert($rc3 == XL_CONTINUE); assert($data3_len % 8 == 0); for ($pos = 0; $pos < $data3_len; $pos += 8) { # <HH4x $run = array_values(unpack('v2', substr($data3, $pos, 8))); $o->rich_text_runlist[] = $run; $totruns += 8; } } # remove trailing entries that point to the end of the string while ($o->rich_text_runlist && $o->rich_text_runlist[count($o->rich_text_runlist) - 1][0] == $cchText) { unset($o->rich_text_runlist[count($o->rich_text_runlist) - 1]); } return $o; }