Completed
Push — master ( 4b5c92...896769 )
by Adrien
16:06 queued 09:43
created

Root::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
4
5
// vim: set expandtab tabstop=4 shiftwidth=4:
6
// +----------------------------------------------------------------------+
7
// | PHP Version 4                                                        |
8
// +----------------------------------------------------------------------+
9
// | Copyright (c) 1997-2002 The PHP Group                                |
10
// +----------------------------------------------------------------------+
11
// | This source file is subject to version 2.02 of the PHP license,      |
12
// | that is bundled with this package in the file LICENSE, and is        |
13
// | available at through the world-wide-web at                           |
14
// | http://www.php.net/license/2_02.txt.                                 |
15
// | If you did not receive a copy of the PHP license and are unable to   |
16
// | obtain it through the world-wide-web, please send a note to          |
17
// | [email protected] so we can mail you a copy immediately.               |
18
// +----------------------------------------------------------------------+
19
// | Author: Xavier Noguer <[email protected]>                              |
20
// | Based on OLE::Storage_Lite by Kawai, Takanori                        |
21
// +----------------------------------------------------------------------+
22
//
23
use PhpOffice\PhpSpreadsheet\Shared\OLE;
24
use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
25
26
/**
27
 * Class for creating Root PPS's for OLE containers.
28
 *
29
 * @author   Xavier Noguer <[email protected]>
30
 *
31
 * @category PhpSpreadsheet
32
 */
