bb34668146
This is preparatory to providing support for workbook properties (and extended properties) in the Excel5 Writer, because properties are stored in the SummaryInformation and DocumentSummaryInformation streams, and not in the workbook stream. Previously, PHP_OLE could only save a single stream, so this had to be the workbook stream; so document property information was discarded by the Excel5 Writer. git-svn-id: https://phpexcel.svn.codeplex.com/svn/trunk@77804 2327b42d-5241-43d6-9e2a-de5ac946f064
466 lines
14 KiB
PHP
466 lines
14 KiB
PHP
<?php
|
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
|
// +----------------------------------------------------------------------+
|
|
// | PHP Version 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>
|
|
* @category PHPExcel
|
|
* @package PHPExcel_Shared_OLE
|
|
*/
|
|
class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS
|
|
{
|
|
|
|
/**
|
|
* Directory for temporary files
|
|
* @var string
|
|
*/
|
|
protected $_tmp_dir = '';
|
|
|
|
/**
|
|
* @param integer $time_1st A timestamp
|
|
* @param integer $time_2nd A timestamp
|
|
*/
|
|
public function __construct($time_1st, $time_2nd, $raChild)
|
|
{
|
|
$this->_tempDir = PHPExcel_Shared_File::sys_get_temp_dir();
|
|
|
|
parent::__construct(
|
|
null,
|
|
PHPExcel_Shared_OLE::Asc2Ucs('Root Entry'),
|
|
PHPExcel_Shared_OLE::OLE_PPS_TYPE_ROOT,
|
|
null,
|
|
null,
|
|
null,
|
|
$time_1st,
|
|
$time_2nd,
|
|
null,
|
|
$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.
|
|
* @access public
|
|
* @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));
|
|
|
|
if (is_resource($filename)) {
|
|
$this->_FILEH_ = $filename;
|
|
} else if ($filename == '-' || $filename == '') {
|
|
$this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root");
|
|
$this->_FILEH_ = fopen($this->_tmp_filename,"w+b");
|
|
if ($this->_FILEH_ == false) {
|
|
throw new Exception("Can't create temporary file.");
|
|
}
|
|
} else {
|
|
$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)
|
|
$aList = array();
|
|
PHPExcel_Shared_OLE_PPS::_savePpsSetPnt($aList, array($this));
|
|
// calculate values for header
|
|
list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
|
|
// Save Header
|
|
$this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
|
|
|
|
// Make Small Data string (write SBD)
|
|
$this->_data = $this->_makeSmallData($aList);
|
|
|
|
// Write BB
|
|
$this->_saveBigData($iSBDcnt, $aList);
|
|
// Write PPS
|
|
$this->_savePps($aList);
|
|
// Write Big Block Depot and BDList and Adding Header informations
|
|
$this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
|
|
|
|
if (!is_resource($filename)) {
|
|
fclose($this->_FILEH_);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Calculate some numbers
|
|
*
|
|
* @access public
|
|
* @param array $raList Reference to an array of PPS's
|
|
* @return array The array of numbers
|
|
*/
|
|
public function _calcSize(&$raList)
|
|
{
|
|
// Calculate Basic Setting
|
|
list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
|
|
$iSmallLen = 0;
|
|
$iSBcnt = 0;
|
|
$iCount = count($raList);
|
|
for ($i = 0; $i < $iCount; ++$i) {
|
|
if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) {
|
|
$raList[$i]->Size = $raList[$i]->_DataLen();
|
|
if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) {
|
|
$iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
|
|
+ (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
|
|
} else {
|
|
$iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
|
|
(($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
|
|
}
|
|
}
|
|
}
|
|
$iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE;
|
|
$iSlCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE);
|
|
$iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0);
|
|
$iBBcnt += (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) +
|
|
(( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0));
|
|
$iCnt = count($raList);
|
|
$iBdCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE;
|
|
$iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
|
|
|
|
return array($iSBDcnt, $iBBcnt, $iPPScnt);
|
|
}
|
|
|
|
/**
|
|
* Helper function for caculating a magic value for block sizes
|
|
*
|
|
* @access public
|
|
* @param integer $i2 The argument
|
|
* @see save()
|
|
* @return integer
|
|
*/
|
|
private static function _adjust2($i2)
|
|
{
|
|
$iWk = log($i2)/log(2);
|
|
return ($iWk > floor($iWk))? floor($iWk)+1:$iWk;
|
|
}
|
|
|
|
/**
|
|
* Save OLE header
|
|
*
|
|
* @access public
|
|
* @param integer $iSBDcnt
|
|
* @param integer $iBBcnt
|
|
* @param integer $iPPScnt
|
|
*/
|
|
public function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
|
|
{
|
|
$FILE = $this->_FILEH_;
|
|
|
|
// Calculate Basic Setting
|
|
$iBlCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
|
|
$i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
|
|
|
|
$iBdExL = 0;
|
|
$iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
|
|
$iAllW = $iAll;
|
|
$iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
|
|
$iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
|
|
|
|
// Calculate BD count
|
|
if ($iBdCnt > $i1stBdL) {
|
|
while (1) {
|
|
++$iBdExL;
|
|
++$iAllW;
|
|
$iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
|
|
$iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
|
|
if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save Header
|
|
fwrite($FILE,
|
|
"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
|
|
. "\x00\x00\x00\x00"
|
|
. "\x00\x00\x00\x00"
|
|
. "\x00\x00\x00\x00"
|
|
. "\x00\x00\x00\x00"
|
|
. pack("v", 0x3b)
|
|
. pack("v", 0x03)
|
|
. pack("v", -2)
|
|
. pack("v", 9)
|
|
. pack("v", 6)
|
|
. pack("v", 0)
|
|
. "\x00\x00\x00\x00"
|
|
. "\x00\x00\x00\x00"
|
|
. pack("V", $iBdCnt)
|
|
. pack("V", $iBBcnt+$iSBDcnt) //ROOT START
|
|
. pack("V", 0)
|
|
. pack("V", 0x1000)
|
|
. pack("V", $iSBDcnt ? 0 : -2) //Small Block Depot
|
|
. pack("V", $iSBDcnt)
|
|
);
|
|
// Extra BDList Start, Count
|
|
if ($iBdCnt < $i1stBdL) {
|
|
fwrite($FILE,
|
|
pack("V", -2) // Extra BDList Start
|
|
. pack("V", 0) // Extra BDList Count
|
|
);
|
|
} else {
|
|
fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL));
|
|
}
|
|
|
|
// BDList
|
|
for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++$i) {
|
|
fwrite($FILE, pack("V", $iAll+$i));
|
|
}
|
|
if ($i < $i1stBdL) {
|
|
$jB = $i1stBdL - $i;
|
|
for ($j = 0; $j < $jB; ++$j) {
|
|
fwrite($FILE, (pack("V", -1)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Saving big data (PPS's with data bigger than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
|
|
*
|
|
* @access public
|
|
* @param integer $iStBlk
|
|
* @param array &$raList Reference to array of PPS's
|
|
*/
|
|
public function _saveBigData($iStBlk, &$raList)
|
|
{
|
|
$FILE = $this->_FILEH_;
|
|
|
|
// cycle through PPS's
|
|
$iCount = count($raList);
|
|
for ($i = 0; $i < $iCount; ++$i) {
|
|
if ($raList[$i]->Type != PHPExcel_Shared_OLE::OLE_PPS_TYPE_DIR) {
|
|
$raList[$i]->Size = $raList[$i]->_DataLen();
|
|
if (($raList[$i]->Size >= PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) ||
|
|
(($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data)))
|
|
{
|
|
// Write Data
|
|
//if (isset($raList[$i]->_PPS_FILE)) {
|
|
// $iLen = 0;
|
|
// fseek($raList[$i]->_PPS_FILE, 0); // To The Top
|
|
// while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
|
|
// $iLen += strlen($sBuff);
|
|
// fwrite($FILE, $sBuff);
|
|
// }
|
|
//} else {
|
|
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)));
|
|
}
|
|
// Set For PPS
|
|
$raList[$i]->_StartBlock = $iStBlk;
|
|
$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)
|
|
*
|
|
* @access public
|
|
* @param array &$raList Reference to array of PPS's
|
|
*/
|
|
public function _makeSmallData(&$raList)
|
|
{
|
|
$sRes = '';
|
|
$FILE = $this->_FILEH_;
|
|
$iSmBlk = 0;
|
|
|
|
$iCount = count($raList);
|
|
for ($i = 0; $i < $iCount; ++$i) {
|
|
// Make SBD, small data string
|
|
if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) {
|
|
if ($raList[$i]->Size <= 0) {
|
|
continue;
|
|
}
|
|
if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) {
|
|
$iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
|
|
+ (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
|
|
// Add to SBD
|
|
$jB = $iSmbCnt - 1;
|
|
for ($j = 0; $j < $jB; ++$j) {
|
|
fwrite($FILE, pack("V", $j+$iSmBlk+1));
|
|
}
|
|
fwrite($FILE, pack("V", -2));
|
|
|
|
//// 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 .= $sBuff;
|
|
// }
|
|
//} else {
|
|
$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));
|
|
}
|
|
// Set for PPS
|
|
$raList[$i]->_StartBlock = $iSmBlk;
|
|
$iSmBlk += $iSmbCnt;
|
|
}
|
|
}
|
|
}
|
|
$iSbCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE);
|
|
if ($iSmBlk % $iSbCnt) {
|
|
$iB = $iSbCnt - ($iSmBlk % $iSbCnt);
|
|
for ($i = 0; $i < $iB; ++$i) {
|
|
fwrite($FILE, pack("V", -1));
|
|
}
|
|
}
|
|
return $sRes;
|
|
}
|
|
|
|
/**
|
|
* Saves all the PPS's WKs
|
|
*
|
|
* @access public
|
|
* @param array $raList Reference to an array with all PPS's
|
|
*/
|
|
public function _savePps(&$raList)
|
|
{
|
|
// Save each PPS WK
|
|
$iC = count($raList);
|
|
for ($i = 0; $i < $iC; ++$i) {
|
|
fwrite($this->_FILEH_, $raList[$i]->_getPpsWk());
|
|
}
|
|
// Adjust for Block
|
|
$iCnt = count($raList);
|
|
$iBCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE;
|
|
if ($iCnt % $iBCnt) {
|
|
fwrite($this->_FILEH_, str_repeat("\x00",($iBCnt - ($iCnt % $iBCnt)) * PHPExcel_Shared_OLE::OLE_PPS_SIZE));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Saving Big Block Depot
|
|
*
|
|
* @access public
|
|
* @param integer $iSbdSize
|
|
* @param integer $iBsize
|
|
* @param integer $iPpsCnt
|
|
*/
|
|
public function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
|
|
{
|
|
$FILE = $this->_FILEH_;
|
|
// Calculate Basic Setting
|
|
$iBbCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
|
|
$i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
|
|
|
|
$iBdExL = 0;
|
|
$iAll = $iBsize + $iPpsCnt + $iSbdSize;
|
|
$iAllW = $iAll;
|
|
$iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
|
|
$iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
|
|
// Calculate BD count
|
|
if ($iBdCnt >$i1stBdL) {
|
|
while (1) {
|
|
++$iBdExL;
|
|
++$iAllW;
|
|
$iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
|
|
$iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
|
|
if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Making BD
|
|
// Set for SBD
|
|
if ($iSbdSize > 0) {
|
|
for ($i = 0; $i < ($iSbdSize - 1); ++$i) {
|
|
fwrite($FILE, pack("V", $i+1));
|
|
}
|
|
fwrite($FILE, pack("V", -2));
|
|
}
|
|
// Set for B
|
|
for ($i = 0; $i < ($iBsize - 1); ++$i) {
|
|
fwrite($FILE, pack("V", $i+$iSbdSize+1));
|
|
}
|
|
fwrite($FILE, pack("V", -2));
|
|
|
|
// Set for PPS
|
|
for ($i = 0; $i < ($iPpsCnt - 1); ++$i) {
|
|
fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
|
|
}
|
|
fwrite($FILE, pack("V", -2));
|
|
// Set for BBD itself ( 0xFFFFFFFD : BBD)
|
|
for ($i = 0; $i < $iBdCnt; ++$i) {
|
|
fwrite($FILE, pack("V", 0xFFFFFFFD));
|
|
}
|
|
// Set for ExtraBDList
|
|
for ($i = 0; $i < $iBdExL; ++$i) {
|
|
fwrite($FILE, pack("V", 0xFFFFFFFC));
|
|
}
|
|
// Adjust for Block
|
|
if (($iAllW + $iBdCnt) % $iBbCnt) {
|
|
$iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt));
|
|
for ($i = 0; $i < $iBlock; ++$i) {
|
|
fwrite($FILE, pack("V", -1));
|
|
}
|
|
}
|
|
// Extra BDList
|
|
if ($iBdCnt > $i1stBdL) {
|
|
$iN=0;
|
|
$iNb=0;
|
|
for ($i = $i1stBdL;$i < $iBdCnt; $i++, ++$iN) {
|
|
if ($iN >= ($iBbCnt - 1)) {
|
|
$iN = 0;
|
|
++$iNb;
|
|
fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb));
|
|
}
|
|
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) {
|
|
fwrite($FILE, pack("V", -1));
|
|
}
|
|
}
|
|
fwrite($FILE, pack("V", -2));
|
|
}
|
|
}
|
|
}
|