Source for file Root.php
Documentation is available at Root.php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Xavier Noguer <xnoguer@php.net> |
// | Based on OLE::Storage_Lite by Kawai, Takanori |
// +----------------------------------------------------------------------+
// $Id: Root.php,v 1.9 2005/04/23 21:53:49 dufuz Exp $
* Class for creating Root PPS's for OLE containers
* @author Xavier Noguer <xnoguer@php.net>
* @package PHPExcel_Shared_OLE
* Directory for temporary files
* @param integer $time_1st A timestamp
* @param integer $time_2nd A timestamp
public function __construct($time_1st, $time_2nd, $raChild)
* Method for saving the whole OLE container (including files).
* In fact, if called with an empty argument (or '-'), it saves to a
* temporary file and then outputs it's contents to stdout.
* If a resource pointer to a stream created by fopen() is passed
* it will be used, but you have to close such stream by yourself.
* @param string|resource$filename The name of the file or stream where to save the OLE container.
* @return mixed true on success
public function save($filename)
// Initial Setting for saving
$this->_BIG_BLOCK_SIZE = pow(2,
((isset ($this->_BIG_BLOCK_SIZE))? self::_adjust2($this->_BIG_BLOCK_SIZE) : 9));
$this->_SMALL_BLOCK_SIZE= pow(2,
((isset ($this->_SMALL_BLOCK_SIZE))? self::_adjust2($this->_SMALL_BLOCK_SIZE): 6));
$this->_FILEH_ = $filename;
} else if ($filename == '-' || $filename == '') {
$this->_FILEH_ = fopen($this->_tmp_filename,"w+b");
if ($this->_FILEH_ == false) {
throw new Exception("Can't create temporary file.");
$this->_FILEH_ = fopen($filename, "wb");
if ($this->_FILEH_ == false) {
throw new Exception("Can't open $filename. It may be in use or protected.");
// Make an array of PPS's (for Save)
// calculate values for header
list ($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
// Make Small Data string (write SBD)
// Write Big Block Depot and BDList and Adding Header informations
$this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
* @param array $raList Reference to an array of PPS's
* @return array The array of numbers
// Calculate Basic Setting
list ($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
$iCount = count($raList);
for ($i = 0; $i < $iCount; ++ $i) {
$raList[$i]->Size = $raList[$i]->_DataLen();
$iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
+ (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
$iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
(($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
$iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE;
$iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1: 0);
$iBBcnt += (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) +
(( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0));
$iPPScnt = (floor($iCnt/ $iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
return array($iSBDcnt, $iBBcnt, $iPPScnt);
* Helper function for caculating a magic value for block sizes
* @param integer $i2 The argument
private static function _adjust2($i2)
* @param integer $iSBDcnt
* @param integer $iPPScnt
public function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
// Calculate Basic Setting
$iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
$iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
$iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+ $iBdCntW) % $iBlCnt)? 1: 0);
if ($iBdCnt > $i1stBdL) {
$iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
$iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+ $iBdCntW) % $iBlCnt)? 1: 0);
if ($iBdCnt <= ($iBdExL* $iBlCnt+ $i1stBdL)) {
"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
. pack("V", $iBBcnt+ $iSBDcnt) //ROOT START
. pack("V", $iSBDcnt ? 0 : - 2) //Small Block Depot
// Extra BDList Start, Count
if ($iBdCnt < $i1stBdL) {
pack("V", - 2). // Extra BDList Start
pack("V", 0) // Extra BDList Count
for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++ $i) {
for ($j = 0; $j < $jB; ++ $j) {
* Saving big data (PPS's with data bigger than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
* @param array &$raList Reference to array of PPS's
$iCount = count($raList);
for ($i = 0; $i < $iCount; ++ $i) {
$raList[$i]->Size = $raList[$i]->_DataLen();
//if (isset($raList[$i]->_PPS_FILE)) {
// fseek($raList[$i]->_PPS_FILE, 0); // To The Top
// while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
// $iLen += strlen($sBuff);
// fwrite($FILE, $sBuff);
fwrite($FILE, $raList[$i]->_data);
if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) {
fwrite($FILE, str_repeat("\x00", $this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)));
$raList[$i]->_StartBlock = $iStBlk;
(floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
(($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
// Close file for each PPS, and unlink it
//if (isset($raList[$i]->_PPS_FILE)) {
// fclose($raList[$i]->_PPS_FILE);
// $raList[$i]->_PPS_FILE = null;
// unlink($raList[$i]->_tmp_filename);
* get small data (PPS's with data smaller than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
* @param array &$raList Reference to array of PPS's
$iCount = count($raList);
for ($i = 0; $i < $iCount; ++ $i) {
// Make SBD, small data string
if ($raList[$i]->Size <= 0) {
$iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
+ (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
for ($j = 0; $j < $jB; ++ $j) {
//// Add to Data String(this will be written for RootEntry)
//if ($raList[$i]->_PPS_FILE) {
// fseek($raList[$i]->_PPS_FILE, 0); // To The Top
// while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
$sRes .= $raList[$i]->_data;
if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) {
$sRes .= str_repeat("\x00",$this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE));
$raList[$i]->_StartBlock = $iSmBlk;
$iB = $iSbCnt - ($iSmBlk % $iSbCnt);
for ($i = 0; $i < $iB; ++ $i) {
* Saves all the PPS's WKs
* @param array $raList Reference to an array with all PPS's
for ($i = 0; $i < $iC; ++ $i) {
fwrite($this->_FILEH_, $raList[$i]->_getPpsWk());
* @param integer $iSbdSize
* @param integer $iPpsCnt
public function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
// Calculate Basic Setting
$iAll = $iBsize + $iPpsCnt + $iSbdSize;
$iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
$iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+ $iBdCntW) % $iBbCnt)? 1: 0);
$iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
$iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+ $iBdCntW) % $iBbCnt)? 1: 0);
if ($iBdCnt <= ($iBdExL* $iBbCnt+ $i1stBdL)) {
for ($i = 0; $i < ($iSbdSize - 1); ++ $i) {
for ($i = 0; $i < ($iBsize - 1); ++ $i) {
for ($i = 0; $i < ($iPpsCnt - 1); ++ $i) {
// Set for BBD itself ( 0xFFFFFFFD : BBD)
for ($i = 0; $i < $iBdCnt; ++ $i) {
for ($i = 0; $i < $iBdExL; ++ $i) {
if (($iAllW + $iBdCnt) % $iBbCnt) {
$iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt));
for ($i = 0; $i < $iBlock; ++ $i) {
if ($iBdCnt > $i1stBdL) {
for ($i = $i1stBdL;$i < $iBdCnt; $i++ , ++ $iN) {
if ($iN >= ($iBbCnt - 1)) {
fwrite($FILE, pack("V", $iBsize+ $iSbdSize+ $iPpsCnt+ $i));
if (($iBdCnt- $i1stBdL) % ($iBbCnt- 1)) {
$iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1));
for ($i = 0; $i < $iB; ++ $i) {
|