PHPExcel_Writer_Excel5
[ class tree: PHPExcel_Writer_Excel5 ] [ index: PHPExcel_Writer_Excel5 ] [ all elements ]

Source for file Workbook.php

Documentation is available at Workbook.php

  1. <?php
  2. /**
  3.  * PHPExcel
  4.  *
  5.  * Copyright (c) 2006 - 2011 PHPExcel
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  20.  *
  21.  * @category   PHPExcel
  22.  * @package    PHPExcel_Writer_Excel5
  23.  * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version    1.7.6, 2011-02-27
  26.  */
  27.  
  28. // Original file header of PEAR::Spreadsheet_Excel_Writer_Workbook (used as the base for this class):
  29. // -----------------------------------------------------------------------------------------
  30. // /*
  31. // *  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
  32. // *
  33. // *  The majority of this is _NOT_ my code.  I simply ported it from the
  34. // *  PERL Spreadsheet::WriteExcel module.
  35. // *
  36. // *  The author of the Spreadsheet::WriteExcel module is John McNamara
  37. // *  <jmcnamara@cpan.org>
  38. // *
  39. // *  I _DO_ maintain this code, and John McNamara has nothing to do with the
  40. // *  porting of this code to PHP.  Any questions directly related to this
  41. // *  class library should be directed to me.
  42. // *
  43. // *  License Information:
  44. // *
  45. // *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
  46. // *    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
  47. // *
  48. // *    This library is free software; you can redistribute it and/or
  49. // *    modify it under the terms of the GNU Lesser General Public
  50. // *    License as published by the Free Software Foundation; either
  51. // *    version 2.1 of the License, or (at your option) any later version.
  52. // *
  53. // *    This library is distributed in the hope that it will be useful,
  54. // *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  55. // *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  56. // *    Lesser General Public License for more details.
  57. // *
  58. // *    You should have received a copy of the GNU Lesser General Public
  59. // *    License along with this library; if not, write to the Free Software
  60. // *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  61. // */
  62.  
  63.  
  64. /**
  65.  * PHPExcel_Writer_Excel5_Workbook
  66.  *
  67.  * @category   PHPExcel
  68.  * @package    PHPExcel_Writer_Excel5
  69.  * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
  70.  */
  71. {
  72.     /**
  73.      * Formula parser
  74.      *
  75.      * @var PHPExcel_Writer_Excel5_Parser 
  76.      */
  77.     private $_parser;
  78.  
  79.     /**
  80.      * The BIFF file size for the workbook.
  81.      * @var integer 
  82.      * @see _calcSheetOffsets()
  83.      */
  84.     public $_biffsize;
  85.  
  86.     /**
  87.      * XF Writers
  88.      * @var PHPExcel_Writer_Excel5_Xf[] 
  89.      */
  90.     private $_xfWriters array();
  91.  
  92.     /**
  93.      * Array containing the colour palette
  94.      * @var array 
  95.      */
  96.     public $_palette;
  97.  
  98.     /**
  99.      * The codepage indicates the text encoding used for strings
  100.      * @var integer 
  101.      */
  102.     public $_codepage;
  103.  
  104.     /**
  105.      * The country code used for localization
  106.      * @var integer 
  107.      */
  108.     public $_country_code;
  109.  
  110.     /**
  111.      * Workbook
  112.      * @var PHPExcel 
  113.      */
  114.     private $_phpExcel;
  115.  
  116.     /**
  117.      * Fonts writers
  118.      *
  119.      * @var PHPExcel_Writer_Excel5_Font[] 
  120.      */
  121.     private $_fontWriters array();
  122.  
  123.     /**
  124.      * Added fonts. Maps from font's hash => index in workbook
  125.      *
  126.      * @var array 
  127.      */
  128.     private $_addedFonts array();
  129.  
  130.     /**
  131.      * Shared number formats
  132.      *
  133.      * @var array 
  134.      */
  135.     private $_numberFormats array();
  136.  
  137.     /**
  138.      * Added number formats. Maps from numberFormat's hash => index in workbook
  139.      *
  140.      * @var array 
  141.      */
  142.     private $_addedNumberFormats array();
  143.  
  144.     /**
  145.      * Sizes of the binary worksheet streams
  146.      *
  147.      * @var array 
  148.      */
  149.     private $_worksheetSizes array();
  150.  
  151.     /**
  152.      * Offsets of the binary worksheet streams relative to the start of the global workbook stream
  153.      *
  154.      * @var array 
  155.      */
  156.     private $_worksheetOffsets array();
  157.  
  158.     /**
  159.      * Total number of shared strings in workbook
  160.      *
  161.      * @var int 
  162.      */
  163.     private $_str_total;
  164.  
  165.     /**
  166.      * Number of unique shared strings in workbook
  167.      *
  168.      * @var int 
  169.      */
  170.     private $_str_unique;
  171.  
  172.     /**
  173.      * Array of unique shared strings in workbook
  174.      *
  175.      * @var array 
  176.      */
  177.     private $_str_table;
  178.  
  179.     /**
  180.      * Color cache
  181.      */
  182.     private $_colors;
  183.  
  184.     /**
  185.      * Escher object corresponding to MSODRAWINGGROUP
  186.      *
  187.      * @var PHPExcel_Shared_Escher 
  188.      */
  189.     private $_escher;
  190.  
  191.  
  192.     /**
  193.      * Class constructor
  194.      *
  195.      * @param PHPExcel $phpExcel The Workbook
  196.      * @param int $BIFF_verions BIFF version
  197.      * @param int  $str_total        Total number of strings
  198.      * @param int  $str_unique        Total number of unique strings
  199.      * @param array  $str_table 
  200.      * @param mixed   $parser      The formula parser created for the Workbook
  201.      */
  202.     public function __construct(PHPExcel $phpExcel null$BIFF_version 0x0600,
  203.                                                 &$str_total,
  204.                                                 &$str_unique&$str_table&$colors$parser
  205.                                 )
  206.     {
  207.         // It needs to call its parent's constructor explicitly
  208.         parent::__construct();
  209.  
  210.         $this->_parser           $parser;
  211.         $this->_biffsize         = 0;
  212.         $this->_palette          = array();
  213.         $this->_codepage         = 0x04E4// FIXME: should change for BIFF8
  214.         $this->_country_code     = -1;
  215.  
  216.         $this->_str_total       &$str_total;
  217.         $this->_str_unique      &$str_unique;
  218.         $this->_str_table       &$str_table;
  219.         $this->_colors          &$colors;
  220.         $this->_setPaletteXl97();
  221.  
  222.         $this->_phpExcel $phpExcel;
  223.  
  224.         if ($BIFF_version == 0x0600{
  225.             $this->_BIFF_version = 0x0600;
  226.             // change BIFFwriter limit for CONTINUE records
  227.             $this->_limit = 8224;
  228.             $this->_codepage = 0x04B0;
  229.         }
  230.  
  231.         // Add empty sheets and Build color cache
  232.         $countSheets $phpExcel->getSheetCount();
  233.         for ($i 0$i $countSheets++$i{
  234.             $phpSheet $phpExcel->getSheet($i);
  235.  
  236.             $this->_parser->setExtSheet($phpSheet->getTitle()$i);  // Register worksheet name with parser
  237.  
  238.             // for BIFF8
  239.             if ($this->_BIFF_version == 0x0600{
  240.                 $supbook_index 0x00;
  241.                 $ref pack('vvv'$supbook_index$i$i);
  242.                 $this->_parser->_references[$ref;  // Register reference with parser
  243.             }
  244.             // Sheet tab colors?
  245.             if ($phpSheet->isTabColorSet()) {
  246.                 $this->_addColor($phpSheet->getTabColor()->getRGB());
  247.             }
  248.         }
  249.  
  250.     }
  251.  
  252.     /**
  253.      * Add a new XF writer
  254.      *
  255.      * @param PHPExcel_Style 
  256.      * @param boolean Is it a style XF?
  257.      * @return int Index to XF record
  258.      */
  259.     public function addXfWriter($style$isStyleXf false)
  260.     {
  261.         $xfWriter new PHPExcel_Writer_Excel5_Xf($style);
  262.         $xfWriter->setBIFFVersion($this->_BIFF_version);
  263.         $xfWriter->setIsStyleXf($isStyleXf);
  264.  
  265.         // Add the font if not already added
  266.         $fontHashCode $style->getFont()->getHashCode();
  267.  
  268.         if (isset($this->_addedFonts[$fontHashCode])) {
  269.             $fontIndex $this->_addedFonts[$fontHashCode];
  270.         else {
  271.             $countFonts count($this->_fontWriters);
  272.             $fontIndex ($countFonts 4$countFonts $countFonts 1;
  273.  
  274.             $fontWriter new PHPExcel_Writer_Excel5_Font($style->getFont());
  275.             $fontWriter->setBIFFVersion($this->_BIFF_version);
  276.             $fontWriter->setColorIndex($this->_addColor($style->getFont()->getColor()->getRGB()));
  277.             $this->_fontWriters[$fontWriter;
  278.  
  279.             $this->_addedFonts[$fontHashCode$fontIndex;
  280.         }
  281.  
  282.         // Assign the font index to the xf record
  283.         $xfWriter->setFontIndex($fontIndex);
  284.  
  285.         // Background colors, best to treat these after the font so black will come after white in custom palette
  286.         $xfWriter->setFgColor($this->_addColor($style->getFill()->getStartColor()->getRGB()));
  287.         $xfWriter->setBgColor($this->_addColor($style->getFill()->getEndColor()->getRGB()));
  288.         $xfWriter->setBottomColor($this->_addColor($style->getBorders()->getBottom()->getColor()->getRGB()));
  289.         $xfWriter->setTopColor($this->_addColor($style->getBorders()->getTop()->getColor()->getRGB()));
  290.         $xfWriter->setRightColor($this->_addColor($style->getBorders()->getRight()->getColor()->getRGB()));
  291.         $xfWriter->setLeftColor($this->_addColor($style->getBorders()->getLeft()->getColor()->getRGB()));
  292.         $xfWriter->setDiagColor($this->_addColor($style->getBorders()->getDiagonal()->getColor()->getRGB()));
  293.  
  294.         // Add the number format if it is not a built-in one and not already added
  295.         if ($style->getNumberFormat()->getBuiltInFormatCode(=== false{
  296.             $numberFormatHashCode $style->getNumberFormat()->getHashCode();
  297.  
  298.             if (isset($this->_addedNumberFormats[$numberFormatHashCode])) {
  299.                 $numberFormatIndex $this->_addedNumberFormats[$numberFormatHashCode];
  300.             else {
  301.                 $numberFormatIndex 164 count($this->_numberFormats);
  302.                 $this->_numberFormats[$numberFormatIndex$style->getNumberFormat();
  303.                 $this->_addedNumberFormats[$numberFormatHashCode$numberFormatIndex;
  304.             }
  305.         }
  306.         else {
  307.             $numberFormatIndex = (int) $style->getNumberFormat()->getBuiltInFormatCode();
  308.         }
  309.  
  310.         // Assign the number format index to xf record
  311.         $xfWriter->setNumberFormatIndex($numberFormatIndex);
  312.  
  313.         $this->_xfWriters[$xfWriter;
  314.  
  315.         $xfIndex count($this->_xfWriters1;
  316.         return $xfIndex;
  317.     }
  318.  
  319.     /**
  320.      * Alter color palette adding a custom color
  321.      *
  322.      * @param string $rgb E.g. 'FF00AA'
  323.      * @return int Color index
  324.      */
  325.     private function _addColor($rgb{
  326.         if (!isset($this->_colors[$rgb])) {
  327.             if (count($this->_colors57{
  328.                 // then we add a custom color altering the palette
  329.                 $colorIndex count($this->_colors);
  330.                 $this->_palette[$colorIndex=
  331.                     array(
  332.                         hexdec(substr($rgb02)),
  333.                         hexdec(substr($rgb22)),
  334.                         hexdec(substr($rgb4)),
  335.                         0
  336.                     );
  337.                 $this->_colors[$rgb$colorIndex;
  338.             else {
  339.                 // no room for more custom colors, just map to black
  340.                 $colorIndex 0;
  341.             }
  342.         else {
  343.             // fetch already added custom color
  344.             $colorIndex $this->_colors[$rgb];
  345.         }
  346.  
  347.         return $colorIndex;
  348.     }
  349.  
  350.     /**
  351.      * Sets the colour palette to the Excel 97+ default.
  352.      *
  353.      * @access private
  354.      */
  355.     function _setPaletteXl97()
  356.     {
  357.         $this->_palette = array(
  358.             0x08 => array(0x000x000x000x00),
  359.             0x09 => array(0xff0xff0xff0x00),
  360.             0x0A => array(0xff0x000x000x00),
  361.             0x0B => array(0x000xff0x000x00),
  362.             0x0C => array(0x000x000xff0x00),
  363.             0x0D => array(0xff0xff0x000x00),
  364.             0x0E => array(0xff0x000xff0x00),
  365.             0x0F => array(0x000xff0xff0x00),
  366.             0x10 => array(0x800x000x000x00),
  367.             0x11 => array(0x000x800x000x00),
  368.             0x12 => array(0x000x000x800x00),
  369.             0x13 => array(0x800x800x000x00),
  370.             0x14 => array(0x800x000x800x00),
  371.             0x15 => array(0x000x800x800x00),
  372.             0x16 => array(0xc00xc00xc00x00),
  373.             0x17 => array(0x800x800x800x00),
  374.             0x18 => array(0x990x990xff0x00),
  375.             0x19 => array(0x990x330x660x00),
  376.             0x1A => array(0xff0xff0xcc0x00),
  377.             0x1B => array(0xcc0xff0xff0x00),
  378.             0x1C => array(0x660x000x660x00),
  379.             0x1D => array(0xff0x800x800x00),
  380.             0x1E => array(0x000x660xcc0x00),
  381.             0x1F => array(0xcc0xcc0xff0x00),
  382.             0x20 => array(0x000x000x800x00),
  383.             0x21 => array(0xff0x000xff0x00),
  384.             0x22 => array(0xff0xff0x000x00),
  385.             0x23 => array(0x000xff0xff0x00),
  386.             0x24 => array(0x800x000x800x00),
  387.             0x25 => array(0x800x000x000x00),
  388.             0x26 => array(0x000x800x800x00),
  389.             0x27 => array(0x000x000xff0x00),
  390.             0x28 => array(0x000xcc0xff0x00),
  391.             0x29 => array(0xcc0xff0xff0x00),
  392.             0x2A => array(0xcc0xff0xcc0x00),
  393.             0x2B => array(0xff0xff0x990x00),
  394.             0x2C => array(0x990xcc0xff0x00),
  395.             0x2D => array(0xff0x990xcc0x00),
  396.             0x2E => array(0xcc0x990xff0x00),
  397.             0x2F => array(0xff0xcc0x990x00),
  398.             0x30 => array(0x330x660xff0x00),
  399.             0x31 => array(0x330xcc0xcc0x00),
  400.             0x32 => array(0x990xcc0x000x00),
  401.             0x33 => array(0xff0xcc0x000x00),
  402.             0x34 => array(0xff0x990x000x00),
  403.             0x35 => array(0xff0x660x000x00),
  404.             0x36 => array(0x660x660x990x00),
  405.             0x37 => array(0x960x960x960x00),
  406.             0x38 => array(0x000x330x660x00),
  407.             0x39 => array(0x330x990x660x00),
  408.             0x3A => array(0x000x330x000x00),
  409.             0x3B => array(0x330x330x000x00),
  410.             0x3C => array(0x990x330x000x00),
  411.             0x3D => array(0x990x330x660x00),
  412.             0x3E => array(0x330x330x990x00),
  413.             0x3F => array(0x330x330x330x00),
  414.         );
  415.     }
  416.  
  417.     /**
  418.      * Assemble worksheets into a workbook and send the BIFF data to an OLE
  419.      * storage.
  420.      *
  421.      * @param array $worksheetSizes The sizes in bytes of the binary worksheet streams
  422.      * @return string Binary data for workbook stream
  423.      */
  424.     public function writeWorkbook($pWorksheetSizes null)
  425.     {
  426.         $this->_worksheetSizes $pWorksheetSizes;
  427.  
  428.         // Calculate the number of selected worksheet tabs and call the finalization
  429.         // methods for each worksheet
  430.         $total_worksheets $this->_phpExcel->getSheetCount();
  431.  
  432.         // Add part 1 of the Workbook globals, what goes before the SHEET records
  433.         $this->_storeBof(0x0005);
  434.         $this->_writeCodepage();
  435.         if ($this->_BIFF_version == 0x0600{
  436.             $this->_writeWindow1();
  437.         }
  438.         if ($this->_BIFF_version == 0x0500{
  439.             $this->_writeExterns();    // For print area and repeat rows
  440.             $this->_writeNames();      // For print area and repeat rows
  441.         }
  442.         if ($this->_BIFF_version == 0x0500{
  443.             $this->_writeWindow1();
  444.         }
  445.         $this->_writeDatemode();
  446.         $this->_writeAllFonts();
  447.         $this->_writeAllNumFormats();
  448.         $this->_writeAllXfs();
  449.         $this->_writeAllStyles();
  450.         $this->_writePalette();
  451.  
  452.         // Prepare part 3 of the workbook global stream, what goes after the SHEET records
  453.         $part3 '';
  454.         if ($this->_country_code != -1{
  455.             $part3 .= $this->_writeCountry();
  456.         }
  457.         $part3 .= $this->_writeRecalcId();
  458.  
  459.         if ($this->_BIFF_version == 0x0600{
  460.             $part3 .= $this->_writeSupbookInternal();
  461.             /* TODO: store external SUPBOOK records and XCT and CRN records
  462.             in case of external references for BIFF8 */
  463.             $part3 .= $this->_writeExternsheetBiff8();
  464.             $part3 .= $this->_writeAllDefinedNamesBiff8();
  465.             $part3 .= $this->_writeMsoDrawingGroup();
  466.             $part3 .= $this->_writeSharedStringsTable();
  467.         }
  468.  
  469.         $part3 .= $this->writeEof();
  470.  
  471.         // Add part 2 of the Workbook globals, the SHEET records
  472.         $this->_calcSheetOffsets();
  473.         for ($i 0$i $total_worksheets++$i{
  474.             $this->_writeBoundsheet($this->_phpExcel->getSheet($i)$this->_worksheetOffsets[$i]);
  475.         }
  476.  
  477.         // Add part 3 of the Workbook globals
  478.         $this->_data .= $part3;
  479.  
  480.         return $this->_data;
  481.     }
  482.  
  483.     /**
  484.      * Calculate offsets for Worksheet BOF records.
  485.      *
  486.      * @access private
  487.      */
  488.     function _calcSheetOffsets()
  489.     {
  490.         if ($this->_BIFF_version == 0x0600{
  491.             $boundsheet_length 10;  // fixed length for a BOUNDSHEET record
  492.         else {
  493.             $boundsheet_length 11;
  494.         }
  495.  
  496.         // size of Workbook globals part 1 + 3
  497.         $offset            $this->_datasize;
  498.  
  499.         // add size of Workbook globals part 2, the length of the SHEET records
  500.         $total_worksheets count($this->_phpExcel->getAllSheets());
  501.         foreach ($this->_phpExcel->getWorksheetIterator(as $sheet{
  502.             if ($this->_BIFF_version == 0x0600{
  503.                 $offset += $boundsheet_length strlen(PHPExcel_Shared_String::UTF8toBIFF8UnicodeShort($sheet->getTitle()));
  504.             else {
  505.                 $offset += $boundsheet_length strlen($sheet->getTitle());
  506.             }
  507.         }
  508.  
  509.         // add the sizes of each of the Sheet substreams, respectively
  510.         for ($i 0$i $total_worksheets++$i{
  511.             $this->_worksheetOffsets[$i$offset;
  512.             $offset += $this->_worksheetSizes[$i];
  513.         }
  514.         $this->_biffsize = $offset;
  515.     }
  516.  
  517.     /**
  518.      * Store the Excel FONT records.
  519.      */
  520.     private function _writeAllFonts()
  521.     {
  522.         foreach ($this->_fontWriters as $fontWriter{
  523.             $this->_append($fontWriter->writeFont());
  524.         }
  525.     }
  526.  
  527.     /**
  528.      * Store user defined numerical formats i.e. FORMAT records
  529.      */
  530.     private function _writeAllNumFormats()
  531.     {
  532.         foreach ($this->_numberFormats as $numberFormatIndex => $numberFormat{
  533.             $this->_writeNumFormat($numberFormat->getFormatCode()$numberFormatIndex);
  534.         }
  535.     }
  536.  
  537.     /**
  538.      * Write all XF records.
  539.      */
  540.     private function _writeAllXfs()
  541.     {
  542.         foreach ($this->_xfWriters as $xfWriter{
  543.             $this->_append($xfWriter->writeXf());
  544.         }
  545.     }
  546.  
  547.     /**
  548.      * Write all STYLE records.
  549.      */
  550.     private function _writeAllStyles()
  551.     {
  552.         $this->_writeStyle();
  553.     }
  554.  
  555.     /**
  556.      * Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for
  557.      * the NAME records.
  558.      */
  559.     private function _writeExterns()
  560.     {
  561.         $countSheets $this->_phpExcel->getSheetCount();
  562.         // Create EXTERNCOUNT with number of worksheets
  563.         $this->_writeExterncount($countSheets);
  564.  
  565.         // Create EXTERNSHEET for each worksheet
  566.         for ($i 0$i $countSheets++$i{
  567.             $this->_writeExternsheet($phpExcel->getSheet($i)->getTitle());
  568.         }
  569.     }
  570.  
  571.     /**
  572.      * Write the NAME record to define the print area and the repeat rows and cols.
  573.      */
  574.     private function _writeNames()
  575.     {
  576.         // total number of sheets
  577.         $total_worksheets $this->_phpExcel->getSheetCount();
  578.  
  579.         // Create the print area NAME records
  580.         for ($i 0$i $total_worksheets++$i{
  581.             $sheetSetup $this->_phpExcel->getSheet($i)->getPageSetup();
  582.             // Write a Name record if the print area has been defined
  583.             if ($sheetSetup->isPrintAreaSet()) {
  584.                 // Print area
  585.                 $printArea PHPExcel_Cell::splitRange($sheetSetup->getPrintArea());
  586.                 $printArea $printArea[0];
  587.                 $printArea[0PHPExcel_Cell::coordinateFromString($printArea[0]);
  588.                 $printArea[1PHPExcel_Cell::coordinateFromString($printArea[1]);
  589.  
  590.                 $print_rowmin $printArea[0][11;
  591.                 $print_rowmax $printArea[1][11;
  592.                 $print_colmin PHPExcel_Cell::columnIndexFromString($printArea[0][0]1;
  593.                 $print_colmax PHPExcel_Cell::columnIndexFromString($printArea[1][0]1;
  594.  
  595.                 $this->_writeNameShort(
  596.                     $i// sheet index
  597.                     0x06// NAME type
  598.                     $print_rowmin,
  599.                     $print_rowmax,
  600.                     $print_colmin,
  601.                     $print_colmax
  602.                     );
  603.             }
  604.         }
  605.  
  606.         // Create the print title NAME records
  607.         for ($i 0$i $total_worksheets++$i{
  608.             $sheetSetup $this->_phpExcel->getSheet($i)->getPageSetup();
  609.  
  610.             // simultaneous repeatColumns repeatRows
  611.             if ($sheetSetup->isColumnsToRepeatAtLeftSet(&& $sheetSetup->isRowsToRepeatAtTopSet()) {
  612.                 $repeat $sheetSetup->getColumnsToRepeatAtLeft();
  613.                 $colmin PHPExcel_Cell::columnIndexFromString($repeat[0]1;
  614.                 $colmax PHPExcel_Cell::columnIndexFromString($repeat[1]1;
  615.  
  616.                 $repeat $sheetSetup->getRowsToRepeatAtTop();
  617.                 $rowmin $repeat[01;
  618.                 $rowmax $repeat[11;
  619.  
  620.                 $this->_writeNameLong(
  621.                     $i// sheet index
  622.                     0x07// NAME type
  623.                     $rowmin,
  624.                     $rowmax,
  625.                     $colmin,
  626.                     $colmax
  627.                     );
  628.  
  629.             // (exclusive) either repeatColumns or repeatRows
  630.             else if ($sheetSetup->isColumnsToRepeatAtLeftSet(|| $sheetSetup->isRowsToRepeatAtTopSet()) {
  631.  
  632.                 // Columns to repeat
  633.                 if ($sheetSetup->isColumnsToRepeatAtLeftSet()) {
  634.                     $repeat $sheetSetup->getColumnsToRepeatAtLeft();
  635.                     $colmin PHPExcel_Cell::columnIndexFromString($repeat[0]1;
  636.                     $colmax PHPExcel_Cell::columnIndexFromString($repeat[1]1;
  637.                 else {
  638.                     $colmin 0;
  639.                     $colmax 255;
  640.                 }
  641.  
  642.                 // Rows to repeat
  643.                 if ($sheetSetup->isRowsToRepeatAtTopSet()) {
  644.                     $repeat $sheetSetup->getRowsToRepeatAtTop();
  645.                     $rowmin $repeat[01;
  646.                     $rowmax $repeat[11;
  647.                 else {
  648.                     $rowmin 0;
  649.                     $rowmax 16383;
  650.                 }
  651.  
  652.                 $this->_writeNameShort(
  653.                     $i// sheet index
  654.                     0x07// NAME type
  655.                     $rowmin,
  656.                     $rowmax,
  657.                     $colmin,
  658.                     $colmax
  659.                     );
  660.             }
  661.         }
  662.     }
  663.  
  664.  
  665.     /**
  666.      * Writes all the DEFINEDNAME records (BIFF8).
  667.      * So far this is only used for repeating rows/columns (print titles) and print areas
  668.      */
  669.     private function _writeAllDefinedNamesBiff8()
  670.     {
  671.         $chunk '';
  672.  
  673.         // Named ranges
  674.         if (count($this->_phpExcel->getNamedRanges()) 0{
  675.             // Loop named ranges
  676.             $namedRanges $this->_phpExcel->getNamedRanges();
  677.             foreach ($namedRanges as $namedRange{
  678.  
  679.                 // Create absolute coordinate
  680.                 $range PHPExcel_Cell::splitRange($namedRange->getRange());
  681.                 for ($i 0$i count($range)$i++{
  682.                     $range[$i][0'\'' str_replace("'""''"$namedRange->getWorksheet()->getTitle()) '\'!' PHPExcel_Cell::absoluteCoordinate($range[$i][0]);
  683.                     if (isset($range[$i][1])) {
  684.                         $range[$i][1PHPExcel_Cell::absoluteCoordinate($range[$i][1]);
  685.                     }
  686.                 }
  687.                 $range PHPExcel_Cell::buildRange($range)// e.g. Sheet1!$A$1:$B$2
  688.  
  689.                 // parse formula
  690.                 try {
  691.                     $error $this->_parser->parse($range);
  692.                     $formulaData $this->_parser->toReversePolish();
  693.  
  694.                     // make sure tRef3d is of type tRef3dR (0x3A)
  695.                     if (isset($formulaData{0}and ($formulaData{0== "\x7A" or $formulaData{0== "\x5A")) {
  696.                         $formulaData "\x3A" substr($formulaData1);
  697.                     }
  698.  
  699.                     if ($namedRange->getLocalOnly()) {
  700.                         // local scope
  701.                         $scope $this->_phpExcel->getIndex($namedRange->getScope()) 1;
  702.                     else {
  703.                         // global scope
  704.                         $scope 0;
  705.                     }
  706.                     $chunk .= $this->writeData($this->_writeDefinedNameBiff8($namedRange->getName()$formulaData$scopefalse));
  707.  
  708.                 catch(Exception $e{
  709.                     // do nothing
  710.                 }
  711.             }
  712.         }
  713.  
  714.         // total number of sheets
  715.         $total_worksheets $this->_phpExcel->getSheetCount();
  716.  
  717.         // write the print titles (repeating rows, columns), if any
  718.         for ($i 0$i $total_worksheets++$i{
  719.             $sheetSetup $this->_phpExcel->getSheet($i)->getPageSetup();
  720.             // simultaneous repeatColumns repeatRows
  721.             if ($sheetSetup->isColumnsToRepeatAtLeftSet(&& $sheetSetup->isRowsToRepeatAtTopSet()) {
  722.                 $repeat $sheetSetup->getColumnsToRepeatAtLeft();
  723.                 $colmin PHPExcel_Cell::columnIndexFromString($repeat[0]1;
  724.                 $colmax PHPExcel_Cell::columnIndexFromString($repeat[1]1;
  725.  
  726.                 $repeat $sheetSetup->getRowsToRepeatAtTop();
  727.                 $rowmin $repeat[01;
  728.                 $rowmax $repeat[11;
  729.  
  730.                 // construct formula data manually
  731.                 $formulaData pack('Cv'0x290x17)// tMemFunc
  732.                 $formulaData .= pack('Cvvvvv'0x3B$i065535$colmin$colmax)// tArea3d
  733.                 $formulaData .= pack('Cvvvvv'0x3B$i$rowmin$rowmax0255)// tArea3d
  734.                 $formulaData .= pack('C'0x10)// tList
  735.  
  736.                 // store the DEFINEDNAME record
  737.                 $chunk .= $this->writeData($this->_writeDefinedNameBiff8(pack('C'0x07)$formulaData$i 1true));
  738.  
  739.             // (exclusive) either repeatColumns or repeatRows
  740.             else if ($sheetSetup->isColumnsToRepeatAtLeftSet(|| $sheetSetup->isRowsToRepeatAtTopSet()) {
  741.  
  742.                 // Columns to repeat
  743.                 if ($sheetSetup->isColumnsToRepeatAtLeftSet()) {
  744.                     $repeat $sheetSetup->getColumnsToRepeatAtLeft();
  745.                     $colmin PHPExcel_Cell::columnIndexFromString($repeat[0]1;
  746.                     $colmax PHPExcel_Cell::columnIndexFromString($repeat[1]1;
  747.                 else {
  748.                     $colmin 0;
  749.                     $colmax 255;
  750.                 }
  751.                 // Rows to repeat
  752.                 if ($sheetSetup->isRowsToRepeatAtTopSet()) {
  753.                     $repeat $sheetSetup->getRowsToRepeatAtTop();
  754.                     $rowmin $repeat[01;
  755.                     $rowmax $repeat[11;
  756.                 else {
  757.                     $rowmin 0;
  758.                     $rowmax 65535;
  759.                 }
  760.  
  761.                 // construct formula data manually because parser does not recognize absolute 3d cell references
  762.                 $formulaData pack('Cvvvvv'0x3B$i$rowmin$rowmax$colmin$colmax);
  763.  
  764.                 // store the DEFINEDNAME record
  765.                 $chunk .= $this->writeData($this->_writeDefinedNameBiff8(pack('C'0x07)$formulaData$i 1true));
  766.             }
  767.         }
  768.  
  769.         // write the print areas, if any
  770.         for ($i 0$i $total_worksheets++$i{
  771.             $sheetSetup $this->_phpExcel->getSheet($i)->getPageSetup();
  772.             if ($sheetSetup->isPrintAreaSet()) {
  773.                 // Print area, e.g. A3:J6,H1:X20
  774.                 $printArea PHPExcel_Cell::splitRange($sheetSetup->getPrintArea());
  775.                 $countPrintArea count($printArea);
  776.  
  777.                 $formulaData '';
  778.                 for ($j 0$j $countPrintArea++$j{
  779.                     $printAreaRect $printArea[$j]// e.g. A3:J6
  780.                     $printAreaRect[0PHPExcel_Cell::coordinateFromString($printAreaRect[0]);
  781.                     $printAreaRect[1PHPExcel_Cell::coordinateFromString($printAreaRect[1]);
  782.  
  783.                     $print_rowmin $printAreaRect[0][11;
  784.                     $print_rowmax $printAreaRect[1][11;
  785.                     $print_colmin PHPExcel_Cell::columnIndexFromString($printAreaRect[0][0]1;
  786.                     $print_colmax PHPExcel_Cell::columnIndexFromString($printAreaRect[1][0]1;
  787.  
  788.                     // construct formula data manually because parser does not recognize absolute 3d cell references
  789.                     $formulaData .= pack('Cvvvvv'0x3B$i$print_rowmin$print_rowmax$print_colmin$print_colmax);
  790.  
  791.                     if ($j 0{
  792.                         $formulaData .= pack('C'0x10)// list operator token ','
  793.                     }
  794.                 }
  795.  
  796.                 // store the DEFINEDNAME record
  797.                 $chunk .= $this->writeData($this->_writeDefinedNameBiff8(pack('C'0x06)$formulaData$i 1true));
  798.             }
  799.         }
  800.  
  801.         return $chunk;
  802.     }
  803.  
  804.     /**
  805.      * Write a DEFINEDNAME record for BIFF8 using explicit binary formula data
  806.      *
  807.      * @param    string        $name            The name in UTF-8
  808.      * @param    string        $formulaData    The binary formula data
  809.      * @param    string        $sheetIndex        1-based sheet index the defined name applies to. 0 = global
  810.      * @param    boolean        $isBuiltIn        Built-in name?
  811.      * @return    string    Complete binary record data
  812.      */
  813.     private function _writeDefinedNameBiff8($name$formulaData$sheetIndex 0$isBuiltIn false)
  814.     {
  815.         $record 0x0018;
  816.  
  817.         // option flags
  818.         $options $isBuiltIn 0x20 0x00;
  819.  
  820.         // length of the name, character count
  821.         $nlen PHPExcel_Shared_String::CountCharacters($name);
  822.  
  823.         // name with stripped length field
  824.         $name substr(PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($name)2);
  825.  
  826.         // size of the formula (in bytes)
  827.         $sz strlen($formulaData);
  828.  
  829.         // combine the parts
  830.         $data pack('vCCvvvCCCC'$options0$nlen$sz0$sheetIndex0000)
  831.             . $name $formulaData;
  832.         $length strlen($data);
  833.  
  834.         $header pack('vv'$record$length);
  835.  
  836.         return $header $data;
  837.     }
  838.  
  839.     /**
  840.      * Stores the CODEPAGE biff record.
  841.      */
  842.     private function _writeCodepage()
  843.     {
  844.         $record          0x0042;             // Record identifier
  845.         $length          0x0002;             // Number of bytes to follow
  846.         $cv              $this->_codepage;   // The code page
  847.  
  848.         $header          pack('vv'$record$length);
  849.         $data            pack('v',  $cv);
  850.  
  851.         $this->_append($header $data);
  852.     }
  853.  
  854.     /**
  855.      * Write Excel BIFF WINDOW1 record.
  856.      */
  857.     private function _writeWindow1()
  858.     {
  859.         $record    0x003D;                 // Record identifier
  860.         $length    0x0012;                 // Number of bytes to follow
  861.  
  862.         $xWn       0x0000;                 // Horizontal position of window
  863.         $yWn       0x0000;                 // Vertical position of window
  864.         $dxWn      0x25BC;                 // Width of window
  865.         $dyWn      0x1572;                 // Height of window
  866.  
  867.         $grbit     0x0038;                 // Option flags
  868.  
  869.         // not supported by PHPExcel, so there is only one selected sheet, the active
  870.         $ctabsel   1;       // Number of workbook tabs selected
  871.  
  872.         $wTabRatio 0x0258;                 // Tab to scrollbar ratio
  873.  
  874.         // not supported by PHPExcel, set to 0
  875.         $itabFirst 0;     // 1st displayed worksheet
  876.         $itabCur   $this->_phpExcel->getActiveSheetIndex();    // Active worksheet
  877.  
  878.         $header    pack("vv",        $record$length);
  879.         $data      pack("vvvvvvvvv"$xWn$yWn$dxWn$dyWn,
  880.                                        $grbit,
  881.                                        $itabCur$itabFirst,
  882.                                        $ctabsel$wTabRatio);
  883.         $this->_append($header $data);
  884.     }
  885.  
  886.     /**
  887.      * Writes Excel BIFF BOUNDSHEET record.
  888.      *
  889.      * @param PHPExcel_Worksheet  $sheet Worksheet name
  890.      * @param integer $offset    Location of worksheet BOF
  891.      */
  892.     private function _writeBoundsheet($sheet$offset)
  893.     {
  894.         $sheetname $sheet->getTitle();
  895.         $record    0x0085;                    // Record identifier
  896.  
  897.         // sheet state
  898.         switch ($sheet->getSheetState()) {
  899.             case PHPExcel_Worksheet::SHEETSTATE_VISIBLE:    $ss 0x00break;
  900.             case PHPExcel_Worksheet::SHEETSTATE_HIDDEN:        $ss 0x01break;
  901.             case PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN:    $ss 0x02break;
  902.             default$ss 0x00break;
  903.         }
  904.  
  905.         // sheet type
  906.         $st 0x00;
  907.  
  908.         $grbit     0x0000;                    // Visibility and sheet type
  909.  
  910.         if ($this->_BIFF_version == 0x0600{
  911.             $data      pack("VCC"$offset$ss$st);
  912.             $data .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeShort($sheetname);
  913.         else {
  914.             $cch       strlen($sheetname);        // Length of sheet name
  915.             $data      pack("VCCC"$offset$ss$st$cch);
  916.             $data .= $sheetname;
  917.         }
  918.  
  919.         $length strlen($data);
  920.         $header pack("vv",  $record$length);
  921.         $this->_append($header $data);
  922.     }
  923.  
  924.     /**
  925.      * Write Internal SUPBOOK record
  926.      */
  927.     private function _writeSupbookInternal()
  928.     {
  929.         $record    0x01AE;   // Record identifier
  930.         $length    0x0004;   // Bytes to follow
  931.  
  932.         $header    pack("vv"$record$length);
  933.         $data      pack("vv"$this->_phpExcel->getSheetCount()0x0401);
  934.         return $this->writeData($header $data);
  935.     }
  936.  
  937.     /**
  938.      * Writes the Excel BIFF EXTERNSHEET record. These references are used by
  939.      * formulas.
  940.      *
  941.      */
  942.     private function _writeExternsheetBiff8()
  943.     {
  944.         $total_references count($this->_parser->_references);
  945.         $record   0x0017;                     // Record identifier
  946.         $length   $total_references;  // Number of bytes to follow
  947.  
  948.         $supbook_index 0;           // FIXME: only using internal SUPBOOK record
  949.         $header           pack("vv",  $record$length);
  950.         $data             pack('v'$total_references);
  951.         for ($i 0$i $total_references++$i{
  952.             $data .= $this->_parser->_references[$i];
  953.         }
  954.         return $this->writeData($header $data);
  955.     }
  956.  
  957.     /**
  958.      * Write Excel BIFF STYLE records.
  959.      */
  960.     private function _writeStyle()
  961.     {
  962.         $record    0x0293;   // Record identifier
  963.         $length    0x0004;   // Bytes to follow
  964.  
  965.         $ixfe      0x8000;  // Index to cell style XF
  966.         $BuiltIn   0x00;     // Built-in style
  967.         $iLevel    0xff;     // Outline style level
  968.  
  969.         $header    pack("vv",  $record$length);
  970.         $data      pack("vCC"$ixfe$BuiltIn$iLevel);
  971.         $this->_append($header $data);
  972.     }
  973.  
  974.  
  975.     /**
  976.      * Writes Excel FORMAT record for non "built-in" numerical formats.
  977.      *
  978.      * @param string  $format Custom format string
  979.      * @param integer $ifmt   Format index code
  980.      */
  981.     private function _writeNumFormat($format$ifmt)
  982.     {
  983.         $record    0x041E;                      // Record identifier
  984.  
  985.         if ($this->_BIFF_version == 0x0600{
  986.             $numberFormatString PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($format);
  987.             $length    strlen($numberFormatString);      // Number of bytes to follow
  988.         elseif ($this->_BIFF_version == 0x0500{
  989.             $length    strlen($format);      // Number of bytes to follow
  990.         }
  991.  
  992.  
  993.         $header    pack("vv"$record$length);
  994.         if ($this->_BIFF_version == 0x0600{
  995.             $data      pack("v"$ifmt.  $numberFormatString;
  996.             $this->_append($header $data);
  997.         elseif ($this->_BIFF_version == 0x0500{
  998.             $cch       strlen($format);             // Length of format string
  999.             $data      pack("vC"$ifmt$cch);
  1000.             $this->_append($header $data $format);
  1001.         }
  1002.     }
  1003.  
  1004.     /**
  1005.      * Write DATEMODE record to indicate the date system in use (1904 or 1900).
  1006.      */
  1007.     private function _writeDatemode()
  1008.     {
  1009.         $record    0x0022;         // Record identifier
  1010.         $length    0x0002;         // Bytes to follow
  1011.  
  1012.         $f1904     (PHPExcel_Shared_Date::getExcelCalendar(== PHPExcel_Shared_Date::CALENDAR_MAC_1904?
  1013.             0;   // Flag for 1904 date system
  1014.  
  1015.         $header    pack("vv"$record$length);
  1016.         $data      pack("v"$f1904);
  1017.         $this->_append($header $data);
  1018.     }
  1019.  
  1020.  
  1021.     /**
  1022.      * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
  1023.      * references in the workbook.
  1024.      *
  1025.      * Excel only stores references to external sheets that are used in NAME.
  1026.      * The workbook NAME record is required to define the print area and the repeat
  1027.      * rows and columns.
  1028.      *
  1029.      * A similar method is used in Worksheet.php for a slightly different purpose.
  1030.      *
  1031.      * @param integer $cxals Number of external references
  1032.      */
  1033.     private function _writeExterncount($cxals)
  1034.     {
  1035.         $record   0x0016;          // Record identifier
  1036.         $length   0x0002;          // Number of bytes to follow
  1037.  
  1038.         $header   pack("vv"$record$length);
  1039.         $data     pack("v",  $cxals);
  1040.         $this->_append($header $data);
  1041.     }
  1042.  
  1043.  
  1044.     /**
  1045.      * Writes the Excel BIFF EXTERNSHEET record. These references are used by
  1046.      * formulas. NAME record is required to define the print area and the repeat
  1047.      * rows and columns.
  1048.      *
  1049.      * A similar method is used in Worksheet.php for a slightly different purpose.
  1050.      *
  1051.      * @param string $sheetname Worksheet name
  1052.      */
  1053.     private function _writeExternsheet($sheetname)
  1054.     {
  1055.         $record      0x0017;                     // Record identifier
  1056.         $length      0x02 strlen($sheetname);  // Number of bytes to follow
  1057.  
  1058.         $cch         strlen($sheetname);         // Length of sheet name
  1059.         $rgch        0x03;                       // Filename encoding
  1060.  
  1061.         $header      pack("vv",  $record$length);
  1062.         $data        pack("CC"$cch$rgch);
  1063.         $this->_append($header $data $sheetname);
  1064.     }
  1065.  
  1066.  
  1067.     /**
  1068.      * Store the NAME record in the short format that is used for storing the print
  1069.      * area, repeat rows only and repeat columns only.
  1070.      *
  1071.      * @param integer $index  Sheet index
  1072.      * @param integer $type   Built-in name type
  1073.      * @param integer $rowmin Start row
  1074.      * @param integer $rowmax End row
  1075.      * @param integer $colmin Start colum
  1076.      * @param integer $colmax End column
  1077.      */
  1078.     private function _writeNameShort($index$type$rowmin$rowmax$colmin$colmax)
  1079.     {
  1080.         $record          0x0018;       // Record identifier
  1081.         $length          0x0024;       // Number of bytes to follow
  1082.  
  1083.         $grbit           0x0020;       // Option flags
  1084.         $chKey           0x00;         // Keyboard shortcut
  1085.         $cch             0x01;         // Length of text name
  1086.         $cce             0x0015;       // Length of text definition
  1087.         $ixals           $index 1;   // Sheet index
  1088.         $itab            $ixals;       // Equal to ixals
  1089.         $cchCustMenu     0x00;         // Length of cust menu text
  1090.         $cchDescription  0x00;         // Length of description text
  1091.         $cchHelptopic    0x00;         // Length of help topic text
  1092.         $cchStatustext   0x00;         // Length of status bar text
  1093.         $rgch            $type;        // Built-in name type
  1094.  
  1095.         $unknown03       0x3b;
  1096.         $unknown04       0xffff-$index;
  1097.         $unknown05       0x0000;
  1098.         $unknown06       0x0000;
  1099.         $unknown07       0x1087;
  1100.         $unknown08       0x8005;
  1101.  
  1102.         $header             pack("vv"$record$length);
  1103.         $data               pack("v"$grbit);
  1104.         $data              .= pack("C"$chKey);
  1105.         $data              .= pack("C"$cch);
  1106.         $data              .= pack("v"$cce);
  1107.         $data              .= pack("v"$ixals);
  1108.         $data              .= pack("v"$itab);
  1109.         $data              .= pack("C"$cchCustMenu);
  1110.         $data              .= pack("C"$cchDescription);
  1111.         $data              .= pack("C"$cchHelptopic);
  1112.         $data              .= pack("C"$cchStatustext);
  1113.         $data              .= pack("C"$rgch);
  1114.         $data              .= pack("C"$unknown03);
  1115.         $data              .= pack("v"$unknown04);
  1116.         $data              .= pack("v"$unknown05);
  1117.         $data              .= pack("v"$unknown06);
  1118.         $data              .= pack("v"$unknown07);
  1119.         $data              .= pack("v"$unknown08);
  1120.         $data              .= pack("v"$index);
  1121.         $data              .= pack("v"$index);
  1122.         $data              .= pack("v"$rowmin);
  1123.         $data              .= pack("v"$rowmax);
  1124.         $data              .= pack("C"$colmin);
  1125.         $data              .= pack("C"$colmax);
  1126.         $this->_append($header $data);
  1127.     }
  1128.  
  1129.  
  1130.     /**
  1131.      * Store the NAME record in the long format that is used for storing the repeat
  1132.      * rows and columns when both are specified. This shares a lot of code with
  1133.      * _writeNameShort() but we use a separate method to keep the code clean.
  1134.      * Code abstraction for reuse can be carried too far, and I should know. ;-)
  1135.      *
  1136.      * @param integer $index Sheet index
  1137.      * @param integer $type  Built-in name type
  1138.      * @param integer $rowmin Start row
  1139.      * @param integer $rowmax End row
  1140.      * @param integer $colmin Start colum
  1141.      * @param integer $colmax End column
  1142.      */
  1143.     private function _writeNameLong($index$type$rowmin$rowmax$colmin$colmax)
  1144.     {
  1145.         $record          0x0018;       // Record identifier
  1146.         $length          0x003d;       // Number of bytes to follow
  1147.         $grbit           0x0020;       // Option flags
  1148.         $chKey           0x00;         // Keyboard shortcut
  1149.         $cch             0x01;         // Length of text name
  1150.         $cce             0x002e;       // Length of text definition
  1151.         $ixals           $index 1;   // Sheet index
  1152.         $itab            $ixals;       // Equal to ixals
  1153.         $cchCustMenu     0x00;         // Length of cust menu text
  1154.         $cchDescription  0x00;         // Length of description text
  1155.         $cchHelptopic    0x00;         // Length of help topic text
  1156.         $cchStatustext   0x00;         // Length of status bar text
  1157.         $rgch            $type;        // Built-in name type
  1158.  
  1159.         $unknown01       0x29;
  1160.         $unknown02       0x002b;
  1161.         $unknown03       0x3b;
  1162.         $unknown04       0xffff-$index;
  1163.         $unknown05       0x0000;
  1164.         $unknown06       0x0000;
  1165.         $unknown07       0x1087;
  1166.         $unknown08       0x8008;
  1167.  
  1168.         $header             pack("vv",  $record$length);
  1169.         $data               pack("v"$grbit);
  1170.         $data              .= pack("C"$chKey);
  1171.         $data              .= pack("C"$cch);
  1172.         $data              .= pack("v"$cce);
  1173.         $data              .= pack("v"$ixals);
  1174.         $data              .= pack("v"$itab);
  1175.         $data              .= pack("C"$cchCustMenu);
  1176.         $data              .= pack("C"$cchDescription);
  1177.         $data              .= pack("C"$cchHelptopic);
  1178.         $data              .= pack("C"$cchStatustext);
  1179.         $data              .= pack("C"$rgch);
  1180.         $data              .= pack("C"$unknown01);
  1181.         $data              .= pack("v"$unknown02);
  1182.         // Column definition
  1183.         $data              .= pack("C"$unknown03);
  1184.         $data              .= pack("v"$unknown04);
  1185.         $data              .= pack("v"$unknown05);
  1186.         $data              .= pack("v"$unknown06);
  1187.         $data              .= pack("v"$unknown07);
  1188.         $data              .= pack("v"$unknown08);
  1189.         $data              .= pack("v"$index);
  1190.         $data              .= pack("v"$index);
  1191.         $data              .= pack("v"0x0000);
  1192.         $data              .= pack("v"0x3fff);
  1193.         $data              .= pack("C"$colmin);
  1194.         $data              .= pack("C"$colmax);
  1195.         // Row definition
  1196.         $data              .= pack("C"$unknown03);
  1197.         $data              .= pack("v"$unknown04);
  1198.         $data              .= pack("v"$unknown05);
  1199.         $data              .= pack("v"$unknown06);
  1200.         $data              .= pack("v"$unknown07);
  1201.         $data              .= pack("v"$unknown08);
  1202.         $data              .= pack("v"$index);
  1203.         $data              .= pack("v"$index);
  1204.         $data              .= pack("v"$rowmin);
  1205.         $data              .= pack("v"$rowmax);
  1206.         $data              .= pack("C"0x00);
  1207.         $data              .= pack("C"0xff);
  1208.         // End of data
  1209.         $data              .= pack("C"0x10);
  1210.         $this->_append($header $data);
  1211.     }
  1212.  
  1213.     /**
  1214.      * Stores the COUNTRY record for localization
  1215.      *
  1216.      * @return string 
  1217.      */
  1218.     private function _writeCountry()
  1219.     {
  1220.         $record          0x008C;    // Record identifier
  1221.         $length          4;         // Number of bytes to follow
  1222.  
  1223.         $header pack('vv',  $record$length);
  1224.         /* using the same country code always for simplicity */
  1225.         $data pack('vv'$this->_country_code$this->_country_code);
  1226.         //$this->_append($header . $data);
  1227.         return $this->writeData($header $data);
  1228.     }
  1229.  
  1230.     /**
  1231.      * Write the RECALCID record
  1232.      *
  1233.      * @return string 
  1234.      */
  1235.     private function _writeRecalcId()
  1236.     {
  1237.         $record 0x01C1;    // Record identifier
  1238.         $length 8;         // Number of bytes to follow
  1239.  
  1240.         $header pack('vv',  $record$length);
  1241.  
  1242.         // by inspection of real Excel files, MS Office Excel 2007 writes this
  1243.         $data pack('VV'0x000001C10x00001E667);
  1244.  
  1245.         return $this->writeData($header $data);
  1246.     }
  1247.  
  1248.     /**
  1249.      * Stores the PALETTE biff record.
  1250.      */
  1251.     private function _writePalette()
  1252.     {
  1253.         $aref            $this->_palette;
  1254.  
  1255.         $record          0x0092;                 // Record identifier
  1256.         $length          count($aref);   // Number of bytes to follow
  1257.         $ccv             =         count($aref);   // Number of RGB values to follow
  1258.         $data '';                                // The RGB data
  1259.  
  1260.         // Pack the RGB data
  1261.         foreach ($aref as $color{
  1262.             foreach ($color as $byte{
  1263.                 $data .= pack("C",$byte);
  1264.             }
  1265.         }
  1266.  
  1267.         $header pack("vvv",  $record$length$ccv);
  1268.         $this->_append($header $data);
  1269.     }
  1270.  
  1271.     /**
  1272.      * Handling of the SST continue blocks is complicated by the need to include an
  1273.      * additional continuation byte depending on whether the string is split between
  1274.      * blocks or whether it starts at the beginning of the block. (There are also
  1275.      * additional complications that will arise later when/if Rich Strings are
  1276.      * supported).
  1277.      *
  1278.      * The Excel documentation says that the SST record should be followed by an
  1279.      * EXTSST record. The EXTSST record is a hash table that is used to optimise
  1280.      * access to SST. However, despite the documentation it doesn't seem to be
  1281.      * required so we will ignore it.
  1282.      *
  1283.      * @return string Binary data
  1284.      */
  1285.     private function _writeSharedStringsTable()
  1286.     {
  1287.         // maximum size of record data (excluding record header)
  1288.         $continue_limit 8224;
  1289.  
  1290.         // initialize array of record data blocks
  1291.         $recordDatas array();
  1292.  
  1293.         // start SST record data block with total number of strings, total number of unique strings
  1294.         $recordData pack("VV"$this->_str_total$this->_str_unique);
  1295.  
  1296.         // loop through all (unique) strings in shared strings table
  1297.         foreach (array_keys($this->_str_tableas $string{
  1298.  
  1299.             // here $string is a BIFF8 encoded string
  1300.  
  1301.             // length = character count
  1302.             $headerinfo unpack("vlength/Cencoding"$string);
  1303.  
  1304.             // currently, this is always 1 = uncompressed
  1305.             $encoding $headerinfo["encoding"];
  1306.  
  1307.             // initialize finished writing current $string
  1308.             $finished false;
  1309.  
  1310.             while ($finished === false{
  1311.  
  1312.                 // normally, there will be only one cycle, but if string cannot immediately be written as is
  1313.                 // there will be need for more than one cylcle, if string longer than one record data block, there
  1314.                 // may be need for even more cycles
  1315.  
  1316.                 if (strlen($recordDatastrlen($string$continue_limit{
  1317.                     // then we can write the string (or remainder of string) without any problems
  1318.                     $recordData .= $string;
  1319.  
  1320.                     // we are finished writing this string
  1321.                     $finished true;
  1322.  
  1323.                 else if (strlen($recordDatastrlen($string== $continue_limit{
  1324.                     // then we can also write the string (or remainder of string)
  1325.                     $recordData .= $string;
  1326.  
  1327.                     // but we close the record data block, and initialize a new one
  1328.                     $recordDatas[$recordData;
  1329.                     $recordData '';
  1330.  
  1331.                     // we are finished writing this string
  1332.                     $finished true;
  1333.  
  1334.                 else {
  1335.                     // special treatment writing the string (or remainder of the string)
  1336.                     // If the string is very long it may need to be written in more than one CONTINUE record.
  1337.  
  1338.                     // check how many bytes more there is room for in the current record
  1339.                     $space_remaining $continue_limit strlen($recordData);
  1340.  
  1341.                     // minimum space needed
  1342.                     // uncompressed: 2 byte string length length field + 1 byte option flags + 2 byte character
  1343.                     // compressed:   2 byte string length length field + 1 byte option flags + 1 byte character
  1344.                     $min_space_needed ($encoding == 14;
  1345.  
  1346.                     // We have two cases
  1347.                     // 1. space remaining is less than minimum space needed
  1348.                     //        here we must waste the space remaining and move to next record data block
  1349.                     // 2. space remaining is greater than or equal to minimum space needed
  1350.                     //        here we write as much as we can in the current block, then move to next record data block
  1351.  
  1352.                     // 1. space remaining is less than minimum space needed
  1353.                     if ($space_remaining $min_space_needed{
  1354.                         // we close the block, store the block data
  1355.                         $recordDatas[$recordData;
  1356.  
  1357.                         // and start new record data block where we start writing the string
  1358.                         $recordData '';
  1359.  
  1360.                     // 2. space remaining is greater than or equal to minimum space needed
  1361.                     else {
  1362.                         // initialize effective remaining space, for Unicode strings this may need to be reduced by 1, see below
  1363.                         $effective_space_remaining $space_remaining;
  1364.  
  1365.                         // for uncompressed strings, sometimes effective space remaining is reduced by 1
  1366.                         if $encoding == && (strlen($string$space_remaining== {
  1367.                             --$effective_space_remaining;
  1368.                         }
  1369.  
  1370.                         // one block fininshed, store the block data
  1371.                         $recordData .= substr($string0$effective_space_remaining);
  1372.  
  1373.                         $string substr($string$effective_space_remaining)// for next cycle in while loop
  1374.                         $recordDatas[$recordData;
  1375.  
  1376.                         // start new record data block with the repeated option flags
  1377.                         $recordData pack('C'$encoding);
  1378.                     }
  1379.                 }
  1380.             }
  1381.         }
  1382.  
  1383.         // Store the last record data block unless it is empty
  1384.         // if there was no need for any continue records, this will be the for SST record data block itself
  1385.         if (strlen($recordData0{
  1386.             $recordDatas[$recordData;
  1387.         }
  1388.  
  1389.         // combine into one chunk with all the blocks SST, CONTINUE,...
  1390.         $chunk '';
  1391.         foreach ($recordDatas as $i => $recordData{
  1392.             // first block should have the SST record header, remaing should have CONTINUE header
  1393.             $record ($i == 00x00FC 0x003C;
  1394.  
  1395.             $header pack("vv"$recordstrlen($recordData));
  1396.             $data $header $recordData;
  1397.  
  1398.             $chunk .= $this->writeData($data);
  1399.         }
  1400.  
  1401.         return $chunk;
  1402.     }
  1403.  
  1404.     /**
  1405.      * Writes the MSODRAWINGGROUP record if needed. Possibly split using CONTINUE records.
  1406.      */
  1407.     private function _writeMsoDrawingGroup()
  1408.     {
  1409.         // write the Escher stream if necessary
  1410.         if (isset($this->_escher)) {
  1411.             $writer new PHPExcel_Writer_Excel5_Escher($this->_escher);
  1412.             $data $writer->close();
  1413.  
  1414.             $record 0x00EB;
  1415.             $length strlen($data);
  1416.             $header pack("vv",  $record$length);
  1417.  
  1418.             return $this->writeData($header $data);
  1419.  
  1420.         else {
  1421.             return '';
  1422.         }
  1423.     }
  1424.  
  1425.     /**
  1426.      * Get Escher object
  1427.      *
  1428.      * @return PHPExcel_Shared_Escher 
  1429.      */
  1430.     public function getEscher()
  1431.     {
  1432.         return $this->_escher;
  1433.     }
  1434.  
  1435.     /**
  1436.      * Set Escher object
  1437.      *
  1438.      * @param PHPExcel_Shared_Escher $pValue 
  1439.      */
  1440.     public function setEscher(PHPExcel_Shared_Escher $pValue null)
  1441.     {
  1442.         $this->_escher $pValue;
  1443.     }
  1444.  
  1445. }

Documentation generated on Sun, 27 Feb 2011 16:37:07 -0800 by phpDocumentor 1.4.3