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$ 21 22if (!class_exists('OLE_PPS')) { 23 require_once 'OLE/PPS.php'; 24} 25 26if (!class_exists('System')) { 27 require_once 'System.php'; 28} 29 30/** 31* Class for creating Root PPS's for OLE containers 32* 33* @author Xavier Noguer <xnoguer@php.net> 34* @category Structures 35* @package OLE 36*/ 37class OLE_PPS_Root extends OLE_PPS 38{ 39 /** 40 * Flag to enable new logic 41 * @var bool 42 */ 43 var $new_func = true; 44 45 /** 46 * The temporary dir for storing the OLE file 47 * @var string 48 */ 49 var $_tmp_dir; 50 51 /** 52 * Constructor 53 * 54 * @access public 55 * @param integer $time_1st A timestamp 56 * @param integer $time_2nd A timestamp 57 */ 58 function __construct($time_1st, $time_2nd, $raChild) 59 { 60 $system = new System(); 61 $this->_tmp_dir = $system->tmpdir(); 62 parent::__construct( 63 null, 64 OLE::Asc2Ucs('Root Entry'), 65 OLE_PPS_TYPE_ROOT, 66 null, 67 null, 68 null, 69 $time_1st, 70 $time_2nd, 71 null, 72 $raChild); 73 } 74 75 /** 76 * Sets the temp dir used for storing the OLE file 77 * 78 * @access public 79 * @param string $dir The dir to be used as temp dir 80 * @return true if given dir is valid, false otherwise 81 */ 82 function setTempDir($dir) 83 { 84 if (is_dir($dir)) { 85 $this->_tmp_dir = $dir; 86 return true; 87 } 88 return false; 89 } 90 91 /** 92 * Method for saving the whole OLE container (including files). 93 * In fact, if called with an empty argument (or '-'), it saves to a 94 * temporary file and then outputs it's contents to stdout. 95 * 96 * @param string $filename The name of the file where to save the OLE container 97 * @access public 98 * @return mixed true on success, PEAR_Error on failure 99 */ 100 function save($filename) 101 { 102 // Initial Setting for saving 103 $this->_BIG_BLOCK_SIZE = pow(2, 104 ((isset($this->_BIG_BLOCK_SIZE))? $this->_adjust2($this->_BIG_BLOCK_SIZE) : 9)); 105 $this->_SMALL_BLOCK_SIZE= pow(2, 106 ((isset($this->_SMALL_BLOCK_SIZE))? $this->_adjust2($this->_SMALL_BLOCK_SIZE): 6)); 107 108 // Open temp file if we are sending output to stdout 109 if (($filename == '-') || ($filename == '')) { 110 $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root"); 111 $this->_FILEH_ = @fopen($this->_tmp_filename,"w+b"); 112 if ($this->_FILEH_ == false) { 113 return $this->raiseError("Can't create temporary file."); 114 } 115 } else { 116 $this->_FILEH_ = @fopen($filename, "wb"); 117 if ($this->_FILEH_ == false) { 118 return $this->raiseError("Can't open $filename. It may be in use or protected."); 119 } 120 } 121 // Make an array of PPS's (for Save) 122 $aList = array(); 123 OLE_PPS_Root::_savePpsSetPnt($aList, array($this)); 124 // calculate values for header 125 list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo); 126 // Save Header 127 $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt); 128 129 // Make Small Data string (write SBD) 130 $this->_data = $this->_makeSmallData($aList); 131 132 // Write BB 133 $this->_saveBigData($iSBDcnt, $aList); 134 // Write PPS 135 $this->_savePps($aList); 136 // Write Big Block Depot and BDList and Adding Header informations 137 $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt); 138 // Close File, send it to stdout if necessary 139 if (($filename == '-') || ($filename == '')) { 140 fseek($this->_FILEH_, 0); 141 fpassthru($this->_FILEH_); 142 @fclose($this->_FILEH_); 143 // Delete the temporary file. 144 @unlink($this->_tmp_filename); 145 } else { 146 @fclose($this->_FILEH_); 147 } 148 149 return true; 150 } 151 152 /** 153 * Calculate some numbers 154 * 155 * @access private 156 * @param array $raList Reference to an array of PPS's 157 * @return array The array of numbers 158 */ 159 function _calcSize(&$raList) 160 { 161 // Calculate Basic Setting 162 list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0); 163 $iSmallLen = 0; 164 $iSBcnt = 0; 165 for ($i = 0; $i < count($raList); $i++) { 166 if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) { 167 $raList[$i]->Size = $raList[$i]->_DataLen(); 168 if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) { 169 $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) 170 + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); 171 } else { 172 $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) + 173 (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0)); 174 } 175 } 176 } 177 $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE; 178 $iSlCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE); 179 $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0); 180 $iBBcnt += (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) + 181 (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0)); 182 $iCnt = count($raList); 183 $iBdCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE; 184 $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0)); 185 186 return array($iSBDcnt, $iBBcnt, $iPPScnt); 187 } 188 189 /** 190 * Helper function for caculating a magic value for block sizes 191 * 192 * @access private 193 * @param integer $i2 The argument 194 * @see save() 195 * @return integer 196 */ 197 function _adjust2($i2) 198 { 199 $iWk = log($i2)/log(2); 200 return ($iWk > floor($iWk))? floor($iWk)+1:$iWk; 201 } 202 203 /** 204 * Save OLE header 205 * 206 * @access private 207 * @param integer $iSBDcnt 208 * @param integer $iBBcnt 209 * @param integer $iPPScnt 210 */ 211 function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt) 212 { 213 $FILE = $this->_FILEH_; 214 215 if($this->new_func) 216 return $this->_create_header($iSBDcnt, $iBBcnt, $iPPScnt); 217 218 // Calculate Basic Setting 219 $iBlCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; 220 $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; 221 222 $iBdExL = 0; 223 $iAll = $iBBcnt + $iPPScnt + $iSBDcnt; 224 $iAllW = $iAll; 225 $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0); 226 $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0); 227 228 // Calculate BD count 229 if ($iBdCnt > $i1stBdL) { 230 while (1) { 231 $iBdExL++; 232 $iAllW++; 233 $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0); 234 $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0); 235 if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) { 236 break; 237 } 238 } 239 } 240 241 // Save Header 242 fwrite($FILE, 243 "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" 244 . "\x00\x00\x00\x00" 245 . "\x00\x00\x00\x00" 246 . "\x00\x00\x00\x00" 247 . "\x00\x00\x00\x00" 248 . pack("v", 0x3b) 249 . pack("v", 0x03) 250 . pack("v", -2) 251 . pack("v", 9) 252 . pack("v", 6) 253 . pack("v", 0) 254 . "\x00\x00\x00\x00" 255 . "\x00\x00\x00\x00" 256 . pack("V", $iBdCnt) 257 . pack("V", $iBBcnt+$iSBDcnt) //ROOT START 258 . pack("V", 0) 259 . pack("V", 0x1000) 260 . pack("V", $iSBDcnt ? 0 : -2) //Small Block Depot 261 . pack("V", $iSBDcnt) 262 ); 263 // Extra BDList Start, Count 264 if ($iBdCnt < $i1stBdL) { 265 fwrite($FILE, 266 pack("V", -2). // Extra BDList Start 267 pack("V", 0) // Extra BDList Count 268 ); 269 } else { 270 fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL)); 271 } 272 273 // BDList 274 for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; $i++) { 275 fwrite($FILE, pack("V", $iAll+$i)); 276 } 277 if ($i < $i1stBdL) { 278 for ($j = 0; $j < ($i1stBdL-$i); $j++) { 279 fwrite($FILE, (pack("V", -1))); 280 } 281 } 282 } 283 284 /** 285 * Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL) 286 * 287 * @access private 288 * @param integer $iStBlk 289 * @param array &$raList Reference to array of PPS's 290 */ 291 function _saveBigData($iStBlk, &$raList) 292 { 293 $FILE = $this->_FILEH_; 294 295 // cycle through PPS's 296 for ($i = 0; $i < count($raList); $i++) { 297 if ($raList[$i]->Type != OLE_PPS_TYPE_DIR) { 298 $raList[$i]->Size = $raList[$i]->_DataLen(); 299 if (($raList[$i]->Size >= OLE_DATA_SIZE_SMALL) || 300 (($raList[$i]->Type == OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data))) 301 { 302 // Write Data 303 if (isset($raList[$i]->_PPS_FILE)) { 304 $iLen = 0; 305 fseek($raList[$i]->_PPS_FILE, 0); // To The Top 306 while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) { 307 $iLen += strlen($sBuff); 308 fwrite($FILE, $sBuff); 309 } 310 } else { 311 fwrite($FILE, $raList[$i]->_data); 312 } 313 314 if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) { 315 for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); $j++) { 316 fwrite($FILE, "\x00"); 317 } 318 } 319 // Set For PPS 320 $raList[$i]->_StartBlock = $iStBlk; 321 $iStBlk += 322 (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) + 323 (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0)); 324 } 325 // Close file for each PPS, and unlink it 326 if (isset($raList[$i]->_PPS_FILE)) { 327 @fclose($raList[$i]->_PPS_FILE); 328 $raList[$i]->_PPS_FILE = null; 329 @unlink($raList[$i]->_tmp_filename); 330 } 331 } 332 } 333 } 334 335 /** 336 * get small data (PPS's with data smaller than OLE_DATA_SIZE_SMALL) 337 * 338 * @access private 339 * @param array &$raList Reference to array of PPS's 340 */ 341 function _makeSmallData(&$raList) 342 { 343 $sRes = ''; 344 $FILE = $this->_FILEH_; 345 $iSmBlk = 0; 346 347 for ($i = 0; $i < count($raList); $i++) { 348 // Make SBD, small data string 349 if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) { 350 if ($raList[$i]->Size <= 0) { 351 continue; 352 } 353 if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) { 354 $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) 355 + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); 356 // Add to SBD 357 for ($j = 0; $j < ($iSmbCnt-1); $j++) { 358 fwrite($FILE, pack("V", $j+$iSmBlk+1)); 359 } 360 fwrite($FILE, pack("V", -2)); 361 362 // Add to Data String(this will be written for RootEntry) 363 if ($raList[$i]->_PPS_FILE) { 364 fseek($raList[$i]->_PPS_FILE, 0); // To The Top 365 while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) { 366 $sRes .= $sBuff; 367 } 368 } else { 369 $sRes .= $raList[$i]->_data; 370 } 371 if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) { 372 for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); $j++) { 373 $sRes .= "\x00"; 374 } 375 } 376 // Set for PPS 377 $raList[$i]->_StartBlock = $iSmBlk; 378 $iSmBlk += $iSmbCnt; 379 } 380 } 381 } 382 $iSbCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE); 383 if ($iSmBlk % $iSbCnt) { 384 for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); $i++) { 385 fwrite($FILE, pack("V", -1)); 386 } 387 } 388 return $sRes; 389 } 390 391 /** 392 * Saves all the PPS's WKs 393 * 394 * @access private 395 * @param array $raList Reference to an array with all PPS's 396 */ 397 function _savePps(&$raList) 398 { 399 // Save each PPS WK 400 for ($i = 0; $i < count($raList); $i++) { 401 fwrite($this->_FILEH_, $raList[$i]->_getPpsWk()); 402 } 403 // Adjust for Block 404 $iCnt = count($raList); 405 $iBCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE; 406 if ($iCnt % $iBCnt) { 407 for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * OLE_PPS_SIZE); $i++) { 408 fwrite($this->_FILEH_, "\x00"); 409 } 410 } 411 } 412 413 /** 414 * Saving Big Block Depot 415 * 416 * @access private 417 * @param integer $iSbdSize 418 * @param integer $iBsize 419 * @param integer $iPpsCnt 420 */ 421 function _saveBbd($iSbdSize, $iBsize, $iPpsCnt) 422 { 423 if($this->new_func) 424 return $this->_create_big_block_chain($iSbdSize, $iBsize, $iPpsCnt); 425 426 $FILE = $this->_FILEH_; 427 // Calculate Basic Setting 428 $iBbCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; 429 $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; 430 431 $iBdExL = 0; 432 $iAll = $iBsize + $iPpsCnt + $iSbdSize; 433 $iAllW = $iAll; 434 $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0); 435 $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0); 436 // Calculate BD count 437 if ($iBdCnt >$i1stBdL) { 438 while (1) { 439 $iBdExL++; 440 $iAllW++; 441 $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0); 442 $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0); 443 if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) { 444 break; 445 } 446 } 447 } 448 449 // Making BD 450 // Set for SBD 451 if ($iSbdSize > 0) { 452 for ($i = 0; $i < ($iSbdSize - 1); $i++) { 453 fwrite($FILE, pack("V", $i+1)); 454 } 455 fwrite($FILE, pack("V", -2)); 456 } 457 // Set for B 458 for ($i = 0; $i < ($iBsize - 1); $i++) { 459 fwrite($FILE, pack("V", $i+$iSbdSize+1)); 460 } 461 fwrite($FILE, pack("V", -2)); 462 463 // Set for PPS 464 for ($i = 0; $i < ($iPpsCnt - 1); $i++) { 465 fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1)); 466 } 467 fwrite($FILE, pack("V", -2)); 468 // Set for BBD itself ( 0xFFFFFFFD : BBD) 469 for ($i = 0; $i < $iBdCnt; $i++) { 470 fwrite($FILE, pack("V", 0xFFFFFFFD)); 471 } 472 // Set for ExtraBDList 473 for ($i = 0; $i < $iBdExL; $i++) { 474 fwrite($FILE, pack("V", 0xFFFFFFFC)); 475 } 476 // Adjust for Block 477 if (($iAllW + $iBdCnt) % $iBbCnt) { 478 for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); $i++) { 479 fwrite($FILE, pack("V", -1)); 480 } 481 } 482 // Extra BDList 483 if ($iBdCnt > $i1stBdL) { 484 $iN=0; 485 $iNb=0; 486 for ($i = $i1stBdL;$i < $iBdCnt; $i++, $iN++) { 487 if ($iN >= ($iBbCnt - 1)) { 488 $iN = 0; 489 $iNb++; 490 fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb)); 491 } 492 fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i)); 493 } 494 if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) { 495 for ($i = 0; $i < (($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1))); $i++) { 496 fwrite($FILE, pack("V", -1)); 497 } 498 } 499 fwrite($FILE, pack("V", -2)); 500 } 501 } 502 503 504 505 /** 506 * New method to store Bigblock chain 507 * 508 * @access private 509 * @param integer $num_sb_blocks - number of Smallblock depot blocks 510 * @param integer $num_bb_blocks - number of Bigblock depot blocks 511 * @param integer $num_pps_blocks - number of PropertySetStorage blocks 512 */ 513 function _create_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks) 514 { 515 $FILE = $this->_FILEH_; 516 517 $bbd_info = $this->_calculate_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks); 518 519 $data = ""; 520 521 if($num_sb_blocks > 0) 522 { 523 for($i = 0; $i<($num_sb_blocks-1); $i++) 524 $data .= pack("V", $i+1); 525 $data .= pack("V", -2); 526 } 527 528 for($i = 0; $i<($num_bb_blocks-1); $i++) 529 $data .= pack("V", $i + $num_sb_blocks + 1); 530 $data .= pack("V", -2); 531 532 for($i = 0; $i<($num_pps_blocks-1); $i++) 533 $data .= pack("V", $i + $num_sb_blocks + $num_bb_blocks + 1); 534 $data .= pack("V", -2); 535 536 for($i = 0; $i < $bbd_info["0xFFFFFFFD_blockchain_entries"]; $i++) 537 $data .= pack("V", 0xFFFFFFFD); 538 539 for($i = 0; $i < $bbd_info["0xFFFFFFFC_blockchain_entries"]; $i++) 540 $data .= pack("V", 0xFFFFFFFC); 541 542 // Adjust for Block 543 $all_entries = $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]; 544 if($all_entries % $bbd_info["entries_per_block"]) 545 { 546 $rest = $bbd_info["entries_per_block"] - ($all_entries % $bbd_info["entries_per_block"]); 547 for($i = 0; $i < $rest; $i++) 548 $data .= pack("V", -1); 549 } 550 551 // Extra BDList 552 if($bbd_info["blockchain_list_entries"] > $bbd_info["header_blockchain_list_entries"]) 553 { 554 $iN=0; 555 $iNb=0; 556 for($i = $bbd_info["header_blockchain_list_entries"]; $i < $bbd_info["blockchain_list_entries"]; $i++, $iN++) 557 { 558 if($iN >= ($bbd_info["entries_per_block"]-1)) 559 { 560 $iN = 0; 561 $iNb++; 562 $data .= pack("V", $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $iNb); 563 } 564 565 $data .= pack("V", $num_bb_blocks + $num_sb_blocks + $num_pps_blocks + $i); 566 } 567 568 $all_entries = $bbd_info["blockchain_list_entries"] - $bbd_info["header_blockchain_list_entries"]; 569 if(($all_entries % ($bbd_info["entries_per_block"] - 1))) 570 { 571 $rest = ($bbd_info["entries_per_block"] - 1) - ($all_entries % ($bbd_info["entries_per_block"] - 1)); 572 for($i = 0; $i < $rest; $i++) 573 $data .= pack("V", -1); 574 } 575 576 $data .= pack("V", -2); 577 } 578 579 /* 580 $this->dump($data, 0, strlen($data)); 581 die; 582 */ 583 584 fwrite($FILE, $data); 585 } 586 587 /** 588 * New method to store Header 589 * 590 * @access private 591 * @param integer $num_sb_blocks - number of Smallblock depot blocks 592 * @param integer $num_bb_blocks - number of Bigblock depot blocks 593 * @param integer $num_pps_blocks - number of PropertySetStorage blocks 594 */ 595 function _create_header($num_sb_blocks, $num_bb_blocks, $num_pps_blocks) 596 { 597 $FILE = $this->_FILEH_; 598 599 $bbd_info = $this->_calculate_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks); 600 601 // Save Header 602 fwrite($FILE, 603 "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" 604 . "\x00\x00\x00\x00" 605 . "\x00\x00\x00\x00" 606 . "\x00\x00\x00\x00" 607 . "\x00\x00\x00\x00" 608 . pack("v", 0x3b) 609 . pack("v", 0x03) 610 . pack("v", -2) 611 . pack("v", 9) 612 . pack("v", 6) 613 . pack("v", 0) 614 . "\x00\x00\x00\x00" 615 . "\x00\x00\x00\x00" 616 . pack("V", $bbd_info["blockchain_list_entries"]) 617 . pack("V", $num_sb_blocks + $num_bb_blocks) //ROOT START 618 . pack("V", 0) 619 . pack("V", 0x1000) 620 ); 621 622 //Small Block Depot 623 if($num_sb_blocks > 0) 624 fwrite($FILE, pack("V", 0)); 625 else 626 fwrite($FILE, pack("V", -2)); 627 628 fwrite($FILE, pack("V", $num_sb_blocks)); 629 630 // Extra BDList Start, Count 631 if($bbd_info["blockchain_list_entries"] < $bbd_info["header_blockchain_list_entries"]) 632 { 633 fwrite($FILE, 634 pack("V", -2). // Extra BDList Start 635 pack("V", 0) // Extra BDList Count 636 ); 637 } 638 else 639 { 640 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"])); 641 } 642 643 // BDList 644 for ($i=0; $i < $bbd_info["header_blockchain_list_entries"] and $i < $bbd_info["blockchain_list_entries"]; $i++) 645 { 646 fwrite($FILE, pack("V", $num_bb_blocks + $num_sb_blocks + $num_pps_blocks + $i)); 647 } 648 649 if($i < $bbd_info["header_blockchain_list_entries"]) 650 { 651 for($j = 0; $j < ($bbd_info["header_blockchain_list_entries"]-$i); $j++) 652 { 653 fwrite($FILE, (pack("V", -1))); 654 } 655 } 656 } 657 658 /** 659 * New method to calculate Bigblock chain 660 * 661 * @access private 662 * @param integer $num_sb_blocks - number of Smallblock depot blocks 663 * @param integer $num_bb_blocks - number of Bigblock depot blocks 664 * @param integer $num_pps_blocks - number of PropertySetStorage blocks 665 */ 666 function _calculate_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks) 667 { 668 $bbd_info["entries_per_block"] = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; 669 $bbd_info["header_blockchain_list_entries"] = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; 670 $bbd_info["blockchain_entries"] = $num_sb_blocks + $num_bb_blocks + $num_pps_blocks; 671 $bbd_info["0xFFFFFFFD_blockchain_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"]); 672 $bbd_info["blockchain_list_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"]); 673 674 // do some magic 675 $bbd_info["ext_blockchain_list_entries"] = 0; 676 $bbd_info["0xFFFFFFFC_blockchain_entries"] = 0; 677 if($bbd_info["blockchain_list_entries"] > $bbd_info["header_blockchain_list_entries"]) 678 { 679 do 680 { 681 $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"]); 682 $bbd_info["ext_blockchain_list_entries"] = $bbd_info["blockchain_list_entries"] - $bbd_info["header_blockchain_list_entries"]; 683 $bbd_info["0xFFFFFFFC_blockchain_entries"] = $this->get_number_of_pointer_blocks($bbd_info["ext_blockchain_list_entries"]); 684 $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"]); 685 } 686 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"])); 687 } 688 689 return $bbd_info; 690 } 691 692 /** 693 * Calculates number of pointer blocks 694 * 695 * @access public 696 * @param integer $num_pointers - number of pointers 697 */ 698 function get_number_of_pointer_blocks($num_pointers) 699 { 700 $pointers_per_block = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; 701 702 return floor($num_pointers / $pointers_per_block) + (($num_pointers % $pointers_per_block)? 1: 0); 703 } 704 705 /** 706 * Support method for some hexdumping 707 * 708 * @access public 709 * @param string $data - Binary data 710 * @param integer $from - Start offset of data to dump 711 * @param integer $to - Target offset of data to dump 712 */ 713 function dump($data, $from, $to) 714 { 715 $chars = array(); 716 $i = 0; 717 for($i = $from; $i < $to; $i++) 718 { 719 if(sizeof($chars) == 16) 720 { 721 printf("%08X (% 12d) |", $i-16, $i-16); 722 foreach($chars as $char) 723 printf(" %02X", $char); 724 print " |\n"; 725 726 $chars = array(); 727 } 728 729 $chars[] = ord($data[$i]); 730 } 731 732 if(sizeof($chars)) 733 { 734 printf("%08X (% 12d) |", $i-sizeof($chars), $i-sizeof($chars)); 735 foreach($chars as $char) 736 printf(" %02X", $char); 737 print " |\n"; 738 739 $chars = array(); 740 } 741 } 742} 743?> 744