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

Source for file Worksheet.php

Documentation is available at Worksheet.php

  1. <?php
  2. /**
  3.  * PHPExcel
  4.  *
  5.  * Copyright (c) 2006 - 2010 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 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version    1.7.2, 2010-01-11
  26.  */
  27.  
  28. // Original file header of PEAR::Spreadsheet_Excel_Writer_Worksheet (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. /** PHPExcel root directory */
  65. if (!defined('PHPEXCEL_ROOT')) {
  66.     /**
  67.      * @ignore
  68.      */
  69.     define('PHPEXCEL_ROOT'dirname(__FILE__'/../../../');
  70. }
  71.  
  72. /** PHPExcel_Cell_DataType */
  73. require_once PHPEXCEL_ROOT 'PHPExcel/Cell/DataType.php';
  74.  
  75. /** PHPExcel_Writer_Excel5_Parser.php */
  76. require_once PHPEXCEL_ROOT 'PHPExcel/Writer/Excel5/Parser.php';
  77.  
  78. /** PHPExcel_Writer_Excel5_BIFFwriter.php */
  79. require_once PHPEXCEL_ROOT 'PHPExcel/Writer/Excel5/BIFFwriter.php';
  80.  
  81. /** PHPExcel_Writer_Excel5_Escher */
  82. require_once PHPEXCEL_ROOT 'PHPExcel/Writer/Excel5/Escher.php';
  83.  
  84. /** PHPExcel_RichText */
  85. require_once PHPEXCEL_ROOT 'PHPExcel/RichText.php';
  86.  
  87. /** PHPExcel_Shared_Font */
  88. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Font.php';
  89.  
  90. /** PHPExcel_Shared_String */
  91. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/String.php';
  92.  
  93. /** PHPExcel_Shared_Excel5 */
  94. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Excel5.php';
  95.  
  96. /** PHPExcel_Shared_Escher */
  97. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Escher.php';
  98.  
  99. /** PHPExcel_Shared_Escher_DgContainer */
  100. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Escher/DgContainer.php';
  101.  
  102. /** PHPExcel_Shared_Escher_DgContainer_SpgrContainer */
  103. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php';
  104.  
  105. /** PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer */
  106. require_once PHPEXCEL_ROOT 'PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php';
  107.  
  108.  
  109. /**
  110.  * PHPExcel_Writer_Excel5_Worksheet
  111.  *
  112.  * @category   PHPExcel
  113.  * @package    PHPExcel_Writer_Excel5
  114.  * @copyright  Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel)
  115.  */
  116. {
  117.     /**
  118.      * Formula parser
  119.      *
  120.      * @var PHPExcel_Writer_Excel5_Parser 
  121.      */
  122.     private $_parser;
  123.  
  124.     /**
  125.      * Filehandle to the temporary file for storing data
  126.      * @var resource 
  127.      */
  128.     var $_filehandle;
  129.  
  130.     /**
  131.      * Boolean indicating if we are using a temporary file for storing data
  132.      * @var bool 
  133.      */
  134.     var $_using_tmpfile;
  135.  
  136.     /**
  137.      * Maximum number of characters for a string (LABEL record in BIFF5)
  138.      * @var integer 
  139.      */
  140.     var $_xls_strmax;
  141.  
  142.     /**
  143.      * Array containing format information for columns
  144.      * @var array 
  145.      */
  146.     var $_colinfo;
  147.  
  148.     /**
  149.      * Array containing the selected area for the worksheet
  150.      * @var array 
  151.      */
  152.     var $_selection;
  153.  
  154.     /**
  155.      * The active pane for the worksheet
  156.      * @var integer 
  157.      */
  158.     var $_active_pane;
  159.  
  160.     /**
  161.      * Whether to use outline.
  162.      * @var integer 
  163.      */
  164.     var $_outline_on;
  165.  
  166.     /**
  167.      * Auto outline styles.
  168.      * @var bool 
  169.      */
  170.     var $_outline_style;
  171.  
  172.     /**
  173.      * Whether to have outline summary below.
  174.      * @var bool 
  175.      */
  176.     var $_outline_below;
  177.  
  178.     /**
  179.      * Whether to have outline summary at the right.
  180.      * @var bool 
  181.      */
  182.     var $_outline_right;
  183.  
  184.     /**
  185.      * Reference to the total number of strings in the workbook
  186.      * @var integer 
  187.      */
  188.     var $_str_total;
  189.  
  190.     /**
  191.      * Reference to the number of unique strings in the workbook
  192.      * @var integer 
  193.      */
  194.     var $_str_unique;
  195.  
  196.     /**
  197.      * Reference to the array containing all the unique strings in the workbook
  198.      * @var array 
  199.      */
  200.     var $_str_table;
  201.  
  202.     /**
  203.      * Color cache
  204.      */
  205.     private $_colors;
  206.  
  207.     /**
  208.      * The temporary dir for storing files
  209.      * @var string 
  210.      */
  211.     var $_tmp_dir;
  212.  
  213.     /**
  214.      * List of temporary files created
  215.      * @var array 
  216.      */
  217.     var $_tempFilesCreated = array();
  218.  
  219.     /**
  220.      * Index of first used row (at least 0)
  221.      * @var int 
  222.      */
  223.     private $_firstRowIndex;
  224.  
  225.     /**
  226.      * Index of last used row. (no used rows means -1)
  227.      * @var int 
  228.      */
  229.     private $_lastRowIndex;
  230.  
  231.     /**
  232.      * Index of first used column (at least 0)
  233.      * @var int 
  234.      */
  235.     private $_firstColumnIndex;
  236.  
  237.     /**
  238.      * Index of last used column (no used columns means -1)
  239.      * @var int 
  240.      */
  241.     private $_lastColumnIndex;
  242.  
  243.     /**
  244.      * Sheet object
  245.      * @var PHPExcel_Worksheet 
  246.      */
  247.     private $_phpSheet;
  248.  
  249.     /**
  250.      * Count cell style Xfs
  251.      *
  252.      * @var int 
  253.      */
  254.     private $_countCellStyleXfs;
  255.  
  256.     /**
  257.      * Constructor
  258.      *
  259.      * @param int  $BIFF_version         BIFF version
  260.      * @param int  $str_total        Total number of strings
  261.      * @param int  $str_unique        Total number of unique strings
  262.      * @param array  $str_table 
  263.      * @param mixed   $parser      The formula parser created for the Workbook
  264.      * @param string   $tempDir      The temporary directory to be used
  265.      * @param PHPExcel_Worksheet $phpSheet 
  266.      */
  267.     public function __construct($BIFF_version,
  268.                                                 &$str_total,
  269.                                                 &$str_unique&$str_table&$colors,
  270.                                                 $parser$tempDir ''$preCalculateFormulas$phpSheet)
  271.     {
  272.         // It needs to call its parent's constructor explicitly
  273.         parent::__construct();
  274.  
  275.         $this->_BIFF_version    = $BIFF_version;
  276.         if ($BIFF_version == 0x0600{
  277.             // change BIFFwriter limit for CONTINUE records
  278.             $this->_limit = 8224;
  279.         }
  280.  
  281.  
  282.         $this->_preCalculateFormulas $preCalculateFormulas;
  283.         $this->_str_total        = &$str_total;
  284.         $this->_str_unique        = &$str_unique;
  285.         $this->_str_table        = &$str_table;
  286.         $this->_colors            = &$colors;
  287.         $this->_parser            = $parser;
  288.         
  289.         $this->_phpSheet = $phpSheet;
  290.  
  291.         //$this->ext_sheets        = array();
  292.         $this->_filehandle        = '';
  293.         $this->_using_tmpfile    = true;
  294.         //$this->fileclosed        = 0;
  295.         //$this->offset            = 0;
  296.         $this->_xls_strmax        = 255;
  297.         $this->_colinfo            = array();
  298.         $this->_selection        = array(0,0,0,0);
  299.         $this->_active_pane        = 3;
  300.  
  301.         $this->_print_headers        0;
  302.  
  303.         $this->_outline_style        = 0;
  304.         $this->_outline_below        = 1;
  305.         $this->_outline_right        = 1;
  306.         $this->_outline_on            = 1;
  307.  
  308.         $this->_dv                array();
  309.  
  310.         $this->_tmp_dir            = $tempDir;
  311.  
  312.         // calculate values for DIMENSIONS record
  313.         $this->_firstRowIndex    =  0;
  314.         $this->_lastRowIndex     = -1;
  315.         $this->_firstColumnIndex =  0;
  316.         $this->_lastColumnIndex  = -1;
  317.  
  318.         foreach ($this->_phpSheet->getCellCollection(falseas $cell{
  319.             $row $cell->getRow(1;
  320.             $column PHPExcel_Cell::columnIndexFromString($cell->getColumn()) 1;
  321.  
  322.             // Don't break Excel!
  323.             if ($row 65536 or $column 256{
  324.                 break;
  325.             }
  326.  
  327.             $this->_firstRowIndex    = min($this->_firstRowIndex$row);
  328.             $this->_lastRowIndex     = max($this->_lastRowIndex$row);
  329.             $this->_firstColumnIndex = min($this->_firstColumnIndex$column);
  330.             $this->_lastColumnIndex  = max($this->_lastColumnIndex$column);
  331.         }
  332.  
  333.         $this->_initialize();
  334.         $this->_countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection());
  335.     }
  336.  
  337.     /**
  338.      * Cleanup
  339.      */
  340.     public function cleanup({
  341.         @fclose($this->_filehandle);
  342.  
  343.         foreach ($this->_tempFilesCreated as $file{
  344.             @unlink($file);
  345.         }
  346.     }
  347.  
  348.     /**
  349.      * Open a tmp file to store the majority of the Worksheet data. If this fails,
  350.      * for example due to write permissions, store the data in memory. This can be
  351.      * slow for large files.
  352.      *
  353.      * @access private
  354.      */
  355.     function _initialize()
  356.     {
  357.         // Open tmp file for storing Worksheet data
  358.         $fileName tempnam($this->_tmp_dir'XLSHEET');
  359.         $fh fopen($fileName'w+');
  360.         if ($fh{
  361.             // Store filehandle
  362.             $this->_filehandle = $fh;
  363.             $this->_tempFilesCreated[$fileName;
  364.         else {
  365.             // If tmpfile() fails store data in memory
  366.             $this->_using_tmpfile = false;
  367.         }
  368.     }
  369.  
  370.     /**
  371.      * Add data to the beginning of the workbook (note the reverse order)
  372.      * and to the end of the workbook.
  373.      *
  374.      * @access public
  375.      * @see PHPExcel_Writer_Excel5_Workbook::storeWorkbook()
  376.      */
  377.     function close()
  378.     {
  379.         $num_sheets count($this->_phpSheet->getParent()->getAllSheets());
  380.  
  381.         // Write BOF record
  382.         $this->_storeBof(0x0010);
  383.  
  384.         // Write DEFCOLWIDTH record
  385.         $this->_storeDefcol();
  386.  
  387.         // Calculate column widths
  388.         $this->_phpSheet->calculateColumnWidths();
  389.  
  390.         // Column dimensions
  391.         $columnDimensions $this->_phpSheet->getColumnDimensions();
  392.         for ($i 0$i 256++$i{
  393.             $hidden 0;
  394.             $level 0;
  395.             $xfIndex 15// there are 15 cell style Xfs
  396.  
  397.             if ($this->_phpSheet->getDefaultColumnDimension()->getWidth(>= 0{
  398.                 $width $this->_phpSheet->getDefaultColumnDimension()->getWidth();
  399.             else {
  400.                 $width PHPExcel_Shared_Font::getDefaultColumnWidthByFont($this->_phpSheet->getParent()->getDefaultStyle()->getFont());
  401.             }
  402.  
  403.             $columnLetter PHPExcel_Cell::stringFromColumnIndex($i);
  404.             if (isset($columnDimensions[$columnLetter])) {
  405.                 $columnDimension $columnDimensions[$columnLetter];
  406.                 if ($columnDimension->getWidth(>= 0{
  407.                     $width $columnDimension->getWidth();
  408.                 }
  409.                 $hidden $columnDimension->getVisible(1;
  410.                 $level $columnDimension->getOutlineLevel();
  411.                 $xfIndex $columnDimension->getXfIndex(15// there are 15 cell style Xfs
  412.             }
  413.  
  414.             $this->_setColumn$i$i$width$xfIndex$hidden$level);
  415.         }
  416.  
  417.         // Write the COLINFO records if they exist
  418.         if (!empty($this->_colinfo)) {
  419.             $colcount count($this->_colinfo);
  420.             for ($i 0$i $colcount++$i{
  421.                 $this->_storeColinfo($this->_colinfo[$i]);
  422.             }
  423.         }
  424.  
  425.         // Write EXTERNCOUNT of external references
  426.         if ($this->_BIFF_version == 0x0500{
  427.             $this->_storeExterncount($num_sheets);
  428.         }
  429.  
  430.         // Write EXTERNSHEET references
  431.         if ($this->_BIFF_version == 0x0500{
  432.             for ($i 0$i $num_sheets++$i{
  433.                 $this->_storeExternsheet($this->_phpSheet->getParent()->getSheet($i)->getTitle());
  434.             }
  435.         }
  436.  
  437.         // Write PRINTHEADERS
  438.         $this->_storePrintHeaders();
  439.  
  440.         // Write PRINTGRIDLINES
  441.         $this->_storePrintGridlines();
  442.  
  443.         // Write GUTS
  444.         $this->_storeGuts();
  445.  
  446.         // Write GRIDSET
  447.         $this->_storeGridset();
  448.  
  449.         // Write DEFAULTROWHEIGHT
  450.         if ($this->_BIFF_version == 0x0600{
  451.             $this->_storeDefaultRowHeight();
  452.         }
  453.  
  454.         // Write WSBOOL
  455.         $this->_storeWsbool();
  456.  
  457.         // Write horizontal and vertical page breaks
  458.         $this->_storeBreaks();
  459.  
  460.         // Write page header
  461.         $this->_storeHeader();
  462.  
  463.         // Write page footer
  464.         $this->_storeFooter();
  465.  
  466.         // Write page horizontal centering
  467.         $this->_storeHcenter();
  468.  
  469.         // Write page vertical centering
  470.         $this->_storeVcenter();
  471.  
  472.         // Write left margin
  473.         $this->_storeMarginLeft();
  474.  
  475.         // Write right margin
  476.         $this->_storeMarginRight();
  477.  
  478.         // Write top margin
  479.         $this->_storeMarginTop();
  480.  
  481.         // Write bottom margin
  482.         $this->_storeMarginBottom();
  483.  
  484.         // Write page setup
  485.         $this->_storeSetup();
  486.  
  487.         // Write sheet protection
  488.         $this->_storeProtect();
  489.  
  490.         // Write SCENPROTECT
  491.         $this->_writeScenProtect();
  492.  
  493.         // Write OBJECTPROTECT
  494.         $this->_writeObjectProtect();
  495.  
  496.         // Write sheet password
  497.         $this->_storePassword();
  498.  
  499.         // Write sheet dimensions
  500.         $this->_storeDimensions();
  501.  
  502.         // Row dimensions
  503.         foreach ($this->_phpSheet->getRowDimensions(as $rowDimension{
  504.             $xfIndex $rowDimension->getXfIndex(15// there are 15 cellXfs
  505.             $this->_setRow$rowDimension->getRowIndex(1$rowDimension->getRowHeight()$xfIndex($rowDimension->getVisible('0' '1')$rowDimension->getOutlineLevel() );
  506.         }
  507.  
  508.         // Write Cells
  509.         foreach ($this->_phpSheet->getCellCollection(as $cell{
  510.             $row $cell->getRow(1;
  511.             $column PHPExcel_Cell::columnIndexFromString($cell->getColumn()) 1;
  512.  
  513.             // Don't break Excel!
  514.             if ($row 65536 or $column 256{
  515.                 break;
  516.             }
  517.  
  518.             // Write cell value
  519.             $xfIndex $cell->getXfIndex(15// there are 15 cell style Xfs
  520.             
  521.             if ($cell->getValue(instanceof PHPExcel_RichText{
  522.                 $this->_writeString($row$column$cell->getValue()->getPlainText()$xfIndex);
  523.             else {
  524.                 switch ($cell->getDatatype()) {
  525.  
  526.                 case PHPExcel_Cell_DataType::TYPE_STRING:
  527.                     if ($cell->getValue(=== '' or $cell->getValue(=== null{
  528.                         $this->_writeBlank($row$column$xfIndex);
  529.                     else {
  530.                         $this->_writeString($row$column$cell->getValue()$xfIndex);
  531.                     }
  532.                     break;
  533.  
  534.                 case PHPExcel_Cell_DataType::TYPE_FORMULA:
  535.                     $calculatedValue $this->_preCalculateFormulas ?
  536.                         $cell->getCalculatedValue(null;
  537.                     $this->_writeFormula($row$column$cell->getValue()$xfIndex$calculatedValue);
  538.                     break;
  539.  
  540.                 case PHPExcel_Cell_DataType::TYPE_BOOL:
  541.                     $this->_writeBoolErr($row$column$cell->getValue()0$xfIndex);
  542.                     break;
  543.  
  544.                 case PHPExcel_Cell_DataType::TYPE_ERROR:
  545.                     $this->_writeBoolErr($row$column$this->_mapErrorCode($cell->getValue())1$xfIndex);
  546.                     break;
  547.  
  548.                 case PHPExcel_Cell_DataType::TYPE_NUMERIC:
  549.                     $this->_writeNumber($row$column$cell->getValue()$xfIndex);
  550.                     break;
  551.                 }
  552.             }
  553.         }
  554.  
  555.         // Append
  556.         if ($this->_BIFF_version == 0x0600{
  557.             $this->_storeMsoDrawing();
  558.         }
  559.         $this->_storeWindow2();
  560.         $this->_storeZoom();
  561.         if ($this->_phpSheet->getFreezePane()) {
  562.             $this->_storePanes();
  563.         }
  564.         $this->_storeSelection();
  565.         $this->_storeMergedCells();
  566.  
  567.         // Hyperlinks
  568.         if ($this->_BIFF_version == 0x0600{
  569.             foreach ($this->_phpSheet->getHyperLinkCollection(as $coordinate => $hyperlink{
  570.                 list($column$rowPHPExcel_Cell::coordinateFromString($coordinate);
  571.  
  572.                 $url $hyperlink->getUrl();
  573.  
  574.                 if strpos($url'sheet://'!== false {
  575.                     // internal to current workbook
  576.                     $url str_replace('sheet://''internal:'$url);
  577.  
  578.                 else if preg_match('/^(http:|https:|ftp:|mailto:)/'$url) ) {
  579.                     // URL
  580.                     // $url = $url;
  581.  
  582.                 else {
  583.                     // external (local file)
  584.                     $url 'external:' $url;
  585.                 }
  586.                 
  587.                 $this->_writeUrl($row 1PHPExcel_Cell::columnIndexFromString($column1$url);
  588.             }
  589.         }
  590.  
  591.         /*if ($this->_BIFF_version == 0x0600) {
  592.             $this->_storeDataValidity();
  593.         }*/
  594.  
  595.         if ($this->_BIFF_version == 0x0600{
  596.             $this->_storeSheetLayout();
  597.             $this->_writeSheetProtection();
  598.             $this->_storeRangeProtection();
  599.         }
  600.  
  601.         $this->_storeEof();
  602.     }
  603.  
  604.     /**
  605.      * Write a cell range address in BIFF8
  606.      * always fixed range
  607.      * See section 2.5.14 in OpenOffice.org's Documentation of the Microsoft Excel File Format
  608.      *
  609.      * @param string $range E.g. 'A1' or 'A1:B6'
  610.      * @return string Binary data
  611.      */
  612.     private function _writeBIFF8CellRangeAddressFixed($range 'A1')
  613.     {
  614.         $explodes explode(':'$range);
  615.  
  616.         // extract first cell, e.g. 'A1'
  617.         $firstCell $explodes[0];
  618.  
  619.         // extract last cell, e.g. 'B6'
  620.         if (count($explodes== 1{
  621.             $lastCell $firstCell;
  622.         else {
  623.             $lastCell $explodes[1];
  624.         }
  625.  
  626.         $firstCellCoordinates PHPExcel_Cell::coordinateFromString($firstCell)// e.g. array(0, 1)
  627.         $lastCellCoordinates  PHPExcel_Cell::coordinateFromString($lastCell);  // e.g. array(1, 6)
  628.  
  629.         $data pack('vvvv',
  630.             $firstCellCoordinates[11,
  631.             $lastCellCoordinates[11,
  632.             PHPExcel_Cell::columnIndexFromString($firstCellCoordinates[0]1,
  633.             PHPExcel_Cell::columnIndexFromString($lastCellCoordinates[0]1
  634.         );
  635.  
  636.         return $data;
  637.     }
  638.  
  639.     /**
  640.      * Retrieves data from memory in one chunk, or from disk in $buffer
  641.      * sized chunks.
  642.      *
  643.      * @return string The data
  644.      */
  645.     function getData()
  646.     {
  647.         $buffer 4096;
  648.  
  649.         // Return data stored in memory
  650.         if (isset($this->_data)) {
  651.             $tmp   $this->_data;
  652.             unset($this->_data);
  653.             $fh    $this->_filehandle;
  654.             if ($this->_using_tmpfile{
  655.                 fseek($fh0);
  656.             }
  657.             return $tmp;
  658.         }
  659.         // Return data stored on disk
  660.         if ($this->_using_tmpfile{
  661.             if ($tmp fread($this->_filehandle$buffer)) {
  662.                 return $tmp;
  663.             }
  664.         }
  665.  
  666.         // No data to return
  667.         return false;
  668.     }
  669.  
  670.     /**
  671.      * Set the width of a single column or a range of columns.
  672.      *
  673.      * @param integer $firstcol first column on the range
  674.      * @param integer $lastcol  last column on the range
  675.      * @param integer $width    width to set
  676.      * @param integer $xfIndex  The optional cell style Xf index to apply to the columns
  677.      * @param integer $hidden   The optional hidden atribute
  678.      * @param integer $level    The optional outline level
  679.      */
  680.     private function _setColumn($firstcol$lastcol$width$xfIndex 15$hidden 0$level 0)
  681.     {
  682.         $this->_colinfo[array($firstcol$lastcol$width$xfIndex$hidden$level);
  683.  
  684.         // Set width to zero if column is hidden
  685.         $width ($hidden$width;
  686.     }
  687.  
  688.     /**
  689.      * Set the option to print the row and column headers on the printed page.
  690.      *
  691.      * @access public
  692.      * @param integer $print Whether to print the headers or not. Defaults to 1 (print).
  693.      */
  694.     function printRowColHeaders($print 1)
  695.     {
  696.         $this->_print_headers $print;
  697.     }
  698.  
  699.     /**
  700.      * Store Worksheet data in memory using the parent's class append() or to a
  701.      * temporary file, the default.
  702.      *
  703.      * @access private
  704.      * @param string $data The binary data to append
  705.      */
  706.     function _append($data)
  707.     {
  708.         if ($this->_using_tmpfile{
  709.             // Add CONTINUE records if necessary
  710.             if (strlen($data$this->_limit{
  711.                 $data $this->_addContinue($data);
  712.             }
  713.             fwrite($this->_filehandle$data);
  714.             $this->_datasize += strlen($data);
  715.         else {
  716.             parent::_append($data);
  717.         }
  718.     }
  719.  
  720.     /**
  721.      * This method sets the properties for outlining and grouping. The defaults
  722.      * correspond to Excel's defaults.
  723.      *
  724.      * @param bool $visible 
  725.      * @param bool $symbols_below 
  726.      * @param bool $symbols_right 
  727.      * @param bool $auto_style 
  728.      */
  729.     function setOutline($visible true$symbols_below true$symbols_right true$auto_style false)
  730.     {
  731.         $this->_outline_on    = $visible;
  732.         $this->_outline_below = $symbols_below;
  733.         $this->_outline_right = $symbols_right;
  734.         $this->_outline_style = $auto_style;
  735.  
  736.         // Ensure this is a boolean vale for Window2
  737.         if ($this->_outline_on{
  738.             $this->_outline_on = 1;
  739.         }
  740.      }
  741.  
  742.     /**
  743.      * Write a double to the specified row and column (zero indexed).
  744.      * An integer can be written as a double. Excel will display an
  745.      * integer. $format is optional.
  746.      *
  747.      * Returns  0 : normal termination
  748.      *         -2 : row or column out of range
  749.      *
  750.      * @param integer $row    Zero indexed row
  751.      * @param integer $col    Zero indexed column
  752.      * @param float   $num    The number to write
  753.      * @param mixed   $format The optional XF format
  754.      * @return integer 
  755.      */
  756.     private function _writeNumber($row$col$num$xfIndex)
  757.     {
  758.         $record    0x0203;                 // Record identifier
  759.         $length    0x000E;                 // Number of bytes to follow
  760.  
  761.         $header    pack("vv",  $record$length);
  762.         $data      pack("vvv"$row$col$xfIndex);
  763.         $xl_double pack("d",   $num);
  764.         if (PHPExcel_Writer_Excel5_BIFFwriter::getByteOrder()) // if it's Big Endian
  765.             $xl_double strrev($xl_double);
  766.         }
  767.  
  768.         $this->_append($header.$data.$xl_double);
  769.         return(0);
  770.     }
  771.  
  772.     /**
  773.      * Write a LABELSST record or a LABEL record. Which one depends on BIFF version
  774.      *
  775.      * @param int $row Row index (0-based)
  776.      * @param int $col Column index (0-based)
  777.      * @param string $str The string
  778.      * @param int $xfIndex Index to XF record
  779.      */
  780.     private function _writeString($row$col$str$xfIndex)
  781.     {
  782.         if ($this->_BIFF_version == 0x0600{
  783.             $this->_writeLabelSst($row$col$str$xfIndex);
  784.         else {
  785.             $this->_writeLabel($row$col$str$xfIndex);
  786.         }
  787.     }
  788.     /**
  789.      * Write a string to the specified row and column (zero indexed).
  790.      * NOTE: there is an Excel 5 defined limit of 255 characters.
  791.      * $format is optional.
  792.      * Returns  0 : normal termination
  793.      *         -2 : row or column out of range
  794.      *         -3 : long string truncated to 255 chars
  795.      *
  796.      * @access public
  797.      * @param integer $row    Zero indexed row
  798.      * @param integer $col    Zero indexed column
  799.      * @param string  $str    The string to write
  800.      * @param mixed   $format The XF format for the cell
  801.      * @return integer 
  802.      */
  803.     private function _writeLabel($row$col$str$xfIndex)
  804.     {
  805.         $strlen    strlen($str);
  806.         $record    0x0204;                   // Record identifier
  807.         $length    0x0008 $strlen;         // Bytes to follow
  808.  
  809.         $str_error 0;
  810.  
  811.         if ($strlen $this->_xls_strmax// LABEL must be < 255 chars
  812.             $str       substr($str0$this->_xls_strmax);
  813.             $length    0x0008 $this->_xls_strmax;
  814.             $strlen    $this->_xls_strmax;
  815.             $str_error = -3;
  816.         }
  817.  
  818.         $header    pack("vv",   $record$length);
  819.         $data      pack("vvvv"$row$col$xfIndex$strlen);
  820.         $this->_append($header $data $str);
  821.         return($str_error);
  822.     }
  823.  
  824.     /**
  825.      * Write a string to the specified row and column (zero indexed).
  826.      * This is the BIFF8 version (no 255 chars limit).
  827.      * $format is optional.
  828.      * Returns  0 : normal termination
  829.      *         -2 : row or column out of range
  830.      *         -3 : long string truncated to 255 chars
  831.      *
  832.      * @access public
  833.      * @param integer $row    Zero indexed row
  834.      * @param integer $col    Zero indexed column
  835.      * @param string  $str    The string to write
  836.      * @param mixed   $format The XF format for the cell
  837.      * @return integer 
  838.      */
  839.     private function _writeLabelSst($row$col$str$xfIndex)
  840.     {
  841.         $record    0x00FD;                   // Record identifier
  842.         $length    0x000A;                   // Bytes to follow
  843.  
  844.         $str PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($str);
  845.  
  846.         /* check if string is already present */
  847.         if (!isset($this->_str_table[$str])) {
  848.             $this->_str_table[$str$this->_str_unique++;
  849.         }
  850.         $this->_str_total++;
  851.  
  852.         $header    pack('vv',   $record$length);
  853.         $data      pack('vvvV'$row$col$xfIndex$this->_str_table[$str]);
  854.         $this->_append($header.$data);
  855.     }
  856.  
  857.     /**
  858.      * Writes a note associated with the cell given by the row and column.
  859.      * NOTE records don't have a length limit.
  860.      *
  861.      * @param integer $row    Zero indexed row
  862.      * @param integer $col    Zero indexed column
  863.      * @param string  $note   The note to write
  864.      */
  865.     private function _writeNote($row$col$note)
  866.     {
  867.         $note_length    strlen($note);
  868.         $record         0x001C;                // Record identifier
  869.         $max_length     2048;                  // Maximun length for a NOTE record
  870.         //$length      = 0x0006 + $note_length;    // Bytes to follow
  871.  
  872.         // Length for this record is no more than 2048 + 6
  873.         $length    0x0006 min($note_length2048);
  874.         $header    pack("vv",   $record$length);
  875.         $data      pack("vvv"$row$col$note_length);
  876.         $this->_append($header $data substr($note02048));
  877.  
  878.         for ($i $max_length$i $note_length$i += $max_length{
  879.             $chunk  substr($note$i$max_length);
  880.             $length 0x0006 strlen($chunk);
  881.             $header pack("vv",   $record$length);
  882.             $data   pack("vvv"-10strlen($chunk));
  883.             $this->_append($header.$data.$chunk);
  884.         }
  885.         return(0);
  886.     }
  887.  
  888.     /**
  889.      * Write a blank cell to the specified row and column (zero indexed).
  890.      * A blank cell is used to specify formatting without adding a string
  891.      * or a number.
  892.      *
  893.      * A blank cell without a format serves no purpose. Therefore, we don't write
  894.      * a BLANK record unless a format is specified.
  895.      *
  896.      * Returns  0 : normal termination (including no format)
  897.      *         -1 : insufficient number of arguments
  898.      *         -2 : row or column out of range
  899.      *
  900.      * @param integer $row    Zero indexed row
  901.      * @param integer $col    Zero indexed column
  902.      * @param mixed   $format The XF format
  903.      */
  904.     function _writeBlank($row$col$xfIndex)
  905.     {
  906.         $record    0x0201;                 // Record identifier
  907.         $length    0x0006;                 // Number of bytes to follow
  908.  
  909.         $header    pack("vv",  $record$length);
  910.         $data      pack("vvv"$row$col$xfIndex);
  911.         $this->_append($header $data);
  912.         return 0;
  913.     }
  914.  
  915.     /**
  916.      * Write a boolean or an error type to the specified row and column (zero indexed)
  917.      *
  918.      * @param int $row Row index (0-based)
  919.      * @param int $col Column index (0-based)
  920.      * @param int $value 
  921.      * @param boolean $isError Error or Boolean?
  922.      * @param int $xfIndex 
  923.      */
  924.     private function _writeBoolErr($row$col$value$isError$xfIndex)
  925.     {
  926.         $record 0x0205;
  927.         $length 8;
  928.  
  929.         $header    pack("vv",  $record$length);
  930.         $data      pack("vvvCC"$row$col$xfIndex$value$isError);
  931.         $this->_append($header $data);
  932.         return 0;
  933.     }
  934.  
  935.     /**
  936.      * Write a formula to the specified row and column (zero indexed).
  937.      * The textual representation of the formula is passed to the parser in
  938.      * Parser.php which returns a packed binary string.
  939.      *
  940.      * Returns  0 : normal termination
  941.      *         -1 : formula errors (bad formula)
  942.      *         -2 : row or column out of range
  943.      *
  944.      * @param integer $row     Zero indexed row
  945.      * @param integer $col     Zero indexed column
  946.      * @param string  $formula The formula text string
  947.      * @param mixed   $format  The optional XF format
  948.      * @param mixed   $calculatedValue  Calculated value
  949.      * @return integer 
  950.      */
  951.     private function _writeFormula($row$col$formula$xfIndex$calculatedValue)
  952.     {
  953.         $record    0x0006;     // Record identifier
  954.  
  955.         // Initialize possible additional value for STRING record that should be written after the FORMULA record?
  956.         $stringValue null;
  957.  
  958.         // calculated value
  959.         if (isset($calculatedValue)) {
  960.  
  961.             // Since we can't yet get the data type of the calculated value,
  962.             // we use best effort to determine data type
  963.  
  964.             if (is_bool($calculatedValue)) {
  965.                 // Boolean value
  966.                 $num pack('CCCvCv'0x010x00(int)$calculatedValue0x000x000xFFFF);
  967.  
  968.             elseif (is_int($calculatedValue|| is_float($calculatedValue)) {
  969.                 // Numeric value
  970.                 $num pack('d'$calculatedValue);
  971.  
  972.             elseif (is_string($calculatedValue)) {
  973.                 if (array_key_exists($calculatedValuePHPExcel_Cell_DataType::getErrorCodes())) {
  974.                     // Error value
  975.                     $num pack('CCCvCv'0x020x00$this->_mapErrorCode($calculatedValue)0x000x000xFFFF);
  976.  
  977.                 elseif ($calculatedValue === '' && $this->_BIFF_version == 0x0600{
  978.                     // Empty string (and BIFF8)
  979.                     $num pack('CCCvCv'0x030x000x000x000x000xFFFF);
  980.  
  981.                 else {
  982.                     // Non-empty string value (or empty string BIFF5)
  983.                     $stringValue $calculatedValue;
  984.                     $num pack('CCCvCv'0x000x000x000x000x000xFFFF);
  985.  
  986.                 }
  987.  
  988.             else {
  989.                 // We are really not supposed to reach here
  990.                 $num pack('d'0x00);
  991.  
  992.             }
  993.  
  994.         else {
  995.             $num pack('d'0x00);
  996.         }
  997.  
  998.         $grbit     0x03;                // Option flags
  999.         $unknown   0x0000;              // Must be zero
  1000.  
  1001.         // Strip the '=' or '@' sign at the beginning of the formula string
  1002.         if (preg_match("/^=/"$formula)) {
  1003.             $formula preg_replace("/(^=)/"""$formula);
  1004.         elseif (preg_match("/^@/"$formula)) {
  1005.             $formula preg_replace("/(^@)/"""$formula);
  1006.         else {
  1007.             // Error handling
  1008.             $this->_writeString($row$col'Unrecognised character for formula');
  1009.             return -1;
  1010.         }
  1011.  
  1012.         // Parse the formula using the parser in Parser.php
  1013.         try {
  1014.             $error $this->_parser->parse($formula);
  1015.             $formula $this->_parser->toReversePolish();
  1016.  
  1017.             $formlen    strlen($formula);    // Length of the binary string
  1018.             $length     0x16 $formlen;     // Length of the record data
  1019.  
  1020.             $header    pack("vv",      $record$length);
  1021.  
  1022.             $data      pack("vvv"$row$col$xfIndex)
  1023.                         . $num
  1024.                         . pack("vVv"$grbit$unknown$formlen);
  1025.             $this->_append($header $data $formula);
  1026.  
  1027.             // Append also a STRING record if necessary
  1028.             if ($stringValue !== null{
  1029.                 $this->_writeStringRecord($stringValue);
  1030.             }
  1031.  
  1032.             return 0;
  1033.  
  1034.         catch (Exception $e{
  1035.             // do nothing
  1036.         }
  1037.  
  1038.     }
  1039.  
  1040.     /**
  1041.      * Write a STRING record. This
  1042.      *
  1043.      * @param string $stringValue 
  1044.      */
  1045.     private function _writeStringRecord($stringValue)
  1046.     {
  1047.         $record 0x0207;     // Record identifier
  1048.         $data PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($stringValue);
  1049.  
  1050.         $length strlen($data);
  1051.         $header pack('vv'$record$length);
  1052.  
  1053.         $this->_append($header $data);
  1054.     }
  1055.  
  1056.     /**
  1057.      * Write a hyperlink.
  1058.      * This is comprised of two elements: the visible label and
  1059.      * the invisible link. The visible label is the same as the link unless an
  1060.      * alternative string is specified. The label is written using the
  1061.      * _writeString() method. Therefore the 255 characters string limit applies.
  1062.      * $string and $format are optional.
  1063.      *
  1064.      * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
  1065.      * directory url.
  1066.      *
  1067.      * Returns  0 : normal termination
  1068.      *         -2 : row or column out of range
  1069.      *         -3 : long string truncated to 255 chars
  1070.      *
  1071.      * @param integer $row    Row
  1072.      * @param integer $col    Column
  1073.      * @param string  $url    URL string
  1074.      * @return integer 
  1075.      */
  1076.     private function _writeUrl($row$col$url)
  1077.     {
  1078.         // Add start row and col to arg list
  1079.         return($this->_writeUrlRange($row$col$row$col$url));
  1080.     }
  1081.  
  1082.     /**
  1083.      * This is the more general form of _writeUrl(). It allows a hyperlink to be
  1084.      * written to a range of cells. This function also decides the type of hyperlink
  1085.      * to be written. These are either, Web (http, ftp, mailto), Internal
  1086.      * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
  1087.      *
  1088.      * @access private
  1089.      * @see _writeUrl()
  1090.      * @param integer $row1   Start row
  1091.      * @param integer $col1   Start column
  1092.      * @param integer $row2   End row
  1093.      * @param integer $col2   End column
  1094.      * @param string  $url    URL string
  1095.      * @return integer 
  1096.      */
  1097.  
  1098.     function _writeUrlRange($row1$col1$row2$col2$url)
  1099.     {
  1100.  
  1101.         // Check for internal/external sheet links or default to web link
  1102.         if (preg_match('[^internal:]'$url)) {
  1103.             return($this->_writeUrlInternal($row1$col1$row2$col2$url));
  1104.         }
  1105.         if (preg_match('[^external:]'$url)) {
  1106.             return($this->_writeUrlExternal($row1$col1$row2$col2$url));
  1107.         }
  1108.         return($this->_writeUrlWeb($row1$col1$row2$col2$url));
  1109.     }
  1110.  
  1111.  
  1112.     /**
  1113.      * Used to write http, ftp and mailto hyperlinks.
  1114.      * The link type ($options) is 0x03 is the same as absolute dir ref without
  1115.      * sheet. However it is differentiated by the $unknown2 data stream.
  1116.      *
  1117.      * @access private
  1118.      * @see _writeUrl()
  1119.      * @param integer $row1   Start row
  1120.      * @param integer $col1   Start column
  1121.      * @param integer $row2   End row
  1122.      * @param integer $col2   End column
  1123.      * @param string  $url    URL string
  1124.      * @return integer 
  1125.      */
  1126.     function _writeUrlWeb($row1$col1$row2$col2$url)
  1127.     {
  1128.         $record      0x01B8;                       // Record identifier
  1129.         $length      0x00000;                      // Bytes to follow
  1130.  
  1131.         // Pack the undocumented parts of the hyperlink stream
  1132.         $unknown1    pack("H*""D0C9EA79F9BACE118C8200AA004BA90B02000000");
  1133.         $unknown2    pack("H*""E0C9EA79F9BACE118C8200AA004BA90B");
  1134.  
  1135.         // Pack the option flags
  1136.         $options     pack("V"0x03);
  1137.  
  1138.         // Convert URL to a null terminated wchar string
  1139.         $url         join("\0"preg_split("''"$url-1PREG_SPLIT_NO_EMPTY));
  1140.         $url         $url "\0\0\0";
  1141.  
  1142.         // Pack the length of the URL
  1143.         $url_len     pack("V"strlen($url));
  1144.  
  1145.         // Calculate the data length
  1146.         $length      0x34 strlen($url);
  1147.  
  1148.         // Pack the header data
  1149.         $header      pack("vv",   $record$length);
  1150.         $data        pack("vvvv"$row1$row2$col1$col2);
  1151.  
  1152.         // Write the packed data
  1153.         $this->_append($header $data .
  1154.                        $unknown1 $options .
  1155.                        $unknown2 $url_len $url);
  1156.         return 0;
  1157.     }
  1158.  
  1159.     /**
  1160.      * Used to write internal reference hyperlinks such as "Sheet1!A1".
  1161.      *
  1162.      * @access private
  1163.      * @see _writeUrl()
  1164.      * @param integer $row1   Start row
  1165.      * @param integer $col1   Start column
  1166.      * @param integer $row2   End row
  1167.      * @param integer $col2   End column
  1168.      * @param string  $url    URL string
  1169.      * @return integer 
  1170.      */
  1171.     function _writeUrlInternal($row1$col1$row2$col2$url)
  1172.     {
  1173.         $record      0x01B8;                       // Record identifier
  1174.         $length      0x00000;                      // Bytes to follow
  1175.  
  1176.         // Strip URL type
  1177.         $url preg_replace('/^internal:/'''$url);
  1178.  
  1179.         // Pack the undocumented parts of the hyperlink stream
  1180.         $unknown1    pack("H*""D0C9EA79F9BACE118C8200AA004BA90B02000000");
  1181.  
  1182.         // Pack the option flags
  1183.         $options     pack("V"0x08);
  1184.  
  1185.         // Convert the URL type and to a null terminated wchar string
  1186.         $url .= "\0";
  1187.  
  1188.         // character count
  1189.         $url_len PHPExcel_Shared_String::CountCharacters($url);
  1190.         $url_len pack('V'$url_len);
  1191.  
  1192.         $url PHPExcel_Shared_String::ConvertEncoding($url'UTF-16LE''UTF-8');
  1193.  
  1194.         // Calculate the data length
  1195.         $length      0x24 strlen($url);
  1196.  
  1197.         // Pack the header data
  1198.         $header      pack("vv",   $record$length);
  1199.         $data        pack("vvvv"$row1$row2$col1$col2);
  1200.  
  1201.         // Write the packed data
  1202.         $this->_append($header $data .
  1203.                        $unknown1 $options .
  1204.                        $url_len $url);
  1205.         return 0;
  1206.     }
  1207.  
  1208.     /**
  1209.      * Write links to external directory names such as 'c:\foo.xls',
  1210.      * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
  1211.      *
  1212.      * Note: Excel writes some relative links with the $dir_long string. We ignore
  1213.      * these cases for the sake of simpler code.
  1214.      *
  1215.      * @access private
  1216.      * @see _writeUrl()
  1217.      * @param integer $row1   Start row
  1218.      * @param integer $col1   Start column
  1219.      * @param integer $row2   End row
  1220.      * @param integer $col2   End column
  1221.      * @param string  $url    URL string
  1222.      * @return integer 
  1223.      */
  1224.     function _writeUrlExternal($row1$col1$row2$col2$url)
  1225.     {
  1226.         // Network drives are different. We will handle them separately
  1227.         // MS/Novell network drives and shares start with \\
  1228.         if (preg_match('[^external:\\\\]'$url)) {
  1229.             return//($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format));
  1230.         }
  1231.  
  1232.         $record      0x01B8;                       // Record identifier
  1233.         $length      0x00000;                      // Bytes to follow
  1234.  
  1235.         // Strip URL type and change Unix dir separator to Dos style (if needed)
  1236.         //
  1237.         $url preg_replace('/^external:/'''$url);
  1238.         $url preg_replace('/\//'"\\"$url);
  1239.  
  1240.         // Determine if the link is relative or absolute:
  1241.         //   relative if link contains no dir separator, "somefile.xls"
  1242.         //   relative if link starts with up-dir, "..\..\somefile.xls"
  1243.         //   otherwise, absolute
  1244.  
  1245.         $absolute 0x00// relative path
  1246.         if preg_match('/^[A-Z]:/'$url) ) {
  1247.             $absolute 0x02// absolute path on Windows, e.g. C:\...
  1248.         }
  1249.         $link_type               0x01 $absolute;
  1250.  
  1251.         // Determine if the link contains a sheet reference and change some of the
  1252.         // parameters accordingly.
  1253.         // Split the dir name and sheet name (if it exists)
  1254.         $dir_long $url;
  1255.         if (preg_match("/\#/"$url)) {
  1256.             $link_type |= 0x08;
  1257.         }
  1258.  
  1259.  
  1260.         // Pack the link type
  1261.         $link_type   pack("V"$link_type);
  1262.  
  1263.         // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
  1264.         $up_count    preg_match_all("/\.\.\\\/"$dir_long$useless);
  1265.         $up_count    pack("v"$up_count);
  1266.  
  1267.         // Store the short dos dir name (null terminated)
  1268.         $dir_short   preg_replace("/\.\.\\\/"''$dir_long"\0";
  1269.  
  1270.         // Store the long dir name as a wchar string (non-null terminated)
  1271.         $dir_long       $dir_long "\0";
  1272.  
  1273.         // Pack the lengths of the dir strings
  1274.         $dir_short_len pack("V"strlen($dir_short)      );
  1275.         $dir_long_len  pack("V"strlen($dir_long)       );
  1276.         $stream_len    pack("V"0);//strlen($dir_long) + 0x06);
  1277.  
  1278.         // Pack the undocumented parts of the hyperlink stream
  1279.         $unknown1 pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000'       );
  1280.         $unknown2 pack("H*",'0303000000000000C000000000000046'               );
  1281.         $unknown3 pack("H*",'FFFFADDE000000000000000000000000000000000000000');
  1282.         $unknown4 pack("v",  0x03                                            );
  1283.  
  1284.         // Pack the main data stream
  1285.         $data        pack("vvvv"$row1$row2$col1$col2.
  1286.                           $unknown1     .
  1287.                           $link_type    .
  1288.                           $unknown2     .
  1289.                           $up_count     .
  1290.                           $dir_short_len.
  1291.                           $dir_short    .
  1292.                           $unknown3     .
  1293.                           $stream_len   ;/*.
  1294.                           $dir_long_len .
  1295.                           $unknown4     .
  1296.                           $dir_long     .
  1297.                           $sheet_len    .
  1298.                           $sheet        ;*/
  1299.  
  1300.         // Pack the header data
  1301.         $length   strlen($data);
  1302.         $header   pack("vv"$record$length);
  1303.  
  1304.         // Write the packed data
  1305.         $this->_append($header$data);
  1306.         return 0;
  1307.     }
  1308.  
  1309.     /**
  1310.      * This method is used to set the height and format for a row.
  1311.      *
  1312.      * @param integer $row    The row to set
  1313.      * @param integer $height Height we are giving to the row.
  1314.      *                         Use null to set XF without setting height
  1315.      * @param integer $xfIndex  The optional cell style Xf index to apply to the columns
  1316.      * @param bool    $hidden The optional hidden attribute
  1317.      * @param integer $level  The optional outline level for row, in range [0,7]
  1318.      */
  1319.     private function _setRow($row$height$xfIndex$hidden false$level 0)
  1320.     {
  1321.         $record      0x0208;               // Record identifier
  1322.         $length      0x0010;               // Number of bytes to follow
  1323.  
  1324.         $colMic      0x0000;               // First defined column
  1325.         $colMac      0x0000;               // Last defined column
  1326.         $irwMac      0x0000;               // Used by Excel to optimise loading
  1327.         $reserved    0x0000;               // Reserved
  1328.         $grbit       0x0000;               // Option flags
  1329.         $ixfe        $xfIndex;
  1330.  
  1331.         if $height ){
  1332.             $height null;
  1333.         }
  1334.  
  1335.         // Use _setRow($row, null, $XF) to set XF format without setting height
  1336.         if ($height != null{
  1337.             $miyRw $height 20;  // row height
  1338.         else {
  1339.             $miyRw 0xff;          // default row height is 256
  1340.         }
  1341.  
  1342.         // Set the options flags. fUnsynced is used to show that the font and row
  1343.         // heights are not compatible. This is usually the case for WriteExcel.
  1344.         // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
  1345.         // is collapsed. Instead it is used to indicate that the previous row is
  1346.         // collapsed. The zero height flag, 0x20, is used to collapse a row.
  1347.  
  1348.         $grbit |= $level;
  1349.         if ($hidden{
  1350.             $grbit |= 0x0020;
  1351.         }
  1352.         if ($height !== null{
  1353.             $grbit |= 0x0040// fUnsynced
  1354.         }
  1355.         if ($xfIndex !== 0xF{
  1356.             $grbit |= 0x0080;
  1357.         }
  1358.         $grbit |= 0x0100;
  1359.  
  1360.         $header   pack("vv",       $record$length);
  1361.         $data     pack("vvvvvvvv"$row$colMic$colMac$miyRw,
  1362.                                      $irwMac,$reserved$grbit$ixfe);
  1363.         $this->_append($header.$data);
  1364.     }
  1365.  
  1366.     /**
  1367.      * Writes Excel DIMENSIONS to define the area in which there is data.
  1368.      *
  1369.      * @access private
  1370.      */
  1371.     function _storeDimensions()
  1372.     {
  1373.         $record 0x0200// Record identifier
  1374.  
  1375.         if ($this->_BIFF_version == 0x0500{
  1376.             $length 0x000A;               // Number of bytes to follow
  1377.             $data pack("vvvvv"
  1378.                     $this->_firstRowIndex
  1379.                     $this->_lastRowIndex + 1
  1380.                     $this->_firstColumnIndex
  1381.                     $this->_lastColumnIndex + 1
  1382.                     0x0000 // reserved
  1383.                 );
  1384.  
  1385.         elseif ($this->_BIFF_version == 0x0600{
  1386.             $length 0x000E;
  1387.             $data pack('VVvvv'
  1388.                     $this->_firstRowIndex
  1389.                     $this->_lastRowIndex + 1
  1390.                     $this->_firstColumnIndex
  1391.                     $this->_lastColumnIndex + 1
  1392.                     0x0000 // reserved
  1393.                 );
  1394.         }
  1395.  
  1396.         $header pack("vv"$record$length);
  1397.         $this->_append($header.$data);
  1398.     }
  1399.  
  1400.     /**
  1401.      * Write BIFF record Window2.
  1402.      *
  1403.      * @access private
  1404.      */
  1405.     function _storeWindow2()
  1406.     {
  1407.         $record         0x023E;     // Record identifier
  1408.         if ($this->_BIFF_version == 0x0500{
  1409.             $length         0x000A;     // Number of bytes to follow
  1410.         elseif ($this->_BIFF_version == 0x0600{
  1411.             $length         0x0012;
  1412.         }
  1413.  
  1414.         $grbit          0x00B6;     // Option flags
  1415.         $rwTop          0x0000;     // Top row visible in window
  1416.         $colLeft        0x0000;     // Leftmost column visible in window
  1417.  
  1418.  
  1419.         // The options flags that comprise $grbit
  1420.         $fDspFmla       0;                     // 0 - bit
  1421.         $fDspGrid       $this->_phpSheet->getShowGridlines(0// 1
  1422.         $fDspRwCol      1;                     // 2
  1423.         $fFrozen        $this->_phpSheet->getFreezePane(0;        // 3
  1424.         $fDspZeros      1;                     // 4
  1425.         $fDefaultHdr    1;                     // 5
  1426.         $fArabic        $this->_phpSheet->getRightToLeft(0// 6
  1427.         $fDspGuts       $this->_outline_on;    // 7
  1428.         $fFrozenNoSplit 0;                     // 0 - bit
  1429.         // no support in PHPExcel for selected sheet, therefore sheet is only selected if it is the active sheet
  1430.         $fSelected      ($this->_phpSheet === $this->_phpSheet->getParent()->getActiveSheet()) 0;
  1431.         $fPaged         1;                     // 2
  1432.  
  1433.         $grbit             $fDspFmla;
  1434.         $grbit            |= $fDspGrid       << 1;
  1435.         $grbit            |= $fDspRwCol      << 2;
  1436.         $grbit            |= $fFrozen        << 3;
  1437.         $grbit            |= $fDspZeros      << 4;
  1438.         $grbit            |= $fDefaultHdr    << 5;
  1439.         $grbit            |= $fArabic        << 6;
  1440.         $grbit            |= $fDspGuts       << 7;
  1441.         $grbit            |= $fFrozenNoSplit << 8;
  1442.         $grbit            |= $fSelected      << 9;
  1443.         $grbit            |= $fPaged         << 10;
  1444.  
  1445.         $header  pack("vv",   $record$length);
  1446.         $data    pack("vvv"$grbit$rwTop$colLeft);
  1447.         // FIXME !!!
  1448.         if ($this->_BIFF_version == 0x0500{
  1449.             $rgbHdr         0x00000000// Row/column heading and gridline color
  1450.             $data .= pack("V"$rgbHdr);
  1451.         elseif ($this->_BIFF_version == 0x0600{
  1452.             $rgbHdr       0x0040// Row/column heading and gridline color index
  1453.             $zoom_factor_page_break 0x0000;
  1454.             $zoom_factor_normal     0x0000;
  1455.             $data .= pack("vvvvV"$rgbHdr0x0000$zoom_factor_page_break$zoom_factor_normal0x00000000);
  1456.         }
  1457.         $this->_append($header.$data);
  1458.     }
  1459.  
  1460.     /**
  1461.      * Write BIFF record DEFAULTROWHEIGHT.
  1462.      *
  1463.      * @access private
  1464.      */
  1465.     private function _storeDefaultRowHeight()
  1466.     {
  1467.         $defaultRowHeight $this->_phpSheet->getDefaultRowDimension()->getRowHeight();
  1468.  
  1469.         if ($defaultRowHeight 0{
  1470.             return;
  1471.         }
  1472.  
  1473.         // convert to twips
  1474.         $defaultRowHeight = (int) 20 $defaultRowHeight;
  1475.  
  1476.         $record   0x0225;      // Record identifier
  1477.         $length   0x0004;      // Number of bytes to follow
  1478.  
  1479.         $header   pack("vv"$record$length);
  1480.         $data     pack("vv",  1$defaultRowHeight);
  1481.         $this->_append($header $data);
  1482.     }
  1483.  
  1484.     /**
  1485.      * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
  1486.      *
  1487.      * @access private
  1488.      */
  1489.     function _storeDefcol()
  1490.     {
  1491.         $defaultColWidth 8;
  1492.         
  1493.         $record   0x0055;      // Record identifier
  1494.         $length   0x0002;      // Number of bytes to follow
  1495.  
  1496.         $header pack("vv"$record$length);
  1497.         $data pack("v"$defaultColWidth);
  1498.         $this->_append($header $data);
  1499.     }
  1500.  
  1501.     /**
  1502.      * Write BIFF record COLINFO to define column widths
  1503.      *
  1504.      * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
  1505.      * length record.
  1506.      *
  1507.      * @access private
  1508.      * @param array $col_array This is the only parameter received and is composed of the following:
  1509.      *                 0 => First formatted column,
  1510.      *                 1 => Last formatted column,
  1511.      *                 2 => Col width (8.43 is Excel default),
  1512.      *                 3 => The optional XF format of the column,
  1513.      *                 4 => Option flags.
  1514.      *                 5 => Optional outline level
  1515.      */
  1516.     function _storeColinfo($col_array)
  1517.     {
  1518.         if (isset($col_array[0])) {
  1519.             $colFirst $col_array[0];
  1520.         }
  1521.         if (isset($col_array[1])) {
  1522.             $colLast $col_array[1];
  1523.         }
  1524.         if (isset($col_array[2])) {
  1525.             $coldx $col_array[2];
  1526.         else {
  1527.             $coldx 8.43;
  1528.         }
  1529.         if (isset($col_array[3])) {
  1530.             $xfIndex $col_array[3];
  1531.         else {
  1532.             $xfIndex 15;
  1533.         }
  1534.         if (isset($col_array[4])) {
  1535.             $grbit $col_array[4];
  1536.         else {
  1537.             $grbit 0;
  1538.         }
  1539.         if (isset($col_array[5])) {
  1540.             $level $col_array[5];
  1541.         else {
  1542.             $level 0;
  1543.         }
  1544.         $record   0x007D;          // Record identifier
  1545.         $length   0x000B;          // Number of bytes to follow
  1546.  
  1547.         $coldx   *= 256;             // Convert to units of 1/256 of a char
  1548.  
  1549.         $ixfe     $xfIndex;
  1550.         $reserved 0x00;            // Reserved
  1551.  
  1552.         $level max(0min($level7));
  1553.         $grbit |= $level << 8;
  1554.  
  1555.         $header   pack("vv",     $record$length);
  1556.         $data     pack("vvvvvC"$colFirst$colLast$coldx,
  1557.                                    $ixfe$grbit$reserved);
  1558.         $this->_append($header.$data);
  1559.     }
  1560.  
  1561.     /**
  1562.      * Write BIFF record SELECTION.
  1563.      *
  1564.      * @access private
  1565.      */
  1566.     function _storeSelection()
  1567.     {
  1568.         // look up the selected cell range
  1569.         $selectedCells $this->_phpSheet->getSelectedCells();
  1570.         $selectedCells PHPExcel_Cell::splitRange($this->_phpSheet->getSelectedCells());
  1571.         $selectedCells $selectedCells[0];
  1572.         if (count($selectedCells== 2{
  1573.             list($first$last$selectedCells;
  1574.         else {
  1575.             $first $selectedCells[0];
  1576.             $last  $selectedCells[0];
  1577.         }
  1578.         
  1579.         list($colFirst$rwFirstPHPExcel_Cell::coordinateFromString($first);
  1580.         $colFirst PHPExcel_Cell::columnIndexFromString($colFirst1// base 0 column index
  1581.         --$rwFirst// base 0 row index
  1582.  
  1583.         list($colLast$rwLastPHPExcel_Cell::coordinateFromString($last);
  1584.         $colLast PHPExcel_Cell::columnIndexFromString($colLast1// base 0 column index
  1585.         --$rwLast// base 0 row index
  1586.         
  1587.         // make sure we are not out of bounds
  1588.         $colFirst min($colFirst255);
  1589.         $colLast  min($colLast,  255);
  1590.         if ($this->_BIFF_version == 0x0600{
  1591.             $rwFirst min($rwFirst65535);
  1592.             $rwLast  min($rwLast,  65535);
  1593.         else {
  1594.             $rwFirst min($rwFirst16383);
  1595.             $rwLast  min($rwLast,  16383);
  1596.         }
  1597.  
  1598.         $record   0x001D;                  // Record identifier
  1599.         $length   0x000F;                  // Number of bytes to follow
  1600.  
  1601.         $pnn      $this->_active_pane;     // Pane position
  1602.         $rwAct    $rwFirst;                // Active row
  1603.         $colAct   $colFirst;               // Active column
  1604.         $irefAct  0;                       // Active cell ref
  1605.         $cref     1;                       // Number of refs
  1606.  
  1607.         if (!isset($rwLast)) {
  1608.             $rwLast   $rwFirst;       // Last  row in reference
  1609.         }
  1610.         if (!isset($colLast)) {
  1611.             $colLast  $colFirst;      // Last  col in reference
  1612.         }
  1613.  
  1614.         // Swap last row/col for first row/col as necessary
  1615.         if ($rwFirst $rwLast{
  1616.             list($rwFirst$rwLastarray($rwLast$rwFirst);
  1617.         }
  1618.  
  1619.         if ($colFirst $colLast{
  1620.             list($colFirst$colLastarray($colLast$colFirst);
  1621.         }
  1622.  
  1623.         $header   pack("vv",         $record$length);
  1624.         $data     pack("CvvvvvvCC",  $pnn$rwAct$colAct,
  1625.                                        $irefAct$cref,
  1626.                                        $rwFirst$rwLast,
  1627.                                        $colFirst$colLast);
  1628.         $this->_append($header $data);
  1629.     }
  1630.  
  1631.     /**
  1632.      * Store the MERGEDCELLS records for all ranges of merged cells
  1633.      *
  1634.      * @access private
  1635.      */
  1636.     function _storeMergedCells()
  1637.     {
  1638.         $mergeCells $this->_phpSheet->getMergeCells();
  1639.         $countMergeCells count($mergeCells);
  1640.         
  1641.         if ($countMergeCells == 0{
  1642.             return;
  1643.         }
  1644.         
  1645.         // maximum allowed number of merged cells per record
  1646.         if ($this->_BIFF_version == 0x0600{
  1647.             $maxCountMergeCellsPerRecord 1027;
  1648.         else {
  1649.             $maxCountMergeCellsPerRecord 259;
  1650.         }
  1651.         
  1652.         // record identifier
  1653.         $record 0x00E5;
  1654.         
  1655.         // counter for total number of merged cells treated so far by the writer
  1656.         $i 0;
  1657.         
  1658.         // counter for number of merged cells written in record currently being written
  1659.         $j 0;
  1660.         
  1661.         // initialize record data
  1662.         $recordData '';
  1663.         
  1664.         // loop through the merged cells
  1665.         foreach ($mergeCells as $mergeCell{
  1666.             ++$i;
  1667.             ++$j;
  1668.  
  1669.             // extract the row and column indexes
  1670.             $range PHPExcel_Cell::splitRange($mergeCell);
  1671.             list($first$last$range[0];
  1672.             list($firstColumn$firstRowPHPExcel_Cell::coordinateFromString($first);
  1673.             list($lastColumn$lastRowPHPExcel_Cell::coordinateFromString($last);
  1674.  
  1675.             $recordData .= pack('vvvv'$firstRow 1$lastRow 1PHPExcel_Cell::columnIndexFromString($firstColumn1PHPExcel_Cell::columnIndexFromString($lastColumn1);
  1676.  
  1677.             // flush record if we have reached limit for number of merged cells, or reached final merged cell
  1678.             if ($j == $maxCountMergeCellsPerRecord or $i == $countMergeCells{
  1679.                 $recordData pack('v'$j$recordData;
  1680.                 $length strlen($recordData);
  1681.                 $header pack('vv'$record$length);
  1682.                 $this->_append($header $recordData);
  1683.                 
  1684.                 // initialize for next record, if any
  1685.                 $recordData '';
  1686.                 $j 0;
  1687.             }
  1688.         }
  1689.     }
  1690.  
  1691.     /**
  1692.      * Write SHEETLAYOUT record
  1693.      */
  1694.     private function _storeSheetLayout()
  1695.     {
  1696.         if (!$this->_phpSheet->isTabColorSet()) {
  1697.             return;
  1698.         }
  1699.  
  1700.         $recordData pack(
  1701.             'vvVVVvv'
  1702.             0x0862
  1703.             0x0000        // unused
  1704.             0x00000000    // unused
  1705.             0x00000000    // unused
  1706.             0x00000014    // size of record data
  1707.             $this->_colors[$this->_phpSheet->getTabColor()->getRGB()]    // color index
  1708.             0x0000        // unused
  1709.         );
  1710.  
  1711.         $length strlen($recordData);
  1712.  
  1713.         $record 0x0862// Record identifier
  1714.         $header pack('vv'$record$length);
  1715.         $this->_append($header $recordData);
  1716.     }
  1717.     
  1718.     /**
  1719.      * Write SHEETPROTECTION
  1720.      */
  1721.     private function _writeSheetProtection()
  1722.     {
  1723.         // record identifier
  1724.         $record 0x0867;
  1725.  
  1726.         // prepare options
  1727.         $options  =   (int) !$this->_phpSheet->getProtection()->getObjects()
  1728.                     | (int) !$this->_phpSheet->getProtection()->getScenarios()           << 1
  1729.                     | (int) !$this->_phpSheet->getProtection()->getFormatCells()         << 2
  1730.                     | (int) !$this->_phpSheet->getProtection()->getFormatColumns()       << 3
  1731.                     | (int) !$this->_phpSheet->getProtection()->getFormatRows()          << 4
  1732.                     | (int) !$this->_phpSheet->getProtection()->getInsertColumns()       << 5
  1733.                     | (int) !$this->_phpSheet->getProtection()->getInsertRows()          << 6
  1734.                     | (int) !$this->_phpSheet->getProtection()->getInsertHyperlinks()    << 7
  1735.                     | (int) !$this->_phpSheet->getProtection()->getDeleteColumns()       << 8
  1736.                     | (int) !$this->_phpSheet->getProtection()->getDeleteRows()          << 9
  1737.                     | (int) !$this->_phpSheet->getProtection()->getSelectLockedCells()   << 10
  1738.                     | (int) !$this->_phpSheet->getProtection()->getSort()                << 11
  1739.                     | (int) !$this->_phpSheet->getProtection()->getAutoFilter()          << 12
  1740.                     | (int) !$this->_phpSheet->getProtection()->getPivotTables()         << 13
  1741.                     | (int) !$this->_phpSheet->getProtection()->getSelectUnlockedCells(<< 14 ;
  1742.  
  1743.         // record data
  1744.         $recordData pack(
  1745.             'vVVCVVvv'
  1746.             0x0867        // repeated record identifier
  1747.             0x0000        // not used
  1748.             0x0000        // not used
  1749.             0x00            // not used
  1750.             0x01000200    // unknown data
  1751.             0xFFFFFFFF    // unknown data
  1752.             $options        // options
  1753.             0x0000        // not used
  1754.         );
  1755.  
  1756.         $length strlen($recordData);
  1757.         $header pack('vv'$record$length);
  1758.  
  1759.         $this->_append($header $recordData);
  1760.     }
  1761.     
  1762.     /**
  1763.      * Write BIFF record RANGEPROTECTION
  1764.      * 
  1765.      * Openoffice.org's Documentaion of the Microsoft Excel File Format uses term RANGEPROTECTION for these records
  1766.      * Microsoft Office Excel 97-2007 Binary File Format Specification uses term FEAT for these records
  1767.      */
  1768.     private function _storeRangeProtection()
  1769.     {
  1770.         foreach ($this->_phpSheet->getProtectedCells(as $range => $password{
  1771.             // number of ranges, e.g. 'A1:B3 C20:D25'
  1772.             $cellRanges explode(' '$range);
  1773.             $cref count($cellRanges);
  1774.  
  1775.             $recordData pack(
  1776.                 'vvVVvCVvVv',
  1777.                 0x0868,
  1778.                 0x00,
  1779.                 0x0000,
  1780.                 0x0000,
  1781.                 0x02,
  1782.                 0x0,
  1783.                 0x0000,
  1784.                 $cref,
  1785.                 0x0000,
  1786.                 0x00
  1787.             );
  1788.  
  1789.             foreach ($cellRanges as $cellRange{
  1790.                 $recordData .= $this->_writeBIFF8CellRangeAddressFixed($cellRange);
  1791.             }
  1792.  
  1793.             // the rgbFeat structure
  1794.             $recordData .= pack(
  1795.                 'VV',
  1796.                 0x0000,
  1797.                 hexdec($password)
  1798.             );
  1799.  
  1800.             $recordData .= PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong('p' md5($recordData));
  1801.  
  1802.             $length strlen($recordData);
  1803.  
  1804.             $record 0x0868;        // Record identifier
  1805.             $header pack("vv"$record$length);
  1806.             $this->_append($header $recordData);
  1807.         }
  1808.     }
  1809.  
  1810.     /**
  1811.      * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
  1812.      * references in a worksheet.
  1813.      *
  1814.      * Excel only stores references to external sheets that are used in formulas.
  1815.      * For simplicity we store references to all the sheets in the workbook
  1816.      * regardless of whether they are used or not. This reduces the overall
  1817.      * complexity and eliminates the need for a two way dialogue between the formula
  1818.      * parser the worksheet objects.
  1819.      *
  1820.      * @access private
  1821.      * @param integer $count The number of external sheet references in this worksheet
  1822.      */
  1823.     function _storeExterncount($count)
  1824.     {
  1825.         $record 0x0016;          // Record identifier
  1826.         $length 0x0002;          // Number of bytes to follow
  1827.  
  1828.         $header pack("vv"$record$length);
  1829.         $data   pack("v",  $count);
  1830.         $this->_append($header $data);
  1831.     }
  1832.  
  1833.     /**
  1834.      * Writes the Excel BIFF EXTERNSHEET record. These references are used by
  1835.      * formulas. A formula references a sheet name via an index. Since we store a
  1836.      * reference to all of the external worksheets the EXTERNSHEET index is the same
  1837.      * as the worksheet index.
  1838.      *
  1839.      * @access private
  1840.      * @param string $sheetname The name of a external worksheet
  1841.      */
  1842.     function _storeExternsheet($sheetname)
  1843.     {
  1844.         $record    0x0017;         // Record identifier
  1845.  
  1846.         // References to the current sheet are encoded differently to references to
  1847.         // external sheets.
  1848.         //
  1849.         if ($this->_phpSheet->getTitle(== $sheetname{
  1850.             $sheetname '';
  1851.             $length    0x02;  // The following 2 bytes
  1852.             $cch       1;     // The following byte
  1853.             $rgch      0x02;  // Self reference
  1854.         else {
  1855.             $length    0x02 strlen($sheetname);
  1856.             $cch       strlen($sheetname);
  1857.             $rgch      0x03;  // Reference to a sheet in the current workbook
  1858.         }
  1859.  
  1860.         $header pack("vv",  $record$length);
  1861.         $data   pack("CC"$cch$rgch);
  1862.         $this->_append($header $data $sheetname);
  1863.     }
  1864.  
  1865.     /**
  1866.      * Writes the Excel BIFF PANE record.
  1867.      * The panes can either be frozen or thawed (unfrozen).
  1868.      * Frozen panes are specified in terms of an integer number of rows and columns.
  1869.      * Thawed panes are specified in terms of Excel's units for rows and columns.
  1870.      *
  1871.      * @access private
  1872.      */
  1873.     function _storePanes()
  1874.     {
  1875.         $panes array();
  1876.         if ($freezePane $this->_phpSheet->getFreezePane()) {
  1877.             list($column$rowPHPExcel_Cell::coordinateFromString($freezePane);
  1878.             $panes[0$row 1;
  1879.             $panes[1PHPExcel_Cell::columnIndexFromString($column1;
  1880.         else {
  1881.             // thaw panes
  1882.             return;
  1883.         }
  1884.         
  1885.         $y       = isset($panes[0]$panes[0null;
  1886.         $x       = isset($panes[1]$panes[1null;
  1887.         $rwTop   = isset($panes[2]$panes[2null;
  1888.         $colLeft = isset($panes[3]$panes[3null;
  1889.         if (count($panes4// if Active pane was received
  1890.             $pnnAct $panes[4];
  1891.         else {
  1892.             $pnnAct null;
  1893.         }
  1894.         $record  0x0041;       // Record identifier
  1895.         $length  0x000A;       // Number of bytes to follow
  1896.  
  1897.         // Code specific to frozen or thawed panes.
  1898.         if ($this->_phpSheet->getFreezePane()) {
  1899.             // Set default values for $rwTop and $colLeft
  1900.             if (!isset($rwTop)) {
  1901.                 $rwTop   $y;
  1902.             }
  1903.             if (!isset($colLeft)) {
  1904.                 $colLeft $x;
  1905.             }
  1906.         else {
  1907.             // Set default values for $rwTop and $colLeft
  1908.             if (!isset($rwTop)) {
  1909.                 $rwTop   0;
  1910.             }
  1911.             if (!isset($colLeft)) {
  1912.                 $colLeft 0;
  1913.             }
  1914.  
  1915.             // Convert Excel's row and column units to the internal units.
  1916.             // The default row height is 12.75
  1917.             // The default column width is 8.43
  1918.             // The following slope and intersection values were interpolated.
  1919.             //
  1920.             $y 20*$y      255;
  1921.             $x 113.879*$x 390;
  1922.         }
  1923.  
  1924.  
  1925.         // Determine which pane should be active. There is also the undocumented
  1926.         // option to override this should it be necessary: may be removed later.
  1927.         //
  1928.         if (!isset($pnnAct)) {
  1929.             if ($x != && $y != 0{
  1930.                 $pnnAct 0// Bottom right
  1931.             }
  1932.             if ($x != && $y == 0{
  1933.                 $pnnAct 1// Top right
  1934.             }
  1935.             if ($x == && $y != 0{
  1936.                 $pnnAct 2// Bottom left
  1937.             }
  1938.             if ($x == && $y == 0{
  1939.                 $pnnAct 3// Top left
  1940.             }
  1941.         }
  1942.  
  1943.         $this->_active_pane = $pnnAct// Used in _storeSelection
  1944.  
  1945.         $header     pack("vv",    $record$length);
  1946.         $data       pack("vvvvv"$x$y$rwTop$colLeft$pnnAct);
  1947.         $this->_append($header $data);
  1948.     }
  1949.  
  1950.     /**
  1951.      * Store the page setup SETUP BIFF record.
  1952.      *
  1953.      * @access private
  1954.      */
  1955.     function _storeSetup()
  1956.     {
  1957.         $record       0x00A1;                  // Record identifier
  1958.         $length       0x0022;                  // Number of bytes to follow
  1959.  
  1960.         $iPaperSize   $this->_phpSheet->getPageSetup()->getPaperSize();    // Paper size
  1961.  
  1962.         $iScale $this->_phpSheet->getPageSetup()->getScale(?
  1963.             $this->_phpSheet->getPageSetup()->getScale(100;   // Print scaling factor
  1964.  
  1965.         $iPageStart   0x01;                 // Starting page number
  1966.         $iFitWidth    = (int) $this->_phpSheet->getPageSetup()->getFitToWidth();    // Fit to number of pages wide
  1967.         $iFitHeight    = (int) $this->_phpSheet->getPageSetup()->getFitToHeight();    // Fit to number of pages high
  1968.         $grbit        0x00;                 // Option flags
  1969.         $iRes         0x0258;               // Print resolution
  1970.         $iVRes        0x0258;               // Vertical print resolution
  1971.         
  1972.         $numHdr       $this->_phpSheet->getPageMargins()->getHeader();  // Header Margin
  1973.         
  1974.         $numFtr       $this->_phpSheet->getPageMargins()->getFooter();   // Footer Margin
  1975.         $iCopies      0x01;                 // Number of copies
  1976.  
  1977.         $fLeftToRight 0x0;                     // Print over then down
  1978.  
  1979.         // Page orientation
  1980.         $fLandscape ($this->_phpSheet->getPageSetup()->getOrientation(== PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE?
  1981.             0x0 0x1;
  1982.  
  1983.         $fNoPls       0x0;                     // Setup not read from printer
  1984.         $fNoColor     0x0;                     // Print black and white
  1985.         $fDraft       0x0;                     // Print draft quality
  1986.         $fNotes       0x0;                     // Print notes
  1987.         $fNoOrient    0x0;                     // Orientation not set
  1988.         $fUsePage     0x0;                     // Use custom starting page
  1989.  
  1990.         $grbit           $fLeftToRight;
  1991.         $grbit          |= $fLandscape    << 1;
  1992.         $grbit          |= $fNoPls        << 2;
  1993.         $grbit          |= $fNoColor      << 3;
  1994.         $grbit          |= $fDraft        << 4;
  1995.         $grbit          |= $fNotes        << 5;
  1996.         $grbit          |= $fNoOrient     << 6;
  1997.         $grbit          |= $fUsePage      << 7;
  1998.  
  1999.         $numHdr pack("d"$numHdr);
  2000.         $numFtr pack("d"$numFtr);
  2001.         if (PHPExcel_Writer_Excel5_BIFFwriter::getByteOrder()) // if it's Big Endian
  2002.             $numHdr strrev($numHdr);
  2003.             $numFtr strrev($numFtr);
  2004.         }
  2005.  
  2006.         $header pack("vv"$record$length);
  2007.         $data1  pack("vvvvvvvv"$iPaperSize,
  2008.                                    $iScale,
  2009.                                    $iPageStart,
  2010.                                    $iFitWidth,
  2011.                                    $iFitHeight,
  2012.                                    $grbit,
  2013.                                    $iRes,
  2014.                                    $iVRes);
  2015.         $data2  $numHdr.$numFtr;
  2016.         $data3  pack("v"$iCopies);
  2017.         $this->_append($header $data1 $data2 $data3);
  2018.     }
  2019.  
  2020.     /**
  2021.      * Store the header caption BIFF record.
  2022.      *
  2023.      * @access private
  2024.      */
  2025.     function _storeHeader()
  2026.     {
  2027.         $record  0x0014;               // Record identifier
  2028.  
  2029.         /* removing for now
  2030.         // need to fix character count (multibyte!)
  2031.         if (strlen($this->_phpSheet->getHeaderFooter()->getOddHeader()) <= 255) {
  2032.             $str      = $this->_phpSheet->getHeaderFooter()->getOddHeader();       // header string
  2033.         } else {
  2034.             $str = '';
  2035.         }
  2036.         */
  2037.         
  2038.         if ($this->_BIFF_version == 0x0600{
  2039.             $recordData PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($this->_phpSheet->getHeaderFooter()->getOddHeader());
  2040.             $length strlen($recordData);
  2041.         else {
  2042.             $cch      strlen($this->_phpSheet->getHeaderFooter()->getOddHeader());         // Length of header string
  2043.             $length  $cch;             // Bytes to follow
  2044.             $data      pack("C",  $cch);
  2045.             $recordData $data $this->_phpSheet->getHeaderFooter()->getOddHeader();
  2046.         }
  2047.  
  2048.         $header   pack("vv"$record$length);
  2049.  
  2050.         $this->_append($header $recordData);
  2051.     }
  2052.  
  2053.     /**
  2054.      * Store the footer caption BIFF record.
  2055.      *
  2056.      * @access private
  2057.      */
  2058.     function _storeFooter()
  2059.     {
  2060.         $record  0x0015;               // Record identifier
  2061.  
  2062.         /* removing for now
  2063.         // need to fix character count (multibyte!)
  2064.         if (strlen($this->_phpSheet->getHeaderFooter()->getOddFooter()) <= 255) {
  2065.             $str = $this->_phpSheet->getHeaderFooter()->getOddFooter();
  2066.         } else {
  2067.             $str = '';
  2068.         }
  2069.         */
  2070.         
  2071.         if ($this->_BIFF_version == 0x0600{
  2072.             $recordData PHPExcel_Shared_String::UTF8toBIFF8UnicodeLong($this->_phpSheet->getHeaderFooter()->getOddFooter());
  2073.             $length strlen($recordData);
  2074.         else {
  2075.             $cch      strlen($this->_phpSheet->getHeaderFooter()->getOddFooter());         // Length of footer string
  2076.             $length  $cch;
  2077.             $data      pack("C",  $cch);
  2078.             $recordData $data $this->_phpSheet->getHeaderFooter()->getOddFooter();
  2079.         }
  2080.  
  2081.         $header    pack("vv"$record$length);
  2082.  
  2083.         $this->_append($header $recordData);
  2084.     }
  2085.  
  2086.     /**
  2087.      * Store the horizontal centering HCENTER BIFF record.
  2088.      *
  2089.      * @access private
  2090.      */
  2091.     function _storeHcenter()
  2092.     {
  2093.         $record   0x0083;              // Record identifier
  2094.         $length   0x0002;              // Bytes to follow
  2095.  
  2096.         $fHCenter $this->_phpSheet->getPageSetup()->getHorizontalCentered(0;     // Horizontal centering
  2097.  
  2098.         $header    pack("vv"$record$length);
  2099.         $data      pack("v",  $fHCenter);
  2100.  
  2101.         $this->_append($header.$data);
  2102.     }
  2103.  
  2104.     /**
  2105.      * Store the vertical centering VCENTER BIFF record.
  2106.      *
  2107.      * @access private
  2108.      */
  2109.     function _storeVcenter()
  2110.     {
  2111.         $record   0x0084;              // Record identifier
  2112.         $length   0x0002;              // Bytes to follow
  2113.  
  2114.         $fVCenter $this->_phpSheet->getPageSetup()->getVerticalCentered(0;     // Horizontal centering
  2115.  
  2116.         $header    pack("vv"$record$length);
  2117.         $data      pack("v",  $fVCenter);
  2118.         $this->_append($header $data);
  2119.     }
  2120.  
  2121.     /**
  2122.      * Store the LEFTMARGIN BIFF record.
  2123.      *
  2124.      * @access private
  2125.      */
  2126.     function _storeMarginLeft()
  2127.     {
  2128.         $record  0x0026;                   // Record identifier
  2129.         $length  0x0008;                   // Bytes to follow
  2130.  
  2131.         $margin  $this->_phpSheet->getPageMargins()->getLeft();     // Margin in inches
  2132.  
  2133.         $header    pack("vv",  $record$length);
  2134.         $data      pack("d",   $margin);
  2135.         if (PHPExcel_Writer_Excel5_BIFFwriter::getByteOrder()) // if it's Big Endian
  2136.             $data strrev($data);
  2137.         }
  2138.  
  2139.         $this->_append($header $data);
  2140.     }
  2141.  
  2142.     /**
  2143.      * Store the RIGHTMARGIN BIFF record.
  2144.      *
  2145.      * @access private
  2146.      */
  2147.     function _storeMarginRight()
  2148.     {
  2149.         $record  0x0027;                   // Record identifier
  2150.         $length  0x0008;                   // Bytes to follow
  2151.  
  2152.         $margin  $this->_phpSheet->getPageMargins()->getRight();     // Margin in inches
  2153.  
  2154.         $header    pack("vv",  $record$length);
  2155.         $data      pack("d",   $margin);
  2156.         if (PHPExcel_Writer_Excel5_BIFFwriter::getByteOrder()) // if it's Big Endian
  2157.             $data strrev($data);
  2158.         }
  2159.  
  2160.         $this->_append($header $data);
  2161.     }
  2162.  
  2163.     /**
  2164.      * Store the TOPMARGIN BIFF record.
  2165.      *
  2166.      * @access private
  2167.      */
  2168.     function _storeMarginTop()
  2169.     {
  2170.         $record  0x0028;                   // Record identifier
  2171.         $length  0x0008;                   // Bytes to follow
  2172.  
  2173.         $margin  $this->_phpSheet->getPageMargins()->getTop();     // Margin in inches
  2174.  
  2175.         $header    pack("vv",  $record$length);
  2176.         $data      pack("d",   $margin);
  2177.         if (PHPExcel_Writer_Excel5_BIFFwriter::getByteOrder()) // if it's Big Endian
  2178.             $data strrev($data);
  2179.         }
  2180.  
  2181.         $this->_append($header $data);
  2182.     }
  2183.  
  2184.     /**
  2185.      * Store the BOTTOMMARGIN BIFF record.
  2186.      *
  2187.      * @access private
  2188.      */
  2189.     function _storeMarginBottom()
  2190.     {
  2191.         $record  0x0029;                   // Record identifier
  2192.         $length  0x0008;                   // Bytes to follow
  2193.  
  2194.         $margin  $this->_phpSheet->getPageMargins()->getBottom();     // Margin in inches
  2195.  
  2196.         $header    pack("vv",  $record$length);
  2197.         $data      pack("d",   $margin);
  2198.         if (PHPExcel_Writer_Excel5_BIFFwriter::getByteOrder()) // if it's Big Endian
  2199.             $data strrev($data);
  2200.         }
  2201.  
  2202.         $this->_append($header $data);
  2203.     }
  2204.  
  2205.     /**
  2206.      * Write the PRINTHEADERS BIFF record.
  2207.      *
  2208.      * @access private
  2209.      */
  2210.     function _storePrintHeaders()
  2211.     {
  2212.         $record      0x002a;                   // Record identifier
  2213.         $length      0x0002;                   // Bytes to follow
  2214.  
  2215.         $fPrintRwCol $this->_print_headers;     // Boolean flag
  2216.  
  2217.         $header      pack("vv"$record$length);
  2218.         $data        pack("v"$fPrintRwCol);
  2219.         $this->_append($header $data);
  2220.     }
  2221.  
  2222.     /**
  2223.      * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
  2224.      * GRIDSET record.
  2225.      *
  2226.      * @access private
  2227.      */
  2228.     function _storePrintGridlines()
  2229.     {
  2230.         $record      0x002b;                    // Record identifier
  2231.         $length      0x0002;                    // Bytes to follow
  2232.  
  2233.         $fPrintGrid  $this->_phpSheet->getPrintGridlines(0;    // Boolean flag
  2234.  
  2235.         $header      pack("vv"$record$length);
  2236.         $data        pack("v"$fPrintGrid);
  2237.         $this->_append($header $data);
  2238.     }
  2239.  
  2240.     /**
  2241.      * Write the GRIDSET BIFF record. Must be used in conjunction with the
  2242.      * PRINTGRIDLINES record.
  2243.      *
  2244.      * @access private
  2245.      */
  2246.     function _storeGridset()
  2247.     {
  2248.         $record      0x0082;                        // Record identifier
  2249.         $length      0x0002;                        // Bytes to follow
  2250.  
  2251.         $fGridSet    !$this->_phpSheet->getPrintGridlines();     // Boolean flag
  2252.  
  2253.         $header      pack("vv",  $record$length);
  2254.         $data        pack("v",   $fGridSet);
  2255.         $this->_append($header $data);
  2256.     }
  2257.  
  2258.     /**
  2259.      * Write the GUTS BIFF record. This is used to configure the gutter margins
  2260.      * where Excel outline symbols are displayed. The visibility of the gutters is
  2261.      * controlled by a flag in WSBOOL.
  2262.      *
  2263.      * @see _storeWsbool()
  2264.      * @access private
  2265.      */
  2266.     function _storeGuts()
  2267.     {
  2268.         $record      0x0080;   // Record identifier
  2269.         $length      0x0008;   // Bytes to follow
  2270.  
  2271.         $dxRwGut     0x0000;   // Size of row gutter
  2272.         $dxColGut    0x0000;   // Size of col gutter
  2273.  
  2274.         // determine maximum row outline level
  2275.         $maxRowOutlineLevel 0;
  2276.         foreach ($this->_phpSheet->getRowDimensions(as $rowDimension{
  2277.             $maxRowOutlineLevel max($maxRowOutlineLevel$rowDimension->getOutlineLevel());
  2278.         }
  2279.  
  2280.         $col_level   0;
  2281.  
  2282.         // Calculate the maximum column outline level. The equivalent calculation
  2283.         // for the row outline level is carried out in _setRow().
  2284.         $colcount count($this->_colinfo);
  2285.         for ($i 0$i $colcount++$i{
  2286.             $col_level max($this->_colinfo[$i][5]$col_level);
  2287.         }
  2288.  
  2289.         // Set the limits for the outline levels (0 <= x <= 7).
  2290.         $col_level max(0min($col_level7));
  2291.  
  2292.         // The displayed level is one greater than the max outline levels
  2293.         if ($maxRowOutlineLevel{
  2294.             ++$maxRowOutlineLevel;
  2295.         }
  2296.         if ($col_level{
  2297.             ++$col_level;
  2298.         }
  2299.  
  2300.         $header      pack("vv",   $record$length);
  2301.         $data        pack("vvvv"$dxRwGut$dxColGut$maxRowOutlineLevel$col_level);
  2302.  
  2303.         $this->_append($header.$data);
  2304.     }
  2305.  
  2306.  
  2307.     /**
  2308.      * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
  2309.      * with the SETUP record.
  2310.      *
  2311.      * @access private
  2312.      */
  2313.     function _storeWsbool()
  2314.     {
  2315.         $record      0x0081;   // Record identifier
  2316.         $length      0x0002;   // Bytes to follow
  2317.         $grbit       0x0000;
  2318.  
  2319.         // The only option that is of interest is the flag for fit to page. So we
  2320.         // set all the options in one go.
  2321.         //
  2322.         // Set the option flags
  2323.         $grbit |= 0x0001;                           // Auto page breaks visible
  2324.         if ($this->_outline_style{
  2325.             $grbit |= 0x0020// Auto outline styles
  2326.         }
  2327.         if ($this->_phpSheet->getShowSummaryBelow()) {
  2328.             $grbit |= 0x0040// Outline summary below
  2329.         }
  2330.         if ($this->_phpSheet->getShowSummaryRight()) {
  2331.             $grbit |= 0x0080// Outline summary right
  2332.         }
  2333.         if ($this->_phpSheet->getPageSetup()->getFitToPage()) {
  2334.             $grbit |= 0x0100// Page setup fit to page
  2335.         }
  2336.         if ($this->_outline_on{
  2337.             $grbit |= 0x0400// Outline symbols displayed
  2338.         }
  2339.  
  2340.         $header      pack("vv"$record$length);
  2341.         $data        pack("v",  $grbit);
  2342.         $this->_append($header $data);
  2343.     }
  2344.  
  2345.     /**
  2346.      * Write the HORIZONTALPAGEBREAKS and VERTICALPAGEBREAKS BIFF records.
  2347.      */
  2348.     private function _storeBreaks()
  2349.     {
  2350.         // initialize
  2351.         $vbreaks array();
  2352.         $hbreaks array();
  2353.  
  2354.         foreach ($this->_phpSheet->getBreaks(as $cell => $breakType{
  2355.             // Fetch coordinates
  2356.             $coordinates PHPExcel_Cell::coordinateFromString($cell);
  2357.  
  2358.             // Decide what to do by the type of break
  2359.             switch ($breakType{
  2360.                 case PHPExcel_Worksheet::BREAK_COLUMN:
  2361.                     // Add to list of vertical breaks
  2362.                     $vbreaks[PHPExcel_Cell::columnIndexFromString($coordinates[0]1;
  2363.                     break;
  2364.  
  2365.                 case PHPExcel_Worksheet::BREAK_ROW:
  2366.                     // Add to list of horizontal breaks
  2367.                     $hbreaks[$coordinates[1];
  2368.                     break;
  2369.  
  2370.                 case PHPExcel_Worksheet::BREAK_NONE:
  2371.                 default:
  2372.                     // Nothing to do
  2373.                     break;
  2374.             }
  2375.         }
  2376.         
  2377.         //horizontal page breaks
  2378.         if (count($hbreaks0{
  2379.  
  2380.             // Sort and filter array of page breaks
  2381.             sort($hbreaksSORT_NUMERIC);
  2382.             if ($hbreaks[0== 0// don't use first break if it's 0
  2383.                 array_shift($hbreaks);
  2384.             }
  2385.  
  2386.             $record  0x001b;               // Record identifier
  2387.             $cbrk    count($hbreaks);       // Number of page breaks
  2388.             if ($this->_BIFF_version == 0x0600{
  2389.                 $length  $cbrk;      // Bytes to follow
  2390.             else {
  2391.                 $length  $cbrk;      // Bytes to follow
  2392.             }
  2393.  
  2394.             $header  pack("vv"$record$length);
  2395.             $data    pack("v",  $cbrk);
  2396.  
  2397.             // Append each page break
  2398.             foreach ($hbreaks as $hbreak{
  2399.                 if ($this->_BIFF_version == 0x0600{
  2400.                     $data .= pack("vvv"$hbreak0x00000x00ff);
  2401.                 else {
  2402.                     $data .= pack("v"$hbreak);
  2403.                 }
  2404.             }
  2405.  
  2406.             $this->_append($header $data);
  2407.         }
  2408.  
  2409.         // vertical page breaks
  2410.         if (count($vbreaks0{
  2411.  
  2412.             // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
  2413.             // It is slightly higher in Excel 97/200, approx. 1026
  2414.             $vbreaks array_slice($vbreaks01000);
  2415.  
  2416.             // Sort and filter array of page breaks
  2417.             sort($vbreaksSORT_NUMERIC);
  2418.             if ($vbreaks[0== 0// don't use first break if it's 0
  2419.                 array_shift($vbreaks);
  2420.             }
  2421.  
  2422.             $record  0x001a;               // Record identifier
  2423.             $cbrk    count($vbreaks);       // Number of page breaks
  2424.             if ($this->_BIFF_version == 0x0600{
  2425.                 $length  $cbrk;      // Bytes to follow
  2426.             else {
  2427.                 $length  $cbrk;      // Bytes to follow
  2428.             }
  2429.  
  2430.             $header  pack("vv",  $record$length);
  2431.             $data    pack("v",   $cbrk);
  2432.  
  2433.             // Append each page break
  2434.             foreach ($vbreaks as $vbreak{
  2435.                 if ($this->_BIFF_version == 0x0600{
  2436.                     $data .= pack("vvv"$vbreak0x00000xffff);
  2437.                 else {
  2438.                     $data .= pack("v"$vbreak);
  2439.                 }
  2440.             }
  2441.  
  2442.             $this->_append($header $data);
  2443.         }
  2444.     }
  2445.  
  2446.     /**
  2447.      * Set the Biff PROTECT record to indicate that the worksheet is protected.
  2448.      *
  2449.      * @access private
  2450.      */
  2451.     function _storeProtect()
  2452.     {
  2453.         // Exit unless sheet protection has been specified
  2454.         if (!$this->_phpSheet->getProtection()->getSheet()) {
  2455.             return;
  2456.         }
  2457.  
  2458.         $record      0x0012;             // Record identifier
  2459.         $length      0x0002;             // Bytes to follow
  2460.  
  2461.         $fLock       1;    // Worksheet is protected
  2462.  
  2463.         $header      pack("vv"$record$length);
  2464.         $data        pack("v",  $fLock);
  2465.  
  2466.         $this->_append($header.$data);
  2467.     }
  2468.  
  2469.     /**
  2470.      * Write SCENPROTECT
  2471.      */
  2472.     private function _writeScenProtect()
  2473.     {
  2474.         // Exit if sheet protection is not active
  2475.         if (!$this->_phpSheet->getProtection()->getSheet()) {
  2476.             return;
  2477.         }
  2478.  
  2479.         // Exit if scenarios are not protected
  2480.         if (!$this->_phpSheet->getProtection()->getScenarios()) {
  2481.             return;
  2482.         }
  2483.  
  2484.         $record 0x00DD// Record identifier
  2485.         $length 0x0002// Bytes to follow
  2486.  
  2487.         $header pack('vv'$record$length);
  2488.         $data pack('v'1);
  2489.  
  2490.         $this->_append($header $data);
  2491.     }
  2492.  
  2493.     /**
  2494.      * Write OBJECTPROTECT
  2495.      */
  2496.     private function _writeObjectProtect()
  2497.     {
  2498.         // Exit if sheet protection is not active
  2499.         if (!$this->_phpSheet->getProtection()->getSheet()) {
  2500.             return;
  2501.         }
  2502.  
  2503.         // Exit if objects are not protected
  2504.         if (!$this->_phpSheet->getProtection()->getObjects()) {
  2505.             return;
  2506.         }
  2507.  
  2508.         $record 0x0063// Record identifier
  2509.         $length 0x0002// Bytes to follow
  2510.  
  2511.         $header pack('vv'$record$length);
  2512.         $data pack('v'1);
  2513.  
  2514.         $this->_append($header $data);
  2515.     }
  2516.  
  2517.     /**
  2518.      * Write the worksheet PASSWORD record.
  2519.      *
  2520.      * @access private
  2521.      */
  2522.     function _storePassword()
  2523.     {
  2524.         // Exit unless sheet protection and password have been specified
  2525.         if (!$this->_phpSheet->getProtection()->getSheet(|| !$this->_phpSheet->getProtection()->getPassword()) {
  2526.             return;
  2527.         }
  2528.  
  2529.         $record      0x0013;               // Record identifier
  2530.         $length      0x0002;               // Bytes to follow
  2531.  
  2532.         $wPassword   hexdec($this->_phpSheet->getProtection()->getPassword());     // Encoded password
  2533.  
  2534.         $header      pack("vv"$record$length);
  2535.         $data        pack("v",  $wPassword);
  2536.  
  2537.         $this->_append($header $data);
  2538.     }
  2539.  
  2540.  
  2541.     /**
  2542.      * Insert a 24bit bitmap image in a worksheet.
  2543.      *
  2544.      * @access public
  2545.      * @param integer $row     The row we are going to insert the bitmap into
  2546.      * @param integer $col     The column we are going to insert the bitmap into
  2547.      * @param mixed   $bitmap  The bitmap filename or GD-image resource
  2548.      * @param integer $x       The horizontal position (offset) of the image inside the cell.
  2549.      * @param integer $y       The vertical position (offset) of the image inside the cell.
  2550.      * @param float   $scale_x The horizontal scale
  2551.      * @param float   $scale_y The vertical scale
  2552.      */
  2553.     function insertBitmap($row$col$bitmap$x 0$y 0$scale_x 1$scale_y 1)
  2554.     {
  2555.         $bitmap_array (is_resource($bitmap$this->_processBitmapGd($bitmap$this->_processBitmap($bitmap));
  2556.         list($width$height$size$data$bitmap_array//$this->_processBitmap($bitmap);
  2557.  
  2558.         // Scale the frame of the image.
  2559.         $width  *= $scale_x;
  2560.         $height *= $scale_y;
  2561.  
  2562.         // Calculate the vertices of the image and write the OBJ record
  2563.         $this->_positionImage($col$row$x$y$width$height);
  2564.  
  2565.         // Write the IMDATA record to store the bitmap data
  2566.         $record      0x007f;
  2567.         $length      $size;
  2568.         $cf          0x09;
  2569.         $env         0x01;
  2570.         $lcb         $size;
  2571.  
  2572.         $header      pack("vvvvV"$record$length$cf$env$lcb);
  2573.         $this->_append($header.$data);
  2574.     }
  2575.  
  2576.     /**
  2577.      * Calculate the vertices that define the position of the image as required by
  2578.      * the OBJ record.
  2579.      *
  2580.      *         +------------+------------+
  2581.      *         |     A      |      B     |
  2582.      *   +-----+------------+------------+
  2583.      *   |     |(x1,y1)     |            |
  2584.      *   |  1  |(A1)._______|______      |
  2585.      *   |     |    |              |     |
  2586.      *   |     |    |              |     |
  2587.      *   +-----+----|    BITMAP    |-----+
  2588.      *   |     |    |              |     |
  2589.      *   |  2  |    |______________.     |
  2590.      *   |     |            |        (B2)|
  2591.      *   |     |            |     (x2,y2)|
  2592.      *   +---- +------------+------------+
  2593.      *
  2594.      * Example of a bitmap that covers some of the area from cell A1 to cell B2.
  2595.      *
  2596.      * Based on the width and height of the bitmap we need to calculate 8 vars:
  2597.      *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
  2598.      * The width and height of the cells are also variable and have to be taken into
  2599.      * account.
  2600.      * The values of $col_start and $row_start are passed in from the calling
  2601.      * function. The values of $col_end and $row_end are calculated by subtracting
  2602.      * the width and height of the bitmap from the width and height of the
  2603.      * underlying cells.
  2604.      * The vertices are expressed as a percentage of the underlying cell width as
  2605.      * follows (rhs values are in pixels):
  2606.      *
  2607.      *       x1 = X / W *1024
  2608.      *       y1 = Y / H *256
  2609.      *       x2 = (X-1) / W *1024
  2610.      *       y2 = (Y-1) / H *256
  2611.      *
  2612.      *       Where:  X is distance from the left side of the underlying cell
  2613.      *               Y is distance from the top of the underlying cell
  2614.      *               W is the width of the cell
  2615.      *               H is the height of the cell
  2616.      * The SDK incorrectly states that the height should be expressed as a
  2617.      *        percentage of 1024.
  2618.      *
  2619.      * @access private
  2620.      * @param integer $col_start Col containing upper left corner of object
  2621.      * @param integer $row_start Row containing top left corner of object
  2622.      * @param integer $x1        Distance to left side of object
  2623.      * @param integer $y1        Distance to top of object
  2624.      * @param integer $width     Width of image frame
  2625.      * @param integer $height    Height of image frame
  2626.      */
  2627.     function _positionImage($col_start$row_start$x1$y1$width$height)
  2628.     {
  2629.         // Initialise end cell to the same as the start cell
  2630.         $col_end    $col_start;  // Col containing lower right corner of object
  2631.         $row_end    $row_start;  // Row containing bottom right corner of object
  2632.  
  2633.         // Zero the specified offset if greater than the cell dimensions
  2634.         if ($x1 >= PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_start))) {
  2635.             $x1 0;
  2636.         }
  2637.         if ($y1 >= PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_start 1)) {
  2638.             $y1 0;
  2639.         }
  2640.  
  2641.         $width      $width  $x1 -1;
  2642.         $height     $height $y1 -1;
  2643.  
  2644.         // Subtract the underlying cell widths to find the end cell of the image
  2645.         while ($width >= PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_end))) {
  2646.             $width -= PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_end));
  2647.             ++$col_end;
  2648.         }
  2649.  
  2650.         // Subtract the underlying cell heights to find the end cell of the image
  2651.         while ($height >= PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_end 1)) {
  2652.             $height -= PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_end 1);
  2653.             ++$row_end;
  2654.         }
  2655.  
  2656.         // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
  2657.         // with zero eight or width.
  2658.         //
  2659.         if (PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_start)) == 0{
  2660.             return;
  2661.         }
  2662.         if (PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_end))   == 0{
  2663.             return;
  2664.         }
  2665.         if (PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_start 1== 0{
  2666.             return;
  2667.         }
  2668.         if (PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_end 1)   == 0{
  2669.             return;
  2670.         }
  2671.  
  2672.         // Convert the pixel values to the percentage value expected by Excel
  2673.         $x1 $x1     PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_start))   1024;
  2674.         $y1 $y1     PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_start 1)   *  256;
  2675.         $x2 $width  PHPExcel_Shared_Excel5::sizeCol($this->_phpSheetPHPExcel_Cell::stringFromColumnIndex($col_end))     1024// Distance to right side of object
  2676.         $y2 $height PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet$row_end 1)     *  256// Distance to bottom of object
  2677.  
  2678.         $this->_storeObjPicture($col_start$x1,
  2679.                                  $row_start$y1,
  2680.                                  $col_end$x2,
  2681.                                  $row_end$y2);
  2682.     }
  2683.  
  2684.     /**
  2685.      * Store the OBJ record that precedes an IMDATA record. This could be generalise
  2686.      * to support other Excel objects.
  2687.      *
  2688.      * @access private
  2689.      * @param integer $colL Column containing upper left corner of object
  2690.      * @param integer $dxL  Distance from left side of cell
  2691.      * @param integer $rwT  Row containing top left corner of object
  2692.      * @param integer $dyT  Distance from top of cell
  2693.      * @param integer $colR Column containing lower right corner of object
  2694.      * @param integer $dxR  Distance from right of cell
  2695.      * @param integer $rwB  Row containing bottom right corner of object
  2696.      * @param integer $dyB  Distance from bottom of cell
  2697.      */
  2698.     function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB)
  2699.     {
  2700.         $record      0x005d;   // Record identifier
  2701.         $length      0x003c;   // Bytes to follow
  2702.  
  2703.         $cObj        0x0001;   // Count of objects in file (set to 1)
  2704.         $OT          0x0008;   // Object type. 8 = Picture
  2705.         $id          0x0001;   // Object ID
  2706.         $grbit       0x0614;   // Option flags
  2707.  
  2708.         $cbMacro     0x0000;   // Length of FMLA structure
  2709.         $Reserved1   0x0000;   // Reserved
  2710.         $Reserved2   0x0000;   // Reserved
  2711.  
  2712.         $icvBack     0x09;     // Background colour
  2713.         $icvFore     0x09;     // Foreground colour
  2714.         $fls         0x00;     // Fill pattern
  2715.         $fAuto       0x00;     // Automatic fill
  2716.         $icv         0x08;     // Line colour
  2717.         $lns         0xff;     // Line style
  2718.         $lnw         0x01;     // Line weight
  2719.         $fAutoB      0x00;     // Automatic border
  2720.         $frs         0x0000;   // Frame style
  2721.         $cf          0x0009;   // Image format, 9 = bitmap
  2722.         $Reserved3   0x0000;   // Reserved
  2723.         $cbPictFmla  0x0000;   // Length of FMLA structure
  2724.         $Reserved4   0x0000;   // Reserved
  2725.         $grbit2      0x0001;   // Option flags
  2726.         $Reserved5   0x0000;   // Reserved
  2727.  
  2728.  
  2729.         $header      pack("vv"$record$length);
  2730.         $data        pack("V"$cObj);
  2731.         $data       .= pack("v"$OT);
  2732.         $data       .= pack("v"$id);
  2733.         $data       .= pack("v"$grbit);
  2734.         $data       .= pack("v"$colL);
  2735.         $data       .= pack("v"$dxL);
  2736.         $data       .= pack("v"$rwT);
  2737.         $data       .= pack("v"$dyT);
  2738.         $data       .= pack("v"$colR);
  2739.         $data       .= pack("v"$dxR);
  2740.         $data       .= pack("v"$rwB);
  2741.         $data       .= pack("v"$dyB);
  2742.         $data       .= pack("v"$cbMacro);
  2743.         $data       .= pack("V"$Reserved1);
  2744.         $data       .= pack("v"$Reserved2);
  2745.         $data       .= pack("C"$icvBack);
  2746.         $data       .= pack("C"$icvFore);
  2747.         $data       .= pack("C"$fls);
  2748.         $data       .= pack("C"$fAuto);
  2749.         $data       .= pack("C"$icv);
  2750.         $data       .= pack("C"$lns);
  2751.         $data       .= pack("C"$lnw);
  2752.         $data       .= pack("C"$fAutoB);
  2753.         $data       .= pack("v"$frs);
  2754.         $data       .= pack("V"$cf);
  2755.         $data       .= pack("v"$Reserved3);
  2756.         $data       .= pack("v"$cbPictFmla);
  2757.         $data       .= pack("v"$Reserved4);
  2758.         $data       .= pack("v"$grbit2);
  2759.         $data       .= pack("V"$Reserved5);
  2760.  
  2761.         $this->_append($header $data);
  2762.     }
  2763.  
  2764.     /**
  2765.      * Convert a GD-image into the internal format.
  2766.      *
  2767.      * @access private
  2768.      * @param resource $image The image to process
  2769.      * @return array Array with data and properties of the bitmap
  2770.      */
  2771.     function _processBitmapGd($image{
  2772.         $width imagesx($image);
  2773.         $height imagesy($image);
  2774.  
  2775.         $data pack("Vvvvv"0x000c$width$height0x010x18);
  2776.         for ($j=$height$j--{
  2777.             for ($i=0$i $width++$i{
  2778.                 $color imagecolorsforindex($imageimagecolorat($image$i$j));
  2779.                 foreach (array("red""green""blue"as $key{
  2780.                     $color[$key$color[$keyround((255 $color[$key]$color["alpha"127);
  2781.                 }
  2782.                 $data .= chr($color["blue"]chr($color["green"]chr($color["red"]);
  2783.             }
  2784.             if (3*$width 4{
  2785.                 $data .= str_repeat("\x00"3*$width 4);
  2786.             }
  2787.         }
  2788.  
  2789.         return array($width$heightstrlen($data)$data);
  2790.     }
  2791.  
  2792.     /**
  2793.      * Convert a 24 bit bitmap into the modified internal format used by Windows.
  2794.      * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
  2795.      * MSDN library.
  2796.      *
  2797.      * @access private
  2798.      * @param string $bitmap The bitmap to process
  2799.      * @return array Array with data and properties of the bitmap
  2800.      */
  2801.     function _processBitmap($bitmap)
  2802.     {
  2803.         // Open file.
  2804.         $bmp_fd @fopen($bitmap,"rb");
  2805.         if (!$bmp_fd{
  2806.             throw new Exception("Couldn't import $bitmap");
  2807.         }
  2808.  
  2809.         // Slurp the file into a string.
  2810.         $data fread($bmp_fdfilesize($bitmap));
  2811.  
  2812.         // Check that the file is big enough to be a bitmap.
  2813.         if (strlen($data<= 0x36{
  2814.             throw new Exception("$bitmap doesn't contain enough data.\n");
  2815.         }
  2816.  
  2817.         // The first 2 bytes are used to identify the bitmap.
  2818.         $identity unpack("A2ident"$data);
  2819.         if ($identity['ident'!= "BM"{
  2820.             throw new Exception("$bitmap doesn't appear to be a valid bitmap image.\n");
  2821.         }
  2822.  
  2823.         // Remove bitmap data: ID.
  2824.         $data substr($data2);
  2825.  
  2826.         // Read and remove the bitmap size. This is more reliable than reading
  2827.         // the data size at offset 0x22.
  2828.         //
  2829.         $size_array   unpack("Vsa"substr($data04));
  2830.         $size   $size_array['sa'];
  2831.         $data   substr($data4);
  2832.         $size  -= 0x36// Subtract size of bitmap header.
  2833.         $size  += 0x0C// Add size of BIFF header.
  2834.  
  2835.         // Remove bitmap data: reserved, offset, header length.
  2836.         $data substr($data12);
  2837.  
  2838.         // Read and remove the bitmap width and height. Verify the sizes.
  2839.         $width_and_height unpack("V2"substr($data08));
  2840.         $width  $width_and_height[1];
  2841.         $height $width_and_height[2];
  2842.         $data   substr($data8);
  2843.         if ($width 0xFFFF{
  2844.             throw new Exception("$bitmap: largest image width supported is 65k.\n");
  2845.         }
  2846.         if ($height 0xFFFF{
  2847.             throw new Exception("$bitmap: largest image height supported is 65k.\n");
  2848.         }
  2849.  
  2850.         // Read and remove the bitmap planes and bpp data. Verify them.
  2851.         $planes_and_bitcount unpack("v2"substr($data04));
  2852.         $data substr($data4);
  2853.         if ($planes_and_bitcount[2!= 24// Bitcount
  2854.             throw new Exception("$bitmap isn't a 24bit true color bitmap.\n");
  2855.         }
  2856.         if ($planes_and_bitcount[1!= 1{
  2857.             throw new Exception("$bitmap: only 1 plane supported in bitmap image.\n");
  2858.         }
  2859.  
  2860.         // Read and remove the bitmap compression. Verify compression.
  2861.         $compression unpack("Vcomp"substr($data04));
  2862.         $data substr($data4);
  2863.  
  2864.         //$compression = 0;
  2865.         if ($compression['comp'!= 0{
  2866.             throw new Exception("$bitmap: compression not supported in bitmap image.\n");
  2867.         }
  2868.  
  2869.         // Remove bitmap data: data size, hres, vres, colours, imp. colours.
  2870.         $data substr($data20);
  2871.  
  2872.         // Add the BITMAPCOREHEADER data
  2873.         $header  pack("Vvvvv"0x000c$width$height0x010x18);
  2874.         $data    $header $data;
  2875.  
  2876.         return (array($width$height$size$data));
  2877.     }
  2878.  
  2879.     /**
  2880.      * Store the window zoom factor. This should be a reduced fraction but for
  2881.      * simplicity we will store all fractions with a numerator of 100.
  2882.      *
  2883.      * @access private
  2884.      */
  2885.     function _storeZoom()
  2886.     {
  2887.         // If scale is 100 we don't need to write a record
  2888.         if ($this->_phpSheet->getSheetView()->getZoomScale(== 100{
  2889.             return;
  2890.         }
  2891.  
  2892.         $record      0x00A0;               // Record identifier
  2893.         $length      0x0004;               // Bytes to follow
  2894.  
  2895.         $header      pack("vv"$record$length);
  2896.         $data        pack("vv"$this->_phpSheet->getSheetView()->getZoomScale()100);
  2897.         $this->_append($header $data);
  2898.     }
  2899.  
  2900.     /**
  2901.      * Write MSODRAWING record
  2902.      */
  2903.     private function _storeMsoDrawing()
  2904.     {
  2905.         // check if there are any shapes for this sheet
  2906.         if (count($this->_phpSheet->getDrawingCollection()) == 0{
  2907.             return;
  2908.         }
  2909.  
  2910.         // create intermediate Escher object
  2911.         $escher new PHPExcel_Shared_Escher();
  2912.  
  2913.         // dgContainer
  2914.         $dgContainer new PHPExcel_Shared_Escher_DgContainer();
  2915.  
  2916.         // set the drawing index (we use sheet index + 1)
  2917.         $dgContainer->setDgId($this->_phpSheet->getParent()->getIndex($this->_phpSheet1);
  2918.         $escher->setDgContainer($dgContainer);
  2919.  
  2920.         // spgrContainer
  2921.         $spgrContainer new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();
  2922.         $dgContainer->setSpgrContainer($spgrContainer);
  2923.  
  2924.         // add one shape which is the group shape
  2925.         $spContainer new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
  2926.         $spContainer->setSpgr(true);
  2927.         $spContainer->setSpType(0);
  2928.         $spContainer->setSpId(($this->_phpSheet->getParent()->getIndex($this->_phpSheet1<< 10);
  2929.         $spgrContainer->addChild($spContainer);
  2930.  
  2931.         // add the shapes
  2932.  
  2933.         // outer loop is for determining BSE index
  2934.         $blipIndex 0// 1-based index to BstoreContainer
  2935.  
  2936.         $countShapes 0// count number of shapes (minus group shape), in this sheet
  2937.  
  2938.         foreach ($this->_phpSheet->getParent()->getAllsheets(as $sheet{
  2939.             foreach ($sheet->getDrawingCollection(as $drawing{
  2940.                 ++$blipIndex;
  2941.  
  2942.                 if ($sheet === $this->_phpSheet{
  2943.                     ++$countShapes;
  2944.  
  2945.                     // add the shape
  2946.                     $spContainer new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
  2947.  
  2948.                     // set the shape type
  2949.                     $spContainer->setSpType(0x004B);
  2950.  
  2951.                     // set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
  2952.                     $spId $countShapes
  2953.                         | ($this->_phpSheet->getParent()->getIndex($this->_phpSheet1<< 10;
  2954.                     $spContainer->setSpId($spId);
  2955.  
  2956.                     // keep track of last spId
  2957.                     $lastSpId $spId;
  2958.  
  2959.                     // set the BLIP index
  2960.                     $spContainer->setOPT(0x4104$blipIndex);
  2961.  
  2962.                     // set coordinates and offsets, client anchor
  2963.                     $coordinates $drawing->getCoordinates();
  2964.                     $offsetX $drawing->getOffsetX();
  2965.                     $offsetY $drawing->getOffsetY();
  2966.                     $width $drawing->getWidth();
  2967.                     $height $drawing->getHeight();
  2968.  
  2969.                     $twoAnchor PHPExcel_Shared_Excel5::oneAnchor2twoAnchor($this->_phpSheet$coordinates$offsetX$offsetY$width$height);
  2970.  
  2971.                     $spContainer->setStartCoordinates($twoAnchor['startCoordinates']);
  2972.                     $spContainer->setStartOffsetX($twoAnchor['startOffsetX']);
  2973.                     $spContainer->setStartOffsetY($twoAnchor['startOffsetY']);
  2974.                     $spContainer->setEndCoordinates($twoAnchor['endCoordinates']);
  2975.                     $spContainer->setEndOffsetX($twoAnchor['endOffsetX']);
  2976.                     $spContainer->setEndOffsetY($twoAnchor['endOffsetY']);
  2977.  
  2978.                     $spgrContainer->addChild($spContainer);
  2979.                 }
  2980.             }
  2981.         }
  2982.  
  2983.         // set last shape index
  2984.         $dgContainer->setLastSpId($lastSpId);
  2985.  
  2986.         // write the Escher stream
  2987.         $writer new PHPExcel_Writer_Excel5_Escher($escher);
  2988.         $data $writer->close();
  2989.         $spOffsets $writer->getSpOffsets();
  2990.  
  2991.         // write the neccesary MSODRAWING, OBJ records
  2992.  
  2993.         // split the Escher stream
  2994.         $spOffsets[00;
  2995.         $nm count($spOffsets1// number of shapes excluding first shape
  2996.         for ($i 1$i <= $nm++$i{
  2997.             // MSODRAWING record
  2998.             $record 0x00EC;            // Record identifier
  2999.  
  3000.             // chunk of Escher stream for one shape
  3001.  
  3002.             $dataChunk substr($data$spOffsets[$i -1]$spOffsets[$i$spOffsets[$i 1]);
  3003.  
  3004.             $length strlen($dataChunk);
  3005.             $header pack("vv"$record$length);
  3006.  
  3007.             $this->_append($header $dataChunk);
  3008.  
  3009.             // OBJ record
  3010.             $record 0x005D// record identifier
  3011.             $objData '';
  3012.  
  3013.             // ftCmo
  3014.             $objData .=
  3015.                 pack('vvvvvVVV'
  3016.                     0x0015    // 0x0015 = ftCmo
  3017.                     0x0012    // length of ftCmo data
  3018.                     0x0008    // object type, 0x0008 = picture
  3019.                     $i        // object id number, Excel seems to use 1-based index, local for the sheet
  3020.                     0x6011    // option flags, 0x6011 is what OpenOffice.org uses
  3021.                     0            // reserved
  3022.                     0            // reserved
  3023.                     0            // reserved
  3024.                 );
  3025.             // ftEnd
  3026.             $objData .=
  3027.                 pack('vv'
  3028.                     0x0000    // 0x0000 = ftEnd
  3029.                     0x0000    // length of ftEnd data
  3030.                 );
  3031.  
  3032.             $length strlen($objData);
  3033.             $header pack('vv'$record$length);
  3034.             $this->_append($header $objData);
  3035.         }
  3036.         
  3037.     }
  3038.  
  3039.     /**
  3040.      * Store the DVAL and DV records.
  3041.      *
  3042.      * @access private
  3043.      */
  3044.     function _storeDataValidity()
  3045.     {
  3046.         $record      0x01b2;      // Record identifier
  3047.         $length      0x0012;      // Bytes to follow
  3048.  
  3049.         $grbit       0x0002;      // Prompt box at cell, no cached validity data at DV records
  3050.         $horPos      0x00000000;  // Horizontal position of prompt box, if fixed position
  3051.         $verPos      0x00000000;  // Vertical position of prompt box, if fixed position
  3052.         $objId       0xffffffff;  // Object identifier of drop down arrow object, or -1 if not visible
  3053.  
  3054.         $header      pack('vv'$record$length);
  3055.         $data        pack('vVVVV'$grbit$horPos$verPos$objId,
  3056.                                      count($this->_dv));
  3057.         $this->_append($header.$data);
  3058.  
  3059.         $record 0x01be;              // Record identifier
  3060.         foreach ($this->_dv as $dv{
  3061.             $length strlen($dv);      // Bytes to follow
  3062.             $header pack("vv"$record$length);
  3063.             $this->_append($header $dv);
  3064.         }
  3065.     }
  3066.  
  3067.     /**
  3068.      * Map Error code
  3069.      */
  3070.     private function _mapErrorCode($errorCode{
  3071.         switch ($errorCode{
  3072.             case '#NULL!':    return 0x00;
  3073.             case '#DIV/0!':    return 0x07;
  3074.             case '#VALUE!':    return 0x0F;
  3075.             case '#REF!':    return 0x17;
  3076.             case '#NAME?':    return 0x1D;
  3077.             case '#NUM!':    return 0x24;
  3078.             case '#N/A':    return 0x2A;
  3079.         }
  3080.  
  3081.         return 0;
  3082.     }
  3083.  
  3084. }

Documentation generated on Mon, 11 Jan 2010 08:19:12 +0100 by phpDocumentor 1.4.1