diff --git a/Writer/BIFFwriter.php b/Writer/BIFFwriter.php index e07fef5..1f700df 100644 --- a/Writer/BIFFwriter.php +++ b/Writer/BIFFwriter.php @@ -176,7 +176,7 @@ class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR } elseif ($this->_BIFF_version == 0x0600) { $length = 0x0010; - $unknown = pack("VV", 0x00000000, 0x00000006); //unknown last 8 bytes for BIFF8 + $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8 $build = 0x0DBB; $year = 0x07CC; } diff --git a/Writer/Format.php b/Writer/Format.php index 1dda7ca..872fc56 100644 --- a/Writer/Format.php +++ b/Writer/Format.php @@ -245,11 +245,11 @@ class Spreadsheet_Excel_Writer_Format extends PEAR /** * Constructor * - * @access public + * @access private * @param integer $index the XF index for the format. * @param array $properties array with properties to be set on initialization. */ - function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0,$properties = array()) + function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties = array()) { $this->_xf_index = $index; $this->_BIFF_version = $BIFF_version; @@ -350,6 +350,9 @@ class Spreadsheet_Excel_Writer_Format extends PEAR if ($this->_left == 0) { $this->_left_color = 0; } + if ($this->_diag == 0) { + $this->_diag_color = 0; + } $record = 0x00E0; // Record identifier if ($this->_BIFF_version == 0x0500) { @@ -455,11 +458,16 @@ class Spreadsheet_Excel_Writer_Format extends PEAR $uls = $this->_underline; // Underline $bFamily = $this->_font_family; // Font family $bCharSet = $this->_font_charset; // Character set - $rgch = $this->_font_name; // Font name + $encoding = 0; // TODO: Unicode support - $cch = strlen($rgch); // Length of font name - $record = 0x31; // Record identifier - $length = 0x0F + $cch; // Record length + $cch = strlen($this->_font_name); // Length of font name + $record = 0x31; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x0F + $cch; // Record length + } + elseif ($this->_BIFF_version == 0x0600) { + $length = 0x10 + $cch; + } $reserved = 0x00; // Reserved $grbit = 0x00; // Font attributes if ($this->_italic) { @@ -476,9 +484,16 @@ class Spreadsheet_Excel_Writer_Format extends PEAR } $header = pack("vv", $record, $length); - $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls, - $sss, $uls, $bFamily, - $bCharSet, $reserved, $cch); + if ($this->_BIFF_version == 0x0500) { + $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls, + $sss, $uls, $bFamily, + $bCharSet, $reserved, $cch); + } + elseif ($this->_BIFF_version == 0x0600) { + $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls, + $sss, $uls, $bFamily, + $bCharSet, $reserved, $cch, $encoding); + } return($header . $data. $this->_font_name); } diff --git a/Writer/Parser.php b/Writer/Parser.php index d56de2c..b85275f 100644 --- a/Writer/Parser.php +++ b/Writer/Parser.php @@ -624,13 +624,24 @@ class Spreadsheet_Excel_Writer_Parser extends PEAR * Convert a string token to ptgStr * * @access private - * @param string $string A string for conversion to its ptg value + * @param string $string A string for conversion to its ptg value. + * @return mixed the converted token on success. PEAR_Error if the string + * is longer than 255 characters. */ function _convertString($string) { // chop away beggining and ending quotes $string = substr($string, 1, strlen($string) - 2); - return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string; + if (strlen($string) > 255) { + return $this->raiseError("String is too long"); + } + if ($this->_BIFF_version == 0x0500) { + return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string; + } + elseif ($this->_BIFF_version == 0x0600) { + $encoding = 0; // TODO: Unicode support + return pack("CCC", $this->ptg['ptgStr'], strlen($string), $encoding).$string; + } } /** diff --git a/Writer/Workbook.php b/Writer/Workbook.php index 6ee4f8c..396815a 100644 --- a/Writer/Workbook.php +++ b/Writer/Workbook.php @@ -147,6 +147,12 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri */ var $_url_format; + /** + * The codepage indicates the text encoding used for strings + * @var integer + */ + var $_codepage; + /** * Class constructor * @@ -173,6 +179,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri $this->_sheetnames = array(); $this->_formats = array(); $this->_palette = array(); + $this->_codepage = 0x04E4; // FIXME: should change for BIFF8 // Add the default format for hyperlinks $this->_url_format =& $this->addFormat(array('color' => 'blue', 'underline' => 1)); @@ -227,8 +234,10 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri } /** - * Sets the BIFF version. - * Possible values are 5 (Excel 5.0), or 8 (Excel 97/2000). + * Sets the BIFF version. + * This method exists just to access experimental functionality + * from BIFF8. It will be deprecated ! + * Only possible value is 8 (Excel 97/2000). * For any other value it fails silently. * * @access public @@ -236,19 +245,22 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri */ function setVersion($version) { - if (($version == 5) or ($version == 8)) { - if ($version == 5) { - $version = 0x0500; - } - elseif ($version == 8) { - $version = 0x0600; - } + if ($version == 8) { // only accept version 8 + $version = 0x0600; $this->_BIFF_version = $version; + $this->_tmp_format->_BIFF_version = $version; + $this->_url_format->_BIFF_version = $version; + $this->_parser->_BIFF_version = $version; $total_worksheets = count($this->_worksheets); // change version for all worksheets too for ($i = 0; $i < $total_worksheets; $i++) { $this->_worksheets[$i]->_BIFF_version = $version; } + $total_formats = count($this->_formats); + // change version for all formats too + for ($i = 0; $i < $total_formats; $i++) { + $this->_formats[$i]->_BIFF_version = $version; + } } } @@ -285,7 +297,8 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri } } - $worksheet = new Spreadsheet_Excel_Writer_Worksheet($name, $index, + $worksheet = new Spreadsheet_Excel_Writer_Worksheet($this->_BIFF_version, + $name, $index, $this->_activesheet, $this->_firstsheet, $this->_url_format, $this->_parser); @@ -459,6 +472,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri // Add Workbook globals $this->_storeBof(0x0005); if ($this->_BIFF_version == 0x0600) { + $this->_storeCodepage(); $this->_storeWindow1(); } if ($this->_BIFF_version == 0x0500) { @@ -484,15 +498,16 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri /* TODO: store COUNTRY record? */ if ($this->_BIFF_version == 0x0600) { - $this->_storeSupbookInternal(); + //$this->_storeSupbookInternal(); /* TODO: store external SUPBOOK records and XCT and CRN records in case of external references for BIFF8 */ - $this->_storeExternsheetBiff8(); + //$this->_storeExternsheetBiff8(); } /* TODO: store SST for BIFF8 */ + $this->_storeSharedStringsTable(); // End Workbook globals $this->_storeEof(); @@ -790,6 +805,23 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri * */ + /** + * Stores the CODEPAGE biff record. + * + * @access private + */ + function _storeCodepage() + { + $record = 0x0042; // Record identifier + $length = 0x0002; // Number of bytes to follow + $cv = $this->_codepage; // The code page + + $header = pack('vv', $record, $length); + $data = pack('v', $cv); + + $this->_append($header.$data); + } + /** * Write Excel BIFF WINDOW1 record. * @@ -822,6 +854,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri /** * Writes Excel BIFF BOUNDSHEET record. + * FIXME: inconsistent with BIFF documentation * * @param string $sheetname Worksheet name * @param integer $offset Location of worksheet BOF @@ -830,13 +863,13 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri function _storeBoundsheet($sheetname,$offset) { $record = 0x0085; // Record identifier - $length = 0x07 + strlen($sheetname); // Number of bytes to follow + $length = 0x08 + strlen($sheetname); // Number of bytes to follow - $grbit = 0x0000; // Sheet identifier + $grbit = 0x0000; // Visibility and sheet type $cch = strlen($sheetname); // Length of sheet name $header = pack("vv", $record, $length); - $data = pack("VvC", $offset, $grbit, $cch); + $data = pack("Vvv", $offset, $grbit, $cch); $this->_append($header.$data.$sheetname); } @@ -907,12 +940,24 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri function _storeNumFormat($format,$ifmt) { $record = 0x041E; // Record identifier - $length = 0x03 + strlen($format); // Number of bytes to follow - + + if ($this->_BIFF_version == 0x0600) { + $length = 5 + strlen($format); // Number of bytes to follow + $encoding = 0x0; + } + elseif ($this->_BIFF_version == 0x0500) { + $length = 3 + strlen($format); // Number of bytes to follow + } + $cch = strlen($format); // Length of format string $header = pack("vv", $record, $length); - $data = pack("vC", $ifmt, $cch); + if ($this->_BIFF_version == 0x0600) { + $data = pack("vvC", $ifmt, $cch, $encoding); + } + elseif ($this->_BIFF_version == 0x0500) { + $data = pack("vC", $ifmt, $cch); + } $this->_append($header.$data.$format); } @@ -1156,5 +1201,31 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri $header = pack("vvv", $record, $length, $ccv); $this->_append($header.$data); } + + /** + * Write all of the workbooks strings into an indexed array. + * See the comments in _calculate_shared_string_sizes() for more information. + * + * The Excel documentation says that the SST record should be followed by an + * EXTSST record. The EXTSST record is a hash table that is used to optimise + * access to SST. However, despite the documentation it doesn't seem to be + * required so we will ignore it. + * + * @access private + */ + function _storeSharedStringsTable() + { + $record = 0x00fc; // Record identifier + $length = 8; // Number of bytes to follow + + $this->_str_total = 0; + $this->_str_unique = 0; + + // Write the SST block header information + $header = pack("vv", $record, $length); + $data = pack("VV", $this->_str_total, $this->_str_unique); + $this->_append($header.$data); + + } } ?> diff --git a/Writer/Worksheet.php b/Writer/Worksheet.php index aae670b..40a8e76 100644 --- a/Writer/Worksheet.php +++ b/Writer/Worksheet.php @@ -285,7 +285,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr /** * Whether to use outline. - * @var bool + * @var integer */ var $_outline_on; @@ -340,13 +340,16 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr * @param mixed &$firstsheet The first worksheet in the workbook we belong to * @param mixed &$url_format The default format for hyperlinks * @param mixed &$parser The formula parser created for the Workbook + * @access private */ - function Spreadsheet_Excel_Writer_Worksheet($name, $index, &$activesheet, + function Spreadsheet_Excel_Writer_Worksheet($BIFF_version, $name, + $index, &$activesheet, &$firstsheet, &$url_format, &$parser) { // It needs to call its parent's constructor explicitly $this->Spreadsheet_Excel_Writer_BIFFwriter(); + $this->_BIFF_version = $BIFF_version; $rowmax = 65536; // 16384 in Excel 5 $colmax = 256; @@ -512,7 +515,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr $this->_storeWsbool(); // Prepend GUTS - $this->_storeGuts(); + //$this->_storeGuts(); // Prepend GRIDSET $this->_storeGridset(); @@ -524,14 +527,14 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr $this->_storePrintHeaders(); // Prepend EXTERNSHEET references - for ($i = $num_sheets; $i > 0; $i--) + /*for ($i = $num_sheets; $i > 0; $i--) { $sheetname = $sheetnames[$i-1]; $this->_storeExternsheet($sheetname); - } + }*/ // Prepend the EXTERNCOUNT of external references. - $this->_storeExterncount($num_sheets); + //$this->_storeExterncount($num_sheets); // Prepend the COLINFO records if they exist if (!empty($this->_colinfo)) @@ -556,7 +559,8 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr $this->_storePanes($this->_panes); } $this->_storeSelection($this->_selection); - $this->_storeDataValidity(); + /* TODO: add data validity */ + //$this->_storeDataValidity(); $this->_storeEof(); } @@ -1326,7 +1330,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr // Ensure this is a boolean vale for Window2 if ($this->_outline_on) { - $this->_outline_on = true; + $this->_outline_on = 1; } } @@ -2052,22 +2056,23 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr function storeDimensions() { $record = 0x0200; // Record identifier - $length = 0x000A; // Number of bytes to follow $row_min = $this->_dim_rowmin; // First row $row_max = $this->_dim_rowmax; // Last row plus 1 $col_min = $this->_dim_colmin; // First column $col_max = $this->_dim_colmax; // Last column plus 1 $reserved = 0x0000; // Reserved by Excel - $header = pack("vv", $record, $length); if ($this->_BIFF_version == 0x0500) { + $length = 0x000A; // Number of bytes to follow $data = pack("vvvvv", $row_min, $row_max, $col_min, $col_max, $reserved); } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x000E; $data = pack("VVvvv", $row_min, $row_max, $col_min, $col_max, $reserved); } + $header = pack("vv", $record, $length); $this->_prepend($header.$data); } @@ -2089,7 +2094,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr $grbit = 0x00B6; // Option flags $rwTop = 0x0000; // Top row visible in window $colLeft = 0x0000; // Leftmost column visible in window - $rgbHdr = 0x00000000; // Row/column heading and gridline color + // The options flags that comprise $grbit $fDspFmla = 0; // 0 - bit @@ -2118,13 +2123,16 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr $header = pack("vv", $record, $length); $data = pack("vvv", $grbit, $rwTop, $colLeft); + // FIXME !!! if ($this->_BIFF_version == 0x0500) { + $rgbHdr = 0x00000000; // Row/column heading and gridline color $data .= pack("V", $rgbHdr); } elseif ($this->_BIFF_version == 0x0600) { + $rgbHdr = 0x0040; // Row/column heading and gridline color index $zoom_factor_page_break = 0x0000; $zoom_factor_normal = 0x0000; - $data .= pack("vvvvV", 0x0001, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000); + $data .= pack("vvvvV", $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000); } $this->_append($header.$data); } @@ -2465,12 +2473,13 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr { $record = 0x0014; // Record identifier - $str = $this->_header; // header string - $cch = strlen($str); // Length of header string - $length = 1 + $cch; // Bytes to follow + $str = $this->_header; // header string + $cch = strlen($str); // Length of header string + $encoding = 0x0; // TODO: Unicode support + $length = 3 + $cch; // Bytes to follow - $header = pack("vv", $record, $length); - $data = pack("C", $cch); + $header = pack("vv", $record, $length); + $data = pack("vC", $cch, $encoding); $this->_append($header.$data.$str); } @@ -2484,12 +2493,13 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr { $record = 0x0015; // Record identifier - $str = $this->_footer; // Footer string - $cch = strlen($str); // Length of footer string - $length = 1 + $cch; // Bytes to follow + $str = $this->_footer; // Footer string + $cch = strlen($str); // Length of footer string + $encoding = 0x0; // TODO: Unicode support + $length = 3 + $cch; // Bytes to follow $header = pack("vv", $record, $length); - $data = pack("C", $cch); + $data = pack("vC", $cch, $encoding); $this->_append($header.$data.$str); } @@ -2808,21 +2818,21 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr // Sort and filter array of page breaks $breaks = $this->_hbreaks; - sort($breaks,SORT_NUMERIC); + sort($breaks, SORT_NUMERIC); if ($breaks[0] == 0) { // don't use first break if it's 0 array_shift($breaks); } $record = 0x001b; // Record identifier $cbrk = count($breaks); // Number of page breaks - $length = ($cbrk + 1) * 2; // Bytes to follow + $length = 2 + 6*$cbrk; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("v", $cbrk); // Append each page break foreach($breaks as $break) { - $data .= pack("v", $break); + $data .= pack("vvv", $break, 0x0000, 0x00ff); } $this->_prepend($header.$data); @@ -2846,21 +2856,21 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr $breaks = array_slice($this->_vbreaks,0,1000); // Sort and filter array of page breaks - sort($breaks,SORT_NUMERIC); + sort($breaks, SORT_NUMERIC); if ($breaks[0] == 0) { // don't use first break if it's 0 array_shift($breaks); } $record = 0x001a; // Record identifier $cbrk = count($breaks); // Number of page breaks - $length = ($cbrk + 1) * 2; // Bytes to follow + $length = 2 + 6*$cbrk; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("v", $cbrk); // Append each page break foreach ($breaks as $break) { - $data .= pack("v", $break); + $data .= pack("vvv", $break, 0x0000, 0xffff); } $this->_prepend($header.$data);