2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
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 // +----------------------------------------------------------------------+
23 require_once ('OLE/PPS.php');
26 * Class for creating Root PPS's for OLE containers
28 * @author Xavier Noguer <xnoguer@php.net>
29 * @category Structures
32 class OLE_PPS_Root
extends OLE_PPS
35 * The temporary dir for storing the OLE file
44 * @param integer $time_1st A timestamp
45 * @param integer $time_2nd A timestamp
47 function OLE_PPS_Root($time_1st, $time_2nd, $raChild)
52 OLE
::Asc2Ucs('Root Entry'),
64 * Sets the temp dir used for storing the OLE file
67 * @param string $dir The dir to be used as temp dir
68 * @return true if given dir is valid, false otherwise
70 function setTempDir($dir)
73 $this->_tmp_dir
= $dir;
80 * Method for saving the whole OLE container (including files).
81 * In fact, if called with an empty argument (or '-'), it saves to a
82 * temporary file and then outputs it's contents to stdout.
84 * @param string $filename The name of the file where to save the OLE container
86 * @return mixed true on success, PEAR_Error on failure
88 function save($filename)
90 // Initial Setting for saving
91 $this->_BIG_BLOCK_SIZE
= pow(2,
92 ((isset($this->_BIG_BLOCK_SIZE
))?
$this->_adjust2($this->_BIG_BLOCK_SIZE
) : 9));
93 $this->_SMALL_BLOCK_SIZE
= pow(2,
94 ((isset($this->_SMALL_BLOCK_SIZE
))?
$this->_adjust2($this->_SMALL_BLOCK_SIZE
): 6));
96 // Open temp file if we are sending output to stdout
97 if (($filename == '-') or ($filename == ''))
99 $this->_tmp_filename
= tempnam($this->_tmp_dir
, "OLE_PPS_Root");
100 $this->_FILEH_
= @fopen
($this->_tmp_filename
,"w+b");
101 if ($this->_FILEH_
== false) {
102 return $this->raiseError("Can't create temporary file.");
107 $this->_FILEH_
= @fopen
($filename, "wb");
108 if ($this->_FILEH_
== false) {
109 return $this->raiseError("Can't open $filename. It may be in use or protected.");
112 // Make an array of PPS's (for Save)
114 $this->_savePpsSetPnt($aList);
115 // calculate values for header
116 list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
118 $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
120 // Make Small Data string (write SBD)
121 $this->_data
= $this->_makeSmallData($aList);
124 $this->_saveBigData($iSBDcnt, $aList);
126 $this->_savePps($aList);
127 // Write Big Block Depot and BDList and Adding Header informations
128 $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
129 // Close File, send it to stdout if necessary
130 if(($filename == '-') or ($filename == ''))
132 fseek($this->_FILEH_
, 0);
133 fpassthru($this->_FILEH_
);
134 @fclose
($this->_FILEH_
);
135 // Delete the temporary file.
136 @unlink
($this->_tmp_filename
);
139 @fclose
($this->_FILEH_
);
145 * Calculate some numbers
148 * @param array $raList Reference to an array of PPS's
149 * @return array The array of numbers
151 function _calcSize(&$raList)
153 // Calculate Basic Setting
154 list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
157 for ($i = 0; $i < count($raList); $i++
) {
158 if($raList[$i]->Type
== OLE_PPS_TYPE_FILE
) {
159 $raList[$i]->Size
= $raList[$i]->_DataLen();
160 if($raList[$i]->Size
< OLE_DATA_SIZE_SMALL
) {
161 $iSBcnt +
= floor($raList[$i]->Size
/ $this->_SMALL_BLOCK_SIZE
)
162 +
(($raList[$i]->Size %
$this->_SMALL_BLOCK_SIZE
)?
1: 0);
165 $iBBcnt +
= (floor($raList[$i]->Size
/ $this->_BIG_BLOCK_SIZE
) +
166 (($raList[$i]->Size %
$this->_BIG_BLOCK_SIZE
)?
1: 0));
170 $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE
;
171 $iSlCnt = floor($this->_BIG_BLOCK_SIZE
/ OLE_LONG_INT_SIZE
);
172 $iSBDcnt = floor($iSBcnt / $iSlCnt) +
(($iSBcnt %
$iSlCnt)?
1:0);
173 $iBBcnt +
= (floor($iSmallLen / $this->_BIG_BLOCK_SIZE
) +
174 (( $iSmallLen %
$this->_BIG_BLOCK_SIZE
)?
1: 0));
175 $iCnt = count($raList);
176 $iBdCnt = $this->_BIG_BLOCK_SIZE
/ OLE_PPS_SIZE
;
177 $iPPScnt = (floor($iCnt/$iBdCnt) +
(($iCnt %
$iBdCnt)?
1: 0));
179 return array($iSBDcnt, $iBBcnt, $iPPScnt);
183 * Helper function for caculating a magic value for block sizes
186 * @param integer $i2 The argument
190 function _adjust2($i2)
192 $iWk = log($i2)/log(2);
193 return ($iWk > floor($iWk))?
floor($iWk)+
1:$iWk;
200 * @param integer $iSBDcnt
201 * @param integer $iBBcnt
202 * @param integer $iPPScnt
204 function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
206 $FILE = $this->_FILEH_
;
208 // Calculate Basic Setting
209 $iBlCnt = $this->_BIG_BLOCK_SIZE
/ OLE_LONG_INT_SIZE
;
210 $i1stBdL = ($this->_BIG_BLOCK_SIZE
- 0x4C) / OLE_LONG_INT_SIZE
;
213 $iAll = $iBBcnt +
$iPPScnt +
$iSBDcnt;
215 $iBdCntW = floor($iAllW / $iBlCnt) +
(($iAllW %
$iBlCnt)?
1: 0);
216 $iBdCnt = floor(($iAll +
$iBdCntW) / $iBlCnt) +
((($iAllW+
$iBdCntW) %
$iBlCnt)?
1: 0);
218 // Calculate BD count
219 if ($iBdCnt >$i1stBdL)
225 $iBdCntW = floor($iAllW / $iBlCnt) +
(($iAllW %
$iBlCnt)?
1: 0);
226 $iBdCnt = floor(($iAllW +
$iBdCntW) / $iBlCnt) +
((($iAllW+
$iBdCntW) %
$iBlCnt)?
1: 0);
227 if ($iBdCnt <= ($iBdExL*$iBlCnt+
$i1stBdL)) {
235 "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
249 . pack("V", $iBBcnt+
$iSBDcnt) //ROOT START
252 . pack("V", 0) //Small Block Depot
255 // Extra BDList Start, Count
256 if ($iBdCnt < $i1stBdL)
259 pack("V", -2). // Extra BDList Start
260 pack("V", 0) // Extra BDList Count
265 fwrite($FILE, pack("V", $iAll+
$iBdCnt) . pack("V", $iBdExL));
269 for ($i=0; $i<$i1stBdL and $i < $iBdCnt; $i++
) {
270 fwrite($FILE, pack("V", $iAll+
$i));
274 for ($j = 0; $j < ($i1stBdL-$i); $j++
) {
275 fwrite($FILE, (pack("V", -1)));
281 * Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL)
284 * @param integer $iStBlk
285 * @param array &$raList Reference to array of PPS's
287 function _saveBigData($iStBlk, &$raList)
289 $FILE = $this->_FILEH_
;
291 // cycle through PPS's
292 for ($i = 0; $i < count($raList); $i++
)
294 if($raList[$i]->Type
!= OLE_PPS_TYPE_DIR
)
296 $raList[$i]->Size
= $raList[$i]->_DataLen();
297 if(($raList[$i]->Size
>= OLE_DATA_SIZE_SMALL
) or
298 (($raList[$i]->Type
== OLE_PPS_TYPE_ROOT
) and isset($raList[$i]->_data
)))
301 if(isset($raList[$i]->_PPS_FILE
))
304 fseek($raList[$i]->_PPS_FILE
, 0); // To The Top
305 while($sBuff = fread($raList[$i]->_PPS_FILE
, 4096))
307 $iLen +
= strlen($sBuff);
308 fwrite($FILE, $sBuff);
312 fwrite($FILE, $raList[$i]->_data
);
315 if ($raList[$i]->Size %
$this->_BIG_BLOCK_SIZE
)
317 for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE
- ($raList[$i]->Size %
$this->_BIG_BLOCK_SIZE
)); $j++
) {
318 fwrite($FILE, "\x00");
322 $raList[$i]->_StartBlock
= $iStBlk;
324 (floor($raList[$i]->Size
/ $this->_BIG_BLOCK_SIZE
) +
325 (($raList[$i]->Size %
$this->_BIG_BLOCK_SIZE
)?
1: 0));
327 // Close file for each PPS, and unlink it
328 if (isset($raList[$i]->_PPS_FILE
))
330 @fclose
($raList[$i]->_PPS_FILE
);
331 $raList[$i]->_PPS_FILE
= null;
332 @unlink
($raList[$i]->_tmp_filename
);
339 * get small data (PPS's with data smaller than OLE_DATA_SIZE_SMALL)
342 * @param array &$raList Reference to array of PPS's
344 function _makeSmallData(&$raList)
347 $FILE = $this->_FILEH_
;
350 for ($i = 0; $i < count($raList); $i++
)
352 // Make SBD, small data string
353 if ($raList[$i]->Type
== OLE_PPS_TYPE_FILE
)
355 if ($raList[$i]->Size
<= 0) {
358 if ($raList[$i]->Size
< OLE_DATA_SIZE_SMALL
)
360 $iSmbCnt = floor($raList[$i]->Size
/ $this->_SMALL_BLOCK_SIZE
)
361 +
(($raList[$i]->Size %
$this->_SMALL_BLOCK_SIZE
)?
1: 0);
363 for ($j = 0; $j < ($iSmbCnt-1); $j++
) {
364 fwrite($FILE, pack("V", $j+
$iSmBlk+
1));
366 fwrite($FILE, pack("V", -2));
368 // Add to Data String(this will be written for RootEntry)
369 if ($raList[$i]->_PPS_FILE
)
371 fseek($raList[$i]->_PPS_FILE
, 0); // To The Top
372 while ($sBuff = fread($raList[$i]->_PPS_FILE
, 4096)) {
377 $sRes .= $raList[$i]->_data
;
379 if($raList[$i]->Size %
$this->_SMALL_BLOCK_SIZE
)
381 for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE
- ($raList[$i]->Size %
$this->_SMALL_BLOCK_SIZE
)); $j++
) {
386 $raList[$i]->_StartBlock
= $iSmBlk;
391 $iSbCnt = floor($this->_BIG_BLOCK_SIZE
/ OLE_LONG_INT_SIZE
);
392 if($iSmBlk %
$iSbCnt)
394 for ($i = 0; $i < ($iSbCnt - ($iSmBlk %
$iSbCnt)); $i++
) {
395 fwrite($FILE, pack("V", -1));
402 * Saves all the PPS's WKs
405 * @param array $raList Reference to an array with all PPS's
407 function _savePps(&$raList)
410 for ($i = 0; $i < count($raList); $i++
) {
411 fwrite($this->_FILEH_
, $raList[$i]->_getPpsWk());
414 $iCnt = count($raList);
415 $iBCnt = $this->_BIG_BLOCK_SIZE
/ OLE_PPS_SIZE
;
418 for ($i = 0; $i < (($iBCnt - ($iCnt %
$iBCnt)) * OLE_PPS_SIZE
); $i++
) {
419 fwrite($this->_FILEH_
, "\x00");
425 * Saving Big Block Depot
428 * @param integer $iSbdSize
429 * @param integer $iBsize
430 * @param integer $iPpsCnt
432 function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
434 $FILE = $this->_FILEH_
;
435 // Calculate Basic Setting
436 $iBbCnt = $this->_BIG_BLOCK_SIZE
/ OLE_LONG_INT_SIZE
;
437 $i1stBdL = ($this->_BIG_BLOCK_SIZE
- 0x4C) / OLE_LONG_INT_SIZE
;
440 $iAll = $iBsize +
$iPpsCnt +
$iSbdSize;
442 $iBdCntW = floor($iAllW / $iBbCnt) +
(($iAllW %
$iBbCnt)?
1: 0);
443 $iBdCnt = floor(($iAll +
$iBdCntW) / $iBbCnt) +
((($iAllW+
$iBdCntW) %
$iBbCnt)?
1: 0);
444 // Calculate BD count
445 if ($iBdCnt >$i1stBdL)
451 $iBdCntW = floor($iAllW / $iBbCnt) +
(($iAllW %
$iBbCnt)?
1: 0);
452 $iBdCnt = floor(($iAllW +
$iBdCntW) / $iBbCnt) +
((($iAllW+
$iBdCntW) %
$iBbCnt)?
1: 0);
453 if ($iBdCnt <= ($iBdExL*$iBbCnt+
$i1stBdL)) {
463 for ($i = 0; $i<($iSbdSize-1); $i++
) {
464 fwrite($FILE, pack("V", $i+
1));
466 fwrite($FILE, pack("V", -2));
469 for ($i = 0; $i<($iBsize-1); $i++
) {
470 fwrite($FILE, pack("V", $i+
$iSbdSize+
1));
472 fwrite($FILE, pack("V", -2));
475 for ($i = 0; $i<($iPpsCnt-1); $i++
) {
476 fwrite($FILE, pack("V", $i+
$iSbdSize+
$iBsize+
1));
478 fwrite($FILE, pack("V", -2));
479 // Set for BBD itself ( 0xFFFFFFFD : BBD)
480 for ($i=0; $i<$iBdCnt;$i++
) {
481 fwrite($FILE, pack("V", 0xFFFFFFFD));
483 // Set for ExtraBDList
484 for ($i=0; $i<$iBdExL;$i++
) {
485 fwrite($FILE, pack("V", 0xFFFFFFFC));
488 if (($iAllW +
$iBdCnt) %
$iBbCnt)
490 for ($i = 0; $i < ($iBbCnt - (($iAllW +
$iBdCnt) %
$iBbCnt)); $i++
) {
491 fwrite($FILE, pack("V", -1));
495 if ($iBdCnt > $i1stBdL)
499 for ($i=$i1stBdL;$i<$iBdCnt; $i++
, $iN++
)
501 if ($iN>=($iBbCnt-1))
505 fwrite($FILE, pack("V", $iAll+
$iBdCnt+
$iNb));
507 fwrite($FILE, pack("V", $iBsize+
$iSbdSize+
$iPpsCnt+
$i));
509 if (($iBdCnt-$i1stBdL) %
($iBbCnt-1))
511 for ($i = 0; $i < (($iBbCnt-1) - (($iBdCnt-$i1stBdL) %
($iBbCnt-1))); $i++
) {
512 fwrite($FILE, pack("V", -1));
515 fwrite($FILE, pack("V", -2));