33
class Root extends PPS
34
{
35
    /**
36
     * @var resource
37
     */
38
    private $fileHandle;
39
40
    /**
41
     * @var int
42
     */
43
    private $smallBlockSize;
44
45
    /**
46
     * @var int
47
     */
48
    private $bigBlockSize;
49
50
    /**
51
     * @param int $time_1st A timestamp
52
     * @param int $time_2nd A timestamp
53
     * @param File[] $raChild
54
     */
55 51
    public function __construct($time_1st, $time_2nd, $raChild)
56
    {
57 51
        parent::__construct(null, OLE::ascToUcs('Root Entry'), OLE::OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild);
58 51
    }
59
60
    /**
61
     * Method for saving the whole OLE container (including files).
62
     * In fact, if called with an empty argument (or '-'), it saves to a
63
     * temporary file and then outputs it's contents to stdout.
64
     * If a resource pointer to a stream created by fopen() is passed
65
     * it will be used, but you have to close such stream by yourself.
66
     *
67
     * @param resource $fileHandle the name of the file or stream where to save the OLE container
68
     *
69
     * @return bool true on success
70
     */
71 51
    public function save($fileHandle)
72
    {
73 51
        $this->fileHandle = $fileHandle;
74
75
        // Initial Setting for saving
76 51
        $this->bigBlockSize = pow(
77 51
            2,
78 51
            (isset($this->bigBlockSize)) ? self::adjust2($this->bigBlockSize) : 9
79
        );
80 51
        $this->smallBlockSize = pow(
81 51
            2,
82 51
            (isset($this->smallBlockSize)) ? self::adjust2($this->smallBlockSize) : 6
83
        );
84
85
        // Make an array of PPS's (for Save)
86 51
        $aList = [];
87 51
        PPS::_savePpsSetPnt($aList, [$this]);
88
        // calculate values for header
89 51
        [$iSBDcnt, $iBBcnt, $iPPScnt] = $this->_calcSize($aList); //, $rhInfo);
90
        // Save Header
91 51
        $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
0 ignored issues
show
Bug introduced by
$iSBDcnt of type double is incompatible with the type integer expected by parameter $iSBDcnt of PhpOffice\PhpSpreadsheet...PPS\Root::_saveHeader(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
        $this->_saveHeader(/** @scrutinizer ignore-type */ $iSBDcnt, $iBBcnt, $iPPScnt);
Loading history...
Bug introduced by
$iPPScnt of type double is incompatible with the type integer expected by parameter $iPPScnt of PhpOffice\PhpSpreadsheet...PPS\Root::_saveHeader(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
        $this->_saveHeader($iSBDcnt, $iBBcnt, /** @scrutinizer ignore-type */ $iPPScnt);
Loading history...
Bug introduced by
$iBBcnt of type double is incompatible with the type integer expected by parameter $iBBcnt of PhpOffice\PhpSpreadsheet...PPS\Root::_saveHeader(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
        $this->_saveHeader($iSBDcnt, /** @scrutinizer ignore-type */ $iBBcnt, $iPPScnt);
Loading history...
92
93
        // Make Small Data string (write SBD)
94 51
        $this->_data = $this->_makeSmallData($aList);
95
96
        // Write BB
97 51
        $this->_saveBigData($iSBDcnt, $aList);
0 ignored issues
show
Bug introduced by
$iSBDcnt of type double is incompatible with the type integer expected by parameter $iStBlk of PhpOffice\PhpSpreadsheet...PS\Root::_saveBigData(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

97
        $this->_saveBigData(/** @scrutinizer ignore-type */ $iSBDcnt, $aList);
Loading history...
98
        // Write PPS
99 51
        $this->_savePps($aList);
100
        // Write Big Block Depot and BDList and Adding Header informations
101 51
        $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
0 ignored issues
show
Bug introduced by
$iPPScnt of type double is incompatible with the type integer expected by parameter $iPpsCnt of PhpOffice\PhpSpreadsheet...LE\PPS\Root::_saveBbd(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
        $this->_saveBbd($iSBDcnt, $iBBcnt, /** @scrutinizer ignore-type */ $iPPScnt);
Loading history...
Bug introduced by
$iSBDcnt of type double is incompatible with the type integer expected by parameter $iSbdSize of PhpOffice\PhpSpreadsheet...LE\PPS\Root::_saveBbd(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
        $this->_saveBbd(/** @scrutinizer ignore-type */ $iSBDcnt, $iBBcnt, $iPPScnt);
Loading history...
Bug introduced by
$iBBcnt of type double is incompatible with the type integer expected by parameter $iBsize of PhpOffice\PhpSpreadsheet...LE\PPS\Root::_saveBbd(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
        $this->_saveBbd($iSBDcnt, /** @scrutinizer ignore-type */ $iBBcnt, $iPPScnt);
Loading history...
102
103 51
        return true;
104
    }
105
106
    /**
107
     * Calculate some numbers.
108
     *
109
     * @param array $raList Reference to an array of PPS's
110
     *
111
     * @return float[] The array of numbers
112
     */
113 51
    public function _calcSize(&$raList)
114
    {
115
        // Calculate Basic Setting
116 51
        [$iSBDcnt, $iBBcnt, $iPPScnt] = [0, 0, 0];
117 51
        $iSmallLen = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $iSmallLen is dead and can be removed.
Loading history...
118 51
        $iSBcnt = 0;
119 51
        $iCount = count($raList);
120 51
        for ($i = 0; $i < $iCount; ++$i) {
121 51
            if ($raList[$i]->Type == OLE::OLE_PPS_TYPE_FILE) {
122 51
                $raList[$i]->Size = $raList[$i]->getDataLen();
123 51
                if ($raList[$i]->Size < OLE::OLE_DATA_SIZE_SMALL) {
124 51
                    $iSBcnt += floor($raList[$i]->Size / $this->smallBlockSize)
125 51
                                  + (($raList[$i]->Size % $this->smallBlockSize) ? 1 : 0);
126
                } else {
127 21
                    $iBBcnt += (floor($raList[$i]->Size / $this->bigBlockSize) +
128 21
                        (($raList[$i]->Size % $this->bigBlockSize) ? 1 : 0));
129
                }
130
            }
131
        }
132 51
        $iSmallLen = $iSBcnt * $this->smallBlockSize;
133 51
        $iSlCnt = floor($this->bigBlockSize / OLE::OLE_LONG_INT_SIZE);
134 51
        $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt) ? 1 : 0);
135 51
        $iBBcnt += (floor($iSmallLen / $this->bigBlockSize) +
136 51
                      (($iSmallLen % $this->bigBlockSize) ? 1 : 0));
137 51
        $iCnt = count($raList);
138 51
        $iBdCnt = $this->bigBlockSize / OLE::OLE_PPS_SIZE;
139 51
        $iPPScnt = (floor($iCnt / $iBdCnt) + (($iCnt % $iBdCnt) ? 1 : 0));
140
141 51
        return [$iSBDcnt, $iBBcnt, $iPPScnt];
142
    }
143
144
    /**
145
     * Helper function for caculating a magic value for block sizes.
146
     *
147
     * @param int $i2 The argument
148
     *
149
     * @see save()
150
     *
151
     * @return float
152
     */
153
    private static function adjust2($i2)
154
    {
155
        $iWk = log($i2) / log(2);
156
157
        return ($iWk > floor($iWk)) ? floor($iWk) + 1 : $iWk;
158
    }
159
160
    /**
161
     * Save OLE header.
162
     *
163
     * @param int $iSBDcnt
164
     * @param int $iBBcnt
165
     * @param int $iPPScnt
166
     */
167 51
    public function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
168
    {
169 51
        $FILE = $this->fileHandle;
170
171
        // Calculate Basic Setting
172 51
        $iBlCnt = $this->bigBlockSize / OLE::OLE_LONG_INT_SIZE;
173 51
        $i1stBdL = ($this->bigBlockSize - 0x4C) / OLE::OLE_LONG_INT_SIZE;
174
175 51
        $iBdExL = 0;
176 51
        $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
177 51
        $iAllW = $iAll;
178 51
        $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
179 51
        $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW + $iBdCntW) % $iBlCnt) ? 1 : 0);
180
181
        // Calculate BD count
182 51
        if ($iBdCnt > $i1stBdL) {
183
            while (1) {
184
                ++$iBdExL;
185
                ++$iAllW;
186
                $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
187
                $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW + $iBdCntW) % $iBlCnt) ? 1 : 0);
188
                if ($iBdCnt <= ($iBdExL * $iBlCnt + $i1stBdL)) {
189
                    break;
190
                }
191
            }
192
        }
193
194
        // Save Header
195 51
        fwrite(
196
            $FILE,
197
            "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
198
            . "\x00\x00\x00\x00"
199
            . "\x00\x00\x00\x00"
200
            . "\x00\x00\x00\x00"
201
            . "\x00\x00\x00\x00"
202 51
            . pack('v', 0x3b)
203 51
            . pack('v', 0x03)
204 51
            . pack('v', -2)
205 51
            . pack('v', 9)
206 51
            . pack('v', 6)
207 51
            . pack('v', 0)
208 51
            . "\x00\x00\x00\x00"
209 51
            . "\x00\x00\x00\x00"
210 51
            . pack('V', $iBdCnt)
211 51
            . pack('V', $iBBcnt + $iSBDcnt) //ROOT START
212 51
            . pack('V', 0)
213 51
            . pack('V', 0x1000)
214 51
            . pack('V', $iSBDcnt ? 0 : -2) //Small Block Depot
215 51
            . pack('V', $iSBDcnt)
216
        );
217
        // Extra BDList Start, Count
218 51
        if ($iBdCnt < $i1stBdL) {
219 51
            fwrite(
220
                $FILE,
221 51
                pack('V', -2) // Extra BDList Start
222 51
                . pack('V', 0)// Extra BDList Count
223
            );
224
        } else {
225
            fwrite($FILE, pack('V', $iAll + $iBdCnt) . pack('V', $iBdExL));
226
        }
227
228
        // BDList
229 51
        for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++$i) {
230 51
            fwrite($FILE, pack('V', $iAll + $i));
231
        }
