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