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

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