Test Failed
Push — main ( c8394f...8477f1 )
by Rafael
66:21
created

Root::_saveBbd()   F

Complexity

Conditions 21
Paths 17920

Size

Total Lines 78
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 48
nc 17920
nop 3
dl 0
loc 78
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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