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

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