232 51
        if ($i < $i1stBdL) {
233 51
            $jB = $i1stBdL - $i;
234 51
            for ($j = 0; $j < $jB; ++$j) {
235 51
                fwrite($FILE, (pack('V', -1)));
236
            }
237
        }
238 51
    }
239
240
    /**
241
     * Saving big data (PPS's with data bigger than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL).
242
     *
243
     * @param int $iStBlk
244
     * @param array &$raList Reference to array of PPS's
245
     */
246 51
    public function _saveBigData($iStBlk, &$raList)
247
    {
248 51
        $FILE = $this->fileHandle;
249
250
        // cycle through PPS's
251 51
        $iCount = count($raList);
252 51
        for ($i = 0; $i < $iCount; ++$i) {
253 51
            if ($raList[$i]->Type != OLE::OLE_PPS_TYPE_DIR) {
254 51
                $raList[$i]->Size = $raList[$i]->getDataLen();
255 51
                if (($raList[$i]->Size >= OLE::OLE_DATA_SIZE_SMALL) || (($raList[$i]->Type == OLE::OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data))) {
256 51
                    fwrite($FILE, $raList[$i]->_data);
257
258 51
                    if ($raList[$i]->Size % $this->bigBlockSize) {
259 48
                        fwrite($FILE, str_repeat("\x00", $this->bigBlockSize - ($raList[$i]->Size % $this->bigBlockSize)));
260
                    }
261
                    // Set For PPS
262 51
                    $raList[$i]->startBlock = $iStBlk;
263
                    $iStBlk +=
264 51
                            (floor($raList[$i]->Size / $this->bigBlockSize) +
265 51
                                (($raList[$i]->Size % $this->bigBlockSize) ? 1 : 0));
266
                }
267
            }
268
        }
269 51
    }
