Completed
Push — develop ( 29208e...50a0ec )
by Adrien
05:34
created

Escher::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
4
5
use PhpOffice\PhpSpreadsheet\Cell;
6
use PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer;
7
use PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer;
8
use PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer\SpContainer;
9
use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer;
10
use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer;
11
use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE;
12
use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE\Blip;
13
14
class Escher
15
{
16
    /**
17
     * The object we are writing.
18
     */
19
    private $object;
20
21
    /**
22
     * The written binary data.
23
     */
24
    private $data;
25
26
    /**
27
     * Shape offsets. Positions in binary stream where a new shape record begins.
28
     *
29
     * @var array
30
     */
31
    private $spOffsets;
32
33
    /**
34
     * Shape types.
35
     *
36
     * @var array
37
     */
38
    private $spTypes;
39
40
    /**
41
     * Constructor.
42
     *
43
     * @param mixed
44
     * @param mixed $object
45
     */
46
    public function __construct($object)
47
    {
48
        $this->object = $object;
49
    }
50
51
    /**
52
     * Process the object to be written.
53
     *
54
     * @return string
55
     */
56
    public function close()
57
    {
58
        // initialize
59
        $this->data = '';
60
61
        switch (get_class($this->object)) {
62
            case \PhpOffice\PhpSpreadsheet\Shared\Escher::class:
63
                if ($dggContainer = $this->object->getDggContainer()) {
64
                    $writer = new self($dggContainer);
65
                    $this->data = $writer->close();
66
                } elseif ($dgContainer = $this->object->getDgContainer()) {
67
                    $writer = new self($dgContainer);
68
                    $this->data = $writer->close();
69
                    $this->spOffsets = $writer->getSpOffsets();
70
                    $this->spTypes = $writer->getSpTypes();
71
                }
72
                break;
73
            case DggContainer::class:
74
                // this is a container record
75
76
                // initialize
77
                $innerData = '';
78
79
                // write the dgg
80
                $recVer = 0x0;
81
                $recInstance = 0x0000;
82
                $recType = 0xF006;
83
84
                $recVerInstance = $recVer;
85
                $recVerInstance |= $recInstance << 4;
86
87
                // dgg data
88
                $dggData =
89
                    pack(
90
                        'VVVV',
91
                        $this->object->getSpIdMax(), // maximum shape identifier increased by one
92
                        $this->object->getCDgSaved() + 1, // number of file identifier clusters increased by one
93
                        $this->object->getCSpSaved(),
94
                        $this->object->getCDgSaved() // count total number of drawings saved
95
                    );
96
97
                // add file identifier clusters (one per drawing)
98
                $IDCLs = $this->object->getIDCLs();
99
100
                foreach ($IDCLs as $dgId => $maxReducedSpId) {
101
                    $dggData .= pack('VV', $dgId, $maxReducedSpId + 1);
102
                }
103
104
                $header = pack('vvV', $recVerInstance, $recType, strlen($dggData));
105
                $innerData .= $header . $dggData;
106
107
                // write the bstoreContainer
108
                if ($bstoreContainer = $this->object->getBstoreContainer()) {
109
                    $writer = new self($bstoreContainer);
110
                    $innerData .= $writer->close();
111
                }
112
113
                // write the record
114
                $recVer = 0xF;
115
                $recInstance = 0x0000;
116
                $recType = 0xF000;
117
                $length = strlen($innerData);
118
119
                $recVerInstance = $recVer;
120
                $recVerInstance |= $recInstance << 4;
121
122
                $header = pack('vvV', $recVerInstance, $recType, $length);
123
124
                $this->data = $header . $innerData;
125
                break;
126
            case BstoreContainer::class:
127
                // this is a container record
128
129
                // initialize
130
                $innerData = '';
131
132
                // treat the inner data
133
                if ($BSECollection = $this->object->getBSECollection()) {
134
                    foreach ($BSECollection as $BSE) {
135
                        $writer = new self($BSE);
136
                        $innerData .= $writer->close();
137
                    }
138
                }
139
140
                // write the record
141
                $recVer = 0xF;
142
                $recInstance = count($this->object->getBSECollection());
143
                $recType = 0xF001;
144
                $length = strlen($innerData);
145
146
                $recVerInstance = $recVer;
147
                $recVerInstance |= $recInstance << 4;
148
149
                $header = pack('vvV', $recVerInstance, $recType, $length);
150
151
                $this->data = $header . $innerData;
152
                break;
153
            case BSE::class:
154
                // this is a semi-container record
155
156
                // initialize
157
                $innerData = '';
158
159
                // here we treat the inner data
160
                if ($blip = $this->object->getBlip()) {
161
                    $writer = new self($blip);
162
                    $innerData .= $writer->close();
163
                }
164
165
                // initialize
166
                $data = '';
167
168
                $btWin32 = $this->object->getBlipType();
169
                $btMacOS = $this->object->getBlipType();
170
                $data .= pack('CC', $btWin32, $btMacOS);
171
172
                $rgbUid = pack('VVVV', 0, 0, 0, 0); // todo
173
                $data .= $rgbUid;
174
175
                $tag = 0;
176
                $size = strlen($innerData);
177
                $cRef = 1;
178
                $foDelay = 0; //todo
179
                $unused1 = 0x0;
180
                $cbName = 0x0;
181
                $unused2 = 0x0;
182
                $unused3 = 0x0;
183
                $data .= pack('vVVVCCCC', $tag, $size, $cRef, $foDelay, $unused1, $cbName, $unused2, $unused3);
184
185
                $data .= $innerData;
186
187
                // write the record
188
                $recVer = 0x2;
189
                $recInstance = $this->object->getBlipType();
190
                $recType = 0xF007;
191
                $length = strlen($data);
192
193
                $recVerInstance = $recVer;
194
                $recVerInstance |= $recInstance << 4;
195
196
                $header = pack('vvV', $recVerInstance, $recType, $length);
197
198
                $this->data = $header;
199
200
                $this->data .= $data;
201
                break;
202
            case Blip::class:
203
                // this is an atom record
204
205
                // write the record
206
                switch ($this->object->getParent()->getBlipType()) {
207 View Code Duplication
                    case BSE::BLIPTYPE_JPEG:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
                        // initialize
209
                        $innerData = '';
210
211
                        $rgbUid1 = pack('VVVV', 0, 0, 0, 0); // todo
212
                        $innerData .= $rgbUid1;
213
214
                        $tag = 0xFF; // todo
215
                        $innerData .= pack('C', $tag);
216
217
                        $innerData .= $this->object->getData();
218
219
                        $recVer = 0x0;
220
                        $recInstance = 0x46A;
221
                        $recType = 0xF01D;
222
                        $length = strlen($innerData);
223
224
                        $recVerInstance = $recVer;
225
                        $recVerInstance |= $recInstance << 4;
226
227
                        $header = pack('vvV', $recVerInstance, $recType, $length);
228
229
                        $this->data = $header;
230
231
                        $this->data .= $innerData;
232
                        break;
233 View Code Duplication
                    case BSE::BLIPTYPE_PNG:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
                        // initialize
235
                        $innerData = '';
236
237
                        $rgbUid1 = pack('VVVV', 0, 0, 0, 0); // todo
238
                        $innerData .= $rgbUid1;
239
240
                        $tag = 0xFF; // todo
241
                        $innerData .= pack('C', $tag);
242
243
                        $innerData .= $this->object->getData();
244
245
                        $recVer = 0x0;
246
                        $recInstance = 0x6E0;
247
                        $recType = 0xF01E;
248
                        $length = strlen($innerData);
249
250
                        $recVerInstance = $recVer;
251
                        $recVerInstance |= $recInstance << 4;
252
253
                        $header = pack('vvV', $recVerInstance, $recType, $length);
254
255
                        $this->data = $header;
256
257
                        $this->data .= $innerData;
258
                        break;
259
                }
260
                break;
261
            case DgContainer::class:
262
                // this is a container record
263
264
                // initialize
265
                $innerData = '';
266
267
                // write the dg
268
                $recVer = 0x0;
269
                $recInstance = $this->object->getDgId();
270
                $recType = 0xF008;
271
                $length = 8;
272
273
                $recVerInstance = $recVer;
274
                $recVerInstance |= $recInstance << 4;
275
276
                $header = pack('vvV', $recVerInstance, $recType, $length);
277
278
                // number of shapes in this drawing (including group shape)
279
                $countShapes = count($this->object->getSpgrContainer()->getChildren());
280
                $innerData .= $header . pack('VV', $countShapes, $this->object->getLastSpId());
281
282
                // write the spgrContainer
283
                if ($spgrContainer = $this->object->getSpgrContainer()) {
284
                    $writer = new self($spgrContainer);
285
                    $innerData .= $writer->close();
286
287
                    // get the shape offsets relative to the spgrContainer record
288
                    $spOffsets = $writer->getSpOffsets();
289
                    $spTypes = $writer->getSpTypes();
290
291
                    // save the shape offsets relative to dgContainer
292
                    foreach ($spOffsets as &$spOffset) {
293
                        $spOffset += 24; // add length of dgContainer header data (8 bytes) plus dg data (16 bytes)
294
                    }
295
296
                    $this->spOffsets = $spOffsets;
297
                    $this->spTypes = $spTypes;
298
                }
299
300
                // write the record
301
                $recVer = 0xF;
302
                $recInstance = 0x0000;
303
                $recType = 0xF002;
304
                $length = strlen($innerData);
305
306
                $recVerInstance = $recVer;
307
                $recVerInstance |= $recInstance << 4;
308
309
                $header = pack('vvV', $recVerInstance, $recType, $length);
310
311
                $this->data = $header . $innerData;
312
                break;
313
            case SpgrContainer::class:
314
                // this is a container record
315
316
                // initialize
317
                $innerData = '';
318
319
                // initialize spape offsets
320
                $totalSize = 8;
321
                $spOffsets = [];
322
                $spTypes = [];
323
324
                // treat the inner data
325
                foreach ($this->object->getChildren() as $spContainer) {
326
                    $writer = new self($spContainer);
327
                    $spData = $writer->close();
328
                    $innerData .= $spData;
329
330
                    // save the shape offsets (where new shape records begin)
331
                    $totalSize += strlen($spData);
332
                    $spOffsets[] = $totalSize;
333
334
                    $spTypes = array_merge($spTypes, $writer->getSpTypes());
335
                }
336
337
                // write the record
338
                $recVer = 0xF;
339
                $recInstance = 0x0000;
340
                $recType = 0xF003;
341
                $length = strlen($innerData);
342
343
                $recVerInstance = $recVer;
344
                $recVerInstance |= $recInstance << 4;
345
346
                $header = pack('vvV', $recVerInstance, $recType, $length);
347
348
                $this->data = $header . $innerData;
349
                $this->spOffsets = $spOffsets;
350
                $this->spTypes = $spTypes;
351
                break;
352
            case SpContainer::class:
353
                // initialize
354
                $data = '';
355
356
                // build the data
357
358
                // write group shape record, if necessary?
359
                if ($this->object->getSpgr()) {
360
                    $recVer = 0x1;
361
                    $recInstance = 0x0000;
362
                    $recType = 0xF009;
363
                    $length = 0x00000010;
364
365
                    $recVerInstance = $recVer;
366
                    $recVerInstance |= $recInstance << 4;
367
368
                    $header = pack('vvV', $recVerInstance, $recType, $length);
369
370
                    $data .= $header . pack('VVVV', 0, 0, 0, 0);
371
                }
372
                $this->spTypes[] = ($this->object->getSpType());
373
374
                // write the shape record
375
                $recVer = 0x2;
376
                $recInstance = $this->object->getSpType(); // shape type
377
                $recType = 0xF00A;
378
                $length = 0x00000008;
379
380
                $recVerInstance = $recVer;
381
                $recVerInstance |= $recInstance << 4;
382
383
                $header = pack('vvV', $recVerInstance, $recType, $length);
384
385
                $data .= $header . pack('VV', $this->object->getSpId(), $this->object->getSpgr() ? 0x0005 : 0x0A00);
386
387
                // the options
388
                if ($this->object->getOPTCollection()) {
389
                    $optData = '';
390
391
                    $recVer = 0x3;
392
                    $recInstance = count($this->object->getOPTCollection());
393
                    $recType = 0xF00B;
394
                    foreach ($this->object->getOPTCollection() as $property => $value) {
395
                        $optData .= pack('vV', $property, $value);
396
                    }
397
                    $length = strlen($optData);
398
399
                    $recVerInstance = $recVer;
400
                    $recVerInstance |= $recInstance << 4;
401
402
                    $header = pack('vvV', $recVerInstance, $recType, $length);
403
                    $data .= $header . $optData;
404
                }
405
406
                // the client anchor
407
                if ($this->object->getStartCoordinates()) {
408
                    $clientAnchorData = '';
0 ignored issues
show
Unused Code introduced by
$clientAnchorData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
409
410
                    $recVer = 0x0;
411
                    $recInstance = 0x0;
412
                    $recType = 0xF010;
413
414
                    // start coordinates
415
                    list($column, $row) = Cell::coordinateFromString($this->object->getStartCoordinates());
416
                    $c1 = Cell::columnIndexFromString($column) - 1;
417
                    $r1 = $row - 1;
418
419
                    // start offsetX
420
                    $startOffsetX = $this->object->getStartOffsetX();
421
422
                    // start offsetY
423
                    $startOffsetY = $this->object->getStartOffsetY();
424
425
                    // end coordinates
426
                    list($column, $row) = Cell::coordinateFromString($this->object->getEndCoordinates());
427
                    $c2 = Cell::columnIndexFromString($column) - 1;
428
                    $r2 = $row - 1;
429
430
                    // end offsetX
431
                    $endOffsetX = $this->object->getEndOffsetX();
432
433
                    // end offsetY
434
                    $endOffsetY = $this->object->getEndOffsetY();
435
436
                    $clientAnchorData = pack('vvvvvvvvv', $this->object->getSpFlag(), $c1, $startOffsetX, $r1, $startOffsetY, $c2, $endOffsetX, $r2, $endOffsetY);
437
438
                    $length = strlen($clientAnchorData);
439
440
                    $recVerInstance = $recVer;
441
                    $recVerInstance |= $recInstance << 4;
442
443
                    $header = pack('vvV', $recVerInstance, $recType, $length);
444
                    $data .= $header . $clientAnchorData;
445
                }
446
447
                // the client data, just empty for now
448
                if (!$this->object->getSpgr()) {
449
                    $clientDataData = '';
450
451
                    $recVer = 0x0;
452
                    $recInstance = 0x0;
453
                    $recType = 0xF011;
454
455
                    $length = strlen($clientDataData);
456
457
                    $recVerInstance = $recVer;
458
                    $recVerInstance |= $recInstance << 4;
459
460
                    $header = pack('vvV', $recVerInstance, $recType, $length);
461
                    $data .= $header . $clientDataData;
462
                }
463
464
                // write the record
465
                $recVer = 0xF;
466
                $recInstance = 0x0000;
467
                $recType = 0xF004;
468
                $length = strlen($data);
469
470
                $recVerInstance = $recVer;
471
                $recVerInstance |= $recInstance << 4;
472
473
                $header = pack('vvV', $recVerInstance, $recType, $length);
474
475
                $this->data = $header . $data;
476
                break;
477
        }
478
479
        return $this->data;
480
    }
481
482
    /**
483
     * Gets the shape offsets.
484
     *
485
     * @return array
486
     */
487
    public function getSpOffsets()
488
    {
489
        return $this->spOffsets;
490
    }
491
492
    /**
493
     * Gets the shape types.
494
     *
495
     * @return array
496
     */
497
    public function getSpTypes()
498
    {
499
        return $this->spTypes;
500
    }
501
}
502