Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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