270
271
    /**
272
     * get small data (PPS's with data smaller than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL).
273
     *
274
     * @param array &$raList Reference to array of PPS's
275
     *
276
     * @return string
277
     */
278 51
    public function _makeSmallData(&$raList)
279
    {
280 51
        $sRes = '';
281 51
        $FILE = $this->fileHandle;
282 51
        $iSmBlk = 0;
283
284 51
        $iCount = count($raList);
285 51
        for ($i = 0; $i < $iCount; ++$i) {
286
            // Make SBD, small data string
287 51
            if ($raList[$i]->Type == OLE::OLE_PPS_TYPE_FILE) {
288 51
                if ($raList[$i]->Size <= 0) {
289
                    continue;
290
                }
291 51
                if ($raList[$i]->Size < OLE::OLE_DATA_SIZE_SMALL) {
292 51
                    $iSmbCnt = floor($raList[$i]->Size / $this->smallBlockSize)
293 51
                                  + (($raList[$i]->Size % $this->smallBlockSize) ? 1 : 0);
294
                    // Add to SBD
295 51
                    $jB = $iSmbCnt - 1;
296 51
                    for ($j = 0; $j < $jB; ++$j) {
297 51
                        fwrite($FILE, pack('V', $j + $iSmBlk + 1));
298
                    }
299 51
                    fwrite($FILE, pack('V', -2));
300
301
                    // Add to Data String(this will be written for RootEntry)
302 51
                    $sRes .= $raList[$i]->_data;
303 51
                    if ($raList[$i]->Size % $this->smallBlockSize) {
304 51
                        $sRes .= str_repeat("\x00", $this->smallBlockSize - ($raList[$i]->Size % $this->smallBlockSize));
305
                    }
306
                    // Set for PPS
307 51
                    $raList[$i]->startBlock = $iSmBlk;
308 51
                    $iSmBlk += $iSmbCnt;
309
                }
310
            }
311
        }
312 51
        $iSbCnt = floor($this->bigBlockSize / OLE::OLE_LONG_INT_SIZE);
313 51
        if ($iSmBlk % $iSbCnt) {
314 51
            $iB = $iSbCnt - ($iSmBlk % $iSbCnt);
315 51
            for ($i = 0; $i < $iB; ++$i) {
316 51
                fwrite($FILE, pack('V', -1));
317
            }
318
        }
319
320 51
        return $sRes;
321
    }
322
323
    /**
324
     * Saves all the PPS's WKs.
325
     *
326
     * @param array $raList Reference to an array with all PPS's
327
     */
328 51
    public function _savePps(&$raList)
329
    {
330
        // Save each PPS WK
331 51
        $iC = count($raList);
332 51
        for ($i = 0; $i < $iC; ++$i) {
333 51
            fwrite($this->fileHandle, $raList[$i]->_getPpsWk());
334
        }
335
        // Adjust for Block
336 51
        $iCnt = count($raList);
337 51
        $iBCnt = $this->bigBlockSize / OLE::OLE_PPS_SIZE;
338 51
        if ($iCnt % $iBCnt) {
339
            fwrite($this->fileHandle, str_repeat("\x00", ($iBCnt - ($iCnt % $iBCnt)) * OLE::OLE_PPS_SIZE));
340
        }
341 51
    }
