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 322720 2012-01-25 12:56:57Z clockwerx $
require_once 'OLE/PPS.php';
require_once 'System.php';
* Class for creating Root PPS's for OLE containers
* @author Xavier Noguer <xnoguer@php.net>
* Flag to enable new logic
* The temporary dir for storing the OLE file
* @param integer $time_1st A timestamp
* @param integer $time_2nd A timestamp
$this->_tmp_dir = System ::tmpdir ();
* Sets the temp dir used for storing the OLE file
* @param string $dir The dir to be used as temp dir
* @return true if given dir is valid, false otherwise
* 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.
* @param string $filename The name of the file where to save the OLE container
* @return mixed true on success, PEAR_Error on failure
// Initial Setting for saving
$this->_BIG_BLOCK_SIZE = pow(2 ,
((isset ($this->_BIG_BLOCK_SIZE))? $this->_adjust2 ($this->_BIG_BLOCK_SIZE) : 9 ));
$this->_SMALL_BLOCK_SIZE= pow(2 ,
((isset ($this->_SMALL_BLOCK_SIZE))? $this->_adjust2 ($this->_SMALL_BLOCK_SIZE): 6 ));
// Open temp file if we are sending output to stdout
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 ) {
return $this->raiseError ("Can't create temporary file.");
$this->_FILEH_ = @fopen($filename, "wb");
if ($this->_FILEH_ == false ) {
return $this->raiseError (" 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);
$this->_saveHeader ($iSBDcnt, $iBBcnt, $iPPScnt);
// Make Small Data string (write SBD)
$this->_data = $this->_makeSmallData ($aList);
$this->_saveBigData ($iSBDcnt, $aList);
// Write Big Block Depot and BDList and Adding Header informations
$this->_saveBbd ($iSBDcnt, $iBBcnt, $iPPScnt);
// Close File, send it to stdout if necessary
if (($filename == '-') || ($filename == '')) {
fseek($this->_FILEH_, 0 );
// Delete the temporary file.
@unlink($this->_tmp_filename);
* @param array $raList Reference to an array of PPS's
* @return array The array of numbers
function _calcSize (&$raList)
// Calculate Basic Setting
list ($iSBDcnt, $iBBcnt, $iPPScnt) = array (0 ,0 ,0 );
for ($i = 0; $i < count($raList); $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
* @param integer $iSBDcnt
* @param integer $iPPScnt
function _saveHeader ($iSBDcnt, $iBBcnt, $iPPScnt)
return $this->_create_header ($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 < ($i1stBdL- $i); $j++ ) {
* Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL)
* @param array &$raList Reference to array of PPS's
function _saveBigData ($iStBlk, &$raList)
for ($i = 0; $i < count($raList); $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 )) {
fwrite($FILE, $raList[$i]->_data );
if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) {
for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); $j++ ) {
$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 OLE_DATA_SIZE_SMALL)
* @param array &$raList Reference to array of PPS's
function _makeSmallData (&$raList)
for ($i = 0; $i < count($raList); $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 < ($iSmbCnt-1 ); $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) {
for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); $j++ ) {
$raList[$i]->_StartBlock = $iSmBlk;
for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); $i++ ) {
* Saves all the PPS's WKs
* @param array $raList Reference to an array with all PPS's
function _savePps (&$raList)
for ($i = 0; $i < count($raList); $i++ ) {
fwrite($this->_FILEH_, $raList[$i]->_getPpsWk ());
for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * OLE_PPS_SIZE); $i++ ) {
fwrite($this->_FILEH_, "\x00");
* @param integer $iSbdSize
* @param integer $iPpsCnt
function _saveBbd ($iSbdSize, $iBsize, $iPpsCnt)
return $this->_create_big_block_chain ($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) {
for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); $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 )) {
for ($i = 0; $i < (($iBbCnt - 1 ) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1 ))); $i++ ) {
* New method to store Bigblock chain
* @param integer $num_sb_blocks - number of Smallblock depot blocks
* @param integer $num_bb_blocks - number of Bigblock depot blocks
* @param integer $num_pps_blocks - number of PropertySetStorage blocks
function _create_big_block_chain ($num_sb_blocks, $num_bb_blocks, $num_pps_blocks)
$bbd_info = $this->_calculate_big_block_chain ($num_sb_blocks, $num_bb_blocks, $num_pps_blocks);
for($i = 0; $i< ($num_sb_blocks-1 ); $i++ )
$data .= pack("V", $i+1 );
for($i = 0; $i< ($num_bb_blocks-1 ); $i++ )
$data .= pack("V", $i + $num_sb_blocks + 1 );
for($i = 0; $i< ($num_pps_blocks-1 ); $i++ )
$data .= pack("V", $i + $num_sb_blocks + $num_bb_blocks + 1 );
for($i = 0; $i < $bbd_info["0xFFFFFFFD_blockchain_entries"]; $i++ )
$data .= pack("V", 0xFFFFFFFD );
for($i = 0; $i < $bbd_info["0xFFFFFFFC_blockchain_entries"]; $i++ )
$data .= pack("V", 0xFFFFFFFC );
$all_entries = $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"];
if($all_entries % $bbd_info["entries_per_block"])
$rest = $bbd_info["entries_per_block"] - ($all_entries % $bbd_info["entries_per_block"]);
for($i = 0; $i < $rest; $i++ )
if($bbd_info["blockchain_list_entries"] > $bbd_info["header_blockchain_list_entries"])
for($i = $bbd_info["header_blockchain_list_entries"]; $i < $bbd_info["blockchain_list_entries"]; $i++ , $iN++ )
if($iN >= ($bbd_info["entries_per_block"]-1 ))
$data .= pack("V", $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $iNb);
$data .= pack("V", $num_bb_blocks + $num_sb_blocks + $num_pps_blocks + $i);
$all_entries = $bbd_info["blockchain_list_entries"] - $bbd_info["header_blockchain_list_entries"];
if(($all_entries % ($bbd_info["entries_per_block"] - 1 )))
$rest = ($bbd_info["entries_per_block"] - 1 ) - ($all_entries % ($bbd_info["entries_per_block"] - 1 ));
for($i = 0; $i < $rest; $i++ )
$this->dump($data, 0, strlen($data));
* New method to store Header
* @param integer $num_sb_blocks - number of Smallblock depot blocks
* @param integer $num_bb_blocks - number of Bigblock depot blocks
* @param integer $num_pps_blocks - number of PropertySetStorage blocks
function _create_header ($num_sb_blocks, $num_bb_blocks, $num_pps_blocks)
$bbd_info = $this->_calculate_big_block_chain ($num_sb_blocks, $num_bb_blocks, $num_pps_blocks);
"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
. pack("V", $bbd_info["blockchain_list_entries"])
. pack("V", $num_sb_blocks + $num_bb_blocks) //ROOT START
// Extra BDList Start, Count
if($bbd_info["blockchain_list_entries"] < $bbd_info["header_blockchain_list_entries"])
pack("V", -2 ). // Extra BDList Start
pack("V", 0 ) // Extra BDList Count
fwrite($FILE, pack("V", $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"]) . pack("V", $bbd_info["0xFFFFFFFC_blockchain_entries"]));
for ($i=0; $i < $bbd_info["header_blockchain_list_entries"] and $i < $bbd_info["blockchain_list_entries"]; $i++ )
fwrite($FILE, pack("V", $num_bb_blocks + $num_sb_blocks + $num_pps_blocks + $i));
if($i < $bbd_info["header_blockchain_list_entries"])
for($j = 0; $j < ($bbd_info["header_blockchain_list_entries"]- $i); $j++ )
* New method to calculate Bigblock chain
* @param integer $num_sb_blocks - number of Smallblock depot blocks
* @param integer $num_bb_blocks - number of Bigblock depot blocks
* @param integer $num_pps_blocks - number of PropertySetStorage blocks
function _calculate_big_block_chain ($num_sb_blocks, $num_bb_blocks, $num_pps_blocks)
$bbd_info["header_blockchain_list_entries"] = ($this->_BIG_BLOCK_SIZE - 0x4C ) / OLE_LONG_INT_SIZE;
$bbd_info["blockchain_entries"] = $num_sb_blocks + $num_bb_blocks + $num_pps_blocks;
$bbd_info["blockchain_list_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"]);
$bbd_info["ext_blockchain_list_entries"] = 0;
$bbd_info["0xFFFFFFFC_blockchain_entries"] = 0;
if($bbd_info["blockchain_list_entries"] > $bbd_info["header_blockchain_list_entries"])
$bbd_info["blockchain_list_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]);
$bbd_info["ext_blockchain_list_entries"] = $bbd_info["blockchain_list_entries"] - $bbd_info["header_blockchain_list_entries"];
$bbd_info["0xFFFFFFFD_blockchain_entries"] = $this->get_number_of_pointer_blocks($num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]);
while ($bbd_info["blockchain_list_entries"] < $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]));
* Calculates number of pointer blocks
* @param integer $num_pointers - number of pointers
return floor($num_pointers / $pointers_per_block) + (($num_pointers % $pointers_per_block)? 1: 0 );
* Support method for some hexdumping
* @param string $data - Binary data
* @param integer $from - Start offset of data to dump
* @param integer $to - Target offset of data to dump
function dump($data, $from, $to)
for($i = $from; $i < $to; $i++ )
printf("%08X (% 12d) |", $i-16 , $i-16 );
$chars[] = ord($data[$i]);
Documentation generated on Mon, 11 Mar 2019 15:47:11 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|