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

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