342
343
    /**
344
     * Saving Big Block Depot.
345
     *
346
     * @param int $iSbdSize
347
     * @param int $iBsize
348
     * @param int $iPpsCnt
349
     */
350 51
    public function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
351
    {
352 51
        $FILE = $this->fileHandle;
353
        // Calculate Basic Setting
354 51
        $iBbCnt = $this->bigBlockSize / OLE::OLE_LONG_INT_SIZE;
355 51
        $i1stBdL = ($this->bigBlockSize - 0x4C) / OLE::OLE_LONG_INT_SIZE;
356
357 51
        $iBdExL = 0;
358 51
        $iAll = $iBsize + $iPpsCnt + $iSbdSize;
359 51
        $iAllW = $iAll;
360 51
        $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
361 51
        $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW + $iBdCntW) % $iBbCnt) ? 1 : 0);
362
        // Calculate BD count
363 51
        if ($iBdCnt > $i1stBdL) {
364
            while (1) {
365
                ++$iBdExL;
366
                ++$iAllW;
367
                $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
368
                $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW + $iBdCntW) % $iBbCnt) ? 1 : 0);
369
                if ($iBdCnt <= ($iBdExL * $iBbCnt + $i1stBdL)) {
370
                    break;
371
                }
372
            }
373
        }
374
375
        // Making BD
376
        // Set for SBD
377 51
        if ($iSbdSize > 0) {
378 51
            for ($i = 0; $i < ($iSbdSize - 1); ++$i) {
379
                fwrite($FILE, pack('V', $i + 1));
380
            }
381 51
            fwrite($FILE, pack('V', -2));
382
        }
383
        // Set for B
384 51
        for ($i = 0; $i < ($iBsize - 1); ++$i) {
385 51
            fwrite($FILE, pack('V', $i + $iSbdSize + 1));
386
        }
387 51
        fwrite($FILE, pack('V', -2));
388
389
        // Set for PPS
390 51
        for ($i = 0; $i < ($iPpsCnt - 1); ++$i) {
391
            fwrite($FILE, pack('V', $i + $iSbdSize + $iBsize + 1));
392
        }
393 51
        fwrite($FILE, pack('V', -2));
394
        // Set for BBD itself ( 0xFFFFFFFD : BBD)
395 51
        for ($i = 0; $i < $iBdCnt; ++$i) {
396 51
            fwrite($FILE, pack('V', 0xFFFFFFFD));
397
        }
398
        // Set for ExtraBDList
399 51
        for ($i = 0; $i < $iBdExL; ++$i) {
400
            fwrite($FILE, pack('V', 0xFFFFFFFC));
401
        }
402
        // Adjust for Block
403 51
        if (($iAllW + $iBdCnt) % $iBbCnt) {
404 51
            $iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt));
405 51
            for ($i = 0; $i < $iBlock; ++$i) {
406 51
                fwrite($FILE, pack('V', -1));
407
            }
408
        }
409
        // Extra BDList
410 51
        if ($iBdCnt > $i1stBdL) {
411
            $iN = 0;
412
            $iNb = 0;
413
            for ($i = $i1stBdL; $i < $iBdCnt; $i++, ++$iN) {
414
                if ($iN >= ($iBbCnt - 1)) {
415
                    $iN = 0;
416
                    ++$iNb;
417
                    fwrite($FILE, pack('V', $iAll + $iBdCnt + $iNb));
418
                }
419
                fwrite($FILE, pack('V', $iBsize + $iSbdSize + $iPpsCnt + $i));
420
            }
421
            if (($iBdCnt - $i1stBdL) % ($iBbCnt - 1)) {
422
                $iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1));
423
                for ($i = 0; $i < $iB; ++$i) {
424
                    fwrite($FILE, pack('V', -1));
425
                }
426
            }
427
            fwrite($FILE, pack('V', -2));
428
        }
429 51
    }
430
}
431