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

Source for file Root.php

Documentation is available at Root.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Xavier Noguer <xnoguer@php.net>                              |
  17. // | Based on OLE::Storage_Lite by Kawai, Takanori                        |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Root.php,v 1.9 2005/04/23 21:53:49 dufuz Exp $
  21.  
  22.  
  23. /**
  24. * Class for creating Root PPS's for OLE containers
  25. *
  26. * @author   Xavier Noguer <xnoguer@php.net>
  27. * @category PHPExcel
  28. * @package  PHPExcel_Shared_OLE
  29. */
  30.     {
  31.  
  32.     /**
  33.      *    Directory for temporary files
  34.      *    @var string 
  35.      */
  36.     protected $_tmp_dir        = '';
  37.  
  38.     /**
  39.      * @param integer $time_1st A timestamp
  40.      * @param integer $time_2nd A timestamp
  41.      */
  42.     public function __construct($time_1st, $time_2nd, $raChild)
  43.     {
  44.         $this->_tempDir = PHPExcel_Shared_File::sys_get_temp_dir();
  45.  
  46.         parent::__construct(
  47.            null,
  48.            PHPExcel_Shared_OLE::Asc2Ucs('Root Entry'),
  49.            PHPExcel_Shared_OLE::OLE_PPS_TYPE_ROOT,
  50.            null,
  51.            null,
  52.            null,
  53.            $time_1st,
  54.            $time_2nd,
  55.            null,
  56.            $raChild);
  57.     }
  58.  
  59.     /**
  60.     * Method for saving the whole OLE container (including files).
  61.     * In fact, if called with an empty argument (or '-'), it saves to a
  62.     * temporary file and then outputs it's contents to stdout.
  63.     * If a resource pointer to a stream created by fopen() is passed
  64.     * it will be used, but you have to close such stream by yourself.
  65.     *
  66.     * @param string|resource$filename The name of the file or stream where to save the OLE container.
  67.     * @access public
  68.     * @return mixed true on success
  69.     */
  70.     public function save($filename)
  71.     {
  72.         // Initial Setting for saving
  73.         $this->_BIG_BLOCK_SIZE  = pow(2,
  74.                       ((isset($this->_BIG_BLOCK_SIZE))? self::_adjust2($this->_BIG_BLOCK_SIZE)  : 9));
  75.         $this->_SMALL_BLOCK_SIZE= pow(2,
  76.                       ((isset($this->_SMALL_BLOCK_SIZE))?  self::_adjust2($this->_SMALL_BLOCK_SIZE): 6));
  77.  
  78.         if (is_resource($filename)) {
  79.             $this->_FILEH_ = $filename;
  80.         } else if ($filename == '-' || $filename == '') {
  81.             $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root");
  82.             $this->_FILEH_ = fopen($this->_tmp_filename,"w+b");
  83.             if ($this->_FILEH_ == false) {
  84.                 throw new Exception("Can't create temporary file.");
  85.             }
  86.         } else {
  87.             $this->_FILEH_ = fopen($filename, "wb");
  88.         }
  89.         if ($this->_FILEH_ == false) {
  90.             throw new Exception("Can't open $filename. It may be in use or protected.");
  91.         }
  92.         // Make an array of PPS's (for Save)
  93.         $aList = array();
  94.         $this->_savePpsSetPnt($aList);
  95.         // calculate values for header
  96.         list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
  97.         // Save Header
  98.         $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
  99.  
  100.         // Make Small Data string (write SBD)
  101.         $this->_data = $this->_makeSmallData($aList);
  102.  
  103.         // Write BB
  104.         $this->_saveBigData($iSBDcnt, $aList);
  105.         // Write PPS
  106.         $this->_savePps($aList);
  107.         // Write Big Block Depot and BDList and Adding Header informations
  108.         $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
  109.  
  110.         if (!is_resource($filename)) {
  111.              fclose($this->_FILEH_);
  112.          }
  113.  
  114.         return true;
  115.     }
  116.  
  117.     /**
  118.     * Calculate some numbers
  119.     *
  120.     * @access public
  121.     * @param array $raList Reference to an array of PPS's
  122.     * @return array The array of numbers
  123.     */
  124.     public function _calcSize(&$raList)
  125.     {
  126.         // Calculate Basic Setting
  127.         list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
  128.         $iSmallLen = 0;
  129.         $iSBcnt = 0;
  130.         $iCount = count($raList);
  131.         for ($i = 0; $i < $iCount; ++$i) {
  132.             if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) {
  133.                 $raList[$i]->Size = $raList[$i]->_DataLen();
  134.                 if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) {
  135.                     $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
  136.                                   + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
  137.                 } else {
  138.                     $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
  139.                         (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
  140.                 }
  141.             }
  142.         }
  143.         $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE;
  144.         $iSlCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE);
  145.         $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0);
  146.         $iBBcnt +=  (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) +
  147.                       (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0));
  148.         $iCnt = count($raList);
  149.         $iBdCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE;
  150.         $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
  151.  
  152.         return array($iSBDcnt, $iBBcnt, $iPPScnt);
  153.     }
  154.  
  155.     /**
  156.     * Helper function for caculating a magic value for block sizes
  157.     *
  158.     * @access public
  159.     * @param integer $i2 The argument
  160.     * @see save()
  161.     * @return integer 
  162.     */
  163.     private static function _adjust2($i2)
  164.     {
  165.         $iWk = log($i2)/log(2);
  166.         return ($iWk > floor($iWk))? floor($iWk)+1:$iWk;
  167.     }
  168.  
  169.     /**
  170.     * Save OLE header
  171.     *
  172.     * @access public
  173.     * @param integer $iSBDcnt 
  174.     * @param integer $iBBcnt 
  175.     * @param integer $iPPScnt 
  176.     */
  177.     public function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
  178.     {
  179.         $FILE = $this->_FILEH_;
  180.  
  181.         // Calculate Basic Setting
  182.         $iBlCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
  183.         $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
  184.  
  185.         $iBdExL = 0;
  186.         $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
  187.         $iAllW = $iAll;
  188.         $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
  189.         $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
  190.  
  191.         // Calculate BD count
  192.         if ($iBdCnt > $i1stBdL) {
  193.             while (1) {
  194.                 ++$iBdExL;
  195.                 ++$iAllW;
  196.                 $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
  197.                 $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
  198.                 if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) {
  199.                     break;
  200.                 }
  201.             }
  202.         }
  203.  
  204.         // Save Header
  205.         fwrite($FILE,
  206.                   "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
  207.                   . "\x00\x00\x00\x00"
  208.                   . "\x00\x00\x00\x00"
  209.                   . "\x00\x00\x00\x00"
  210.                   . "\x00\x00\x00\x00"
  211.                   . pack("v", 0x3b)
  212.                   . pack("v", 0x03)
  213.                   . pack("v", -2)
  214.                   . pack("v", 9)
  215.                   . pack("v", 6)
  216.                   . pack("v", 0)
  217.                   . "\x00\x00\x00\x00"
  218.                   . "\x00\x00\x00\x00"
  219.                   . pack("V", $iBdCnt)
  220.                   . pack("V", $iBBcnt+$iSBDcnt) //ROOT START
  221.                   . pack("V", 0)
  222.                   . pack("V", 0x1000)
  223.                   . pack("V", $iSBDcnt ? 0 : -2)                  //Small Block Depot
  224.                   . pack("V", $iSBDcnt)
  225.           );
  226.         // Extra BDList Start, Count
  227.         if ($iBdCnt < $i1stBdL) {
  228.             fwrite($FILE,
  229.                       pack("V", -2).      // Extra BDList Start
  230.                       pack("V", 0)        // Extra BDList Count
  231.                   );
  232.         } else {
  233.             fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL));
  234.         }
  235.  
  236.         // BDList
  237.         for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++$i) {
  238.             fwrite($FILE, pack("V", $iAll+$i));
  239.         }
  240.         if ($i < $i1stBdL) {
  241.             $jB = $i1stBdL - $i;
  242.             for ($j = 0; $j < $jB; ++$j) {
  243.                 fwrite($FILE, (pack("V", -1)));
  244.             }
  245.         }
  246.     }
  247.  
  248.     /**
  249.     * Saving big data (PPS's with data bigger than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
  250.     *
  251.     * @access public
  252.     * @param integer $iStBlk 
  253.     * @param array &$raList Reference to array of PPS's
  254.     */
  255.     public function _saveBigData($iStBlk, &$raList)
  256.     {
  257.         $FILE = $this->_FILEH_;
  258.  
  259.         // cycle through PPS's
  260.         $iCount = count($raList);
  261.         for ($i = 0; $i < $iCount; ++$i) {
  262.             if ($raList[$i]->Type != PHPExcel_Shared_OLE::OLE_PPS_TYPE_DIR) {
  263.                 $raList[$i]->Size = $raList[$i]->_DataLen();
  264.                 if (($raList[$i]->Size >= PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) ||
  265.                     (($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data)))
  266.                 {
  267.                     // Write Data
  268.                     //if (isset($raList[$i]->_PPS_FILE)) {
  269.                     //    $iLen = 0;
  270.                     //    fseek($raList[$i]->_PPS_FILE, 0); // To The Top
  271.                     //    while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
  272.                     //        $iLen += strlen($sBuff);
  273.                     //        fwrite($FILE, $sBuff);
  274.                     //    }
  275.                     //} else {
  276.                         fwrite($FILE, $raList[$i]->_data);
  277.                     //}
  278.  
  279.                     if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) {
  280.                         fwrite($FILE, str_repeat("\x00", $this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)));
  281.                     }
  282.                     // Set For PPS
  283.                     $raList[$i]->_StartBlock = $iStBlk;
  284.                     $iStBlk +=
  285.                             (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
  286.                                 (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
  287.                 }
  288.                 // Close file for each PPS, and unlink it
  289.                 //if (isset($raList[$i]->_PPS_FILE)) {
  290.                 //    fclose($raList[$i]->_PPS_FILE);
  291.                 //    $raList[$i]->_PPS_FILE = null;
  292.                 //    unlink($raList[$i]->_tmp_filename);
  293.                 //}
  294.             }
  295.         }
  296.     }
  297.  
  298.     /**
  299.     * get small data (PPS's with data smaller than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
  300.     *
  301.     * @access public
  302.     * @param array &$raList Reference to array of PPS's
  303.     */
  304.     public function _makeSmallData(&$raList)
  305.     {
  306.         $sRes = '';
  307.         $FILE = $this->_FILEH_;
  308.         $iSmBlk = 0;
  309.  
  310.         $iCount = count($raList);
  311.         for ($i = 0; $i < $iCount; ++$i) {
  312.             // Make SBD, small data string
  313.             if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) {
  314.                 if ($raList[$i]->Size <= 0) {
  315.                     continue;
  316.                 }
  317.                 if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) {
  318.                     $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
  319.                                   + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
  320.                     // Add to SBD
  321.                     $jB = $iSmbCnt - 1;
  322.                     for ($j = 0; $j < $jB; ++$j) {
  323.                         fwrite($FILE, pack("V", $j+$iSmBlk+1));
  324.                     }
  325.                     fwrite($FILE, pack("V", -2));
  326.  
  327.                     //// Add to Data String(this will be written for RootEntry)
  328.                     //if ($raList[$i]->_PPS_FILE) {
  329.                     //    fseek($raList[$i]->_PPS_FILE, 0); // To The Top
  330.                     //    while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
  331.                     //        $sRes .= $sBuff;
  332.                     //    }
  333.                     //} else {
  334.                         $sRes .= $raList[$i]->_data;
  335.                     //}
  336.                     if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) {
  337.                         $sRes .= str_repeat("\x00",$this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE));
  338.                     }
  339.                     // Set for PPS
  340.                     $raList[$i]->_StartBlock = $iSmBlk;
  341.                     $iSmBlk += $iSmbCnt;
  342.                 }
  343.             }
  344.         }
  345.         $iSbCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE);
  346.         if ($iSmBlk % $iSbCnt) {
  347.             $iB = $iSbCnt - ($iSmBlk % $iSbCnt);
  348.             for ($i = 0; $i < $iB; ++$i) {
  349.                 fwrite($FILE, pack("V", -1));
  350.             }
  351.         }
  352.         return $sRes;
  353.     }
  354.  
  355.     /**
  356.     * Saves all the PPS's WKs
  357.     *
  358.     * @access public
  359.     * @param array $raList Reference to an array with all PPS's
  360.     */
  361.     public function _savePps(&$raList)
  362.     {
  363.         // Save each PPS WK
  364.         $iC = count($raList);
  365.         for ($i = 0; $i < $iC; ++$i) {
  366.             fwrite($this->_FILEH_, $raList[$i]->_getPpsWk());
  367.         }
  368.         // Adjust for Block
  369.         $iCnt = count($raList);
  370.         $iBCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE;
  371.         if ($iCnt % $iBCnt) {
  372.             fwrite($this->_FILEH_, str_repeat("\x00",($iBCnt - ($iCnt % $iBCnt)) * PHPExcel_Shared_OLE::OLE_PPS_SIZE));
  373.         }
  374.     }
  375.  
  376.     /**
  377.     * Saving Big Block Depot
  378.     *
  379.     * @access public
  380.     * @param integer $iSbdSize 
  381.     * @param integer $iBsize 
  382.     * @param integer $iPpsCnt 
  383.     */
  384.     public function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
  385.     {
  386.         $FILE = $this->_FILEH_;
  387.         // Calculate Basic Setting
  388.         $iBbCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
  389.         $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
  390.  
  391.         $iBdExL = 0;
  392.         $iAll = $iBsize + $iPpsCnt + $iSbdSize;
  393.         $iAllW = $iAll;
  394.         $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
  395.         $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
  396.         // Calculate BD count
  397.         if ($iBdCnt >$i1stBdL) {
  398.             while (1) {
  399.                 ++$iBdExL;
  400.                 ++$iAllW;
  401.                 $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
  402.                 $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
  403.                 if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) {
  404.                     break;
  405.                 }
  406.             }
  407.         }
  408.  
  409.         // Making BD
  410.         // Set for SBD
  411.         if ($iSbdSize > 0) {
  412.             for ($i = 0; $i < ($iSbdSize - 1); ++$i) {
  413.                 fwrite($FILE, pack("V", $i+1));
  414.             }
  415.             fwrite($FILE, pack("V", -2));
  416.         }
  417.         // Set for B
  418.         for ($i = 0; $i < ($iBsize - 1); ++$i) {
  419.             fwrite($FILE, pack("V", $i+$iSbdSize+1));
  420.         }
  421.         fwrite($FILE, pack("V", -2));
  422.  
  423.         // Set for PPS
  424.         for ($i = 0; $i < ($iPpsCnt - 1); ++$i) {
  425.             fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
  426.         }
  427.         fwrite($FILE, pack("V", -2));
  428.         // Set for BBD itself ( 0xFFFFFFFD : BBD)
  429.         for ($i = 0; $i < $iBdCnt; ++$i) {
  430.             fwrite($FILE, pack("V", 0xFFFFFFFD));
  431.         }
  432.         // Set for ExtraBDList
  433.         for ($i = 0; $i < $iBdExL; ++$i) {
  434.             fwrite($FILE, pack("V", 0xFFFFFFFC));
  435.         }
  436.         // Adjust for Block
  437.         if (($iAllW + $iBdCnt) % $iBbCnt) {
  438.             $iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt));
  439.             for ($i = 0; $i < $iBlock; ++$i) {
  440.                 fwrite($FILE, pack("V", -1));
  441.             }
  442.         }
  443.         // Extra BDList
  444.         if ($iBdCnt > $i1stBdL) {
  445.             $iN=0;
  446.             $iNb=0;
  447.             for ($i = $i1stBdL;$i < $iBdCnt; $i++, ++$iN) {
  448.                 if ($iN >= ($iBbCnt - 1)) {
  449.                     $iN = 0;
  450.                     ++$iNb;
  451.                     fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb));
  452.                 }
  453.                 fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
  454.             }
  455.             if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) {
  456.                 $iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1));
  457.                 for ($i = 0; $i < $iB; ++$i) {
  458.                     fwrite($FILE, pack("V", -1));
  459.                 }
  460.             }
  461.             fwrite($FILE, pack("V", -2));
  462.         }
  463.     }
  464. }

Documentation generated on Sun, 27 Feb 2011 16:33:47 -0800 by phpDocumentor 1.4.3