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

Source for file Workbook.php

Documentation is available at Workbook.php

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

Documentation generated on Tue, 01 Jun 2010 17:08:20 +0200 by phpDocumentor 1.4.3