source: sourcecode/application/libraries/PHPExcel/Reader/Excel5/Escher.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 18.4 KB
Line 
1<?php
2/**
3 * PHPExcel
4 *
5 * Copyright (c) 2006 - 2014 PHPExcel
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 * @category   PHPExcel
22 * @package    PHPExcel_Reader_Excel5
23 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
25 * @version    1.8.0, 2014-03-02
26 */
27
28/**
29 * PHPExcel_Reader_Excel5_Escher
30 *
31 * @category   PHPExcel
32 * @package    PHPExcel_Reader_Excel5
33 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
34 */
35class PHPExcel_Reader_Excel5_Escher
36{
37        const DGGCONTAINER              = 0xF000;
38        const BSTORECONTAINER   = 0xF001;
39        const DGCONTAINER               = 0xF002;
40        const SPGRCONTAINER             = 0xF003;
41        const SPCONTAINER               = 0xF004;
42        const DGG                               = 0xF006;
43        const BSE                               = 0xF007;
44        const DG                                = 0xF008;
45        const SPGR                              = 0xF009;
46        const SP                                = 0xF00A;
47        const OPT                               = 0xF00B;
48        const CLIENTTEXTBOX             = 0xF00D;
49        const CLIENTANCHOR              = 0xF010;
50        const CLIENTDATA                = 0xF011;
51        const BLIPJPEG                  = 0xF01D;
52        const BLIPPNG                   = 0xF01E;
53        const SPLITMENUCOLORS   = 0xF11E;
54        const TERTIARYOPT               = 0xF122;
55
56        /**
57         * Escher stream data (binary)
58         *
59         * @var string
60         */
61        private $_data;
62
63        /**
64         * Size in bytes of the Escher stream data
65         *
66         * @var int
67         */
68        private $_dataSize;
69
70        /**
71         * Current position of stream pointer in Escher stream data
72         *
73         * @var int
74         */
75        private $_pos;
76
77        /**
78         * The object to be returned by the reader. Modified during load.
79         *
80         * @var mixed
81         */
82        private $_object;
83
84        /**
85         * Create a new PHPExcel_Reader_Excel5_Escher instance
86         *
87         * @param mixed $object
88         */
89        public function __construct($object)
90        {
91                $this->_object = $object;
92        }
93
94        /**
95         * Load Escher stream data. May be a partial Escher stream.
96         *
97         * @param string $data
98         */
99        public function load($data)
100        {
101                $this->_data = $data;
102
103                // total byte size of Excel data (workbook global substream + sheet substreams)
104                $this->_dataSize = strlen($this->_data);
105
106                $this->_pos = 0;
107
108                // Parse Escher stream
109                while ($this->_pos < $this->_dataSize) {
110
111                        // offset: 2; size: 2: Record Type
112                        $fbt = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos + 2);
113
114                        switch ($fbt) {
115                                case self::DGGCONTAINER:        $this->_readDggContainer();             break;
116                                case self::DGG:                         $this->_readDgg();                              break;
117                                case self::BSTORECONTAINER:     $this->_readBstoreContainer();  break;
118                                case self::BSE:                         $this->_readBSE();                              break;
119                                case self::BLIPJPEG:            $this->_readBlipJPEG();                 break;
120                                case self::BLIPPNG:                     $this->_readBlipPNG();                  break;
121                                case self::OPT:                         $this->_readOPT();                              break;
122                                case self::TERTIARYOPT:         $this->_readTertiaryOPT();              break;
123                                case self::SPLITMENUCOLORS:     $this->_readSplitMenuColors();  break;
124                                case self::DGCONTAINER:         $this->_readDgContainer();              break;
125                                case self::DG:                          $this->_readDg();                               break;
126                                case self::SPGRCONTAINER:       $this->_readSpgrContainer();    break;
127                                case self::SPCONTAINER:         $this->_readSpContainer();              break;
128                                case self::SPGR:                        $this->_readSpgr();                             break;
129                                case self::SP:                          $this->_readSp();                               break;
130                                case self::CLIENTTEXTBOX:       $this->_readClientTextbox();    break;
131                                case self::CLIENTANCHOR:        $this->_readClientAnchor();             break;
132                                case self::CLIENTDATA:          $this->_readClientData();               break;
133                                default:                                        $this->_readDefault();                  break;
134                        }
135                }
136
137                return $this->_object;
138        }
139
140        /**
141         * Read a generic record
142         */
143        private function _readDefault()
144        {
145                // offset 0; size: 2; recVer and recInstance
146                $verInstance = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos);
147
148                // offset: 2; size: 2: Record Type
149                $fbt = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos + 2);
150
151                // bit: 0-3; mask: 0x000F; recVer
152                $recVer = (0x000F & $verInstance) >> 0;
153
154                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
155                $recordData = substr($this->_data, $this->_pos + 8, $length);
156
157                // move stream pointer to next record
158                $this->_pos += 8 + $length;
159        }
160
161        /**
162         * Read DggContainer record (Drawing Group Container)
163         */
164        private function _readDggContainer()
165        {
166                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
167                $recordData = substr($this->_data, $this->_pos + 8, $length);
168
169                // move stream pointer to next record
170                $this->_pos += 8 + $length;
171
172                // record is a container, read contents
173                $dggContainer = new PHPExcel_Shared_Escher_DggContainer();
174                $this->_object->setDggContainer($dggContainer);
175                $reader = new PHPExcel_Reader_Excel5_Escher($dggContainer);
176                $reader->load($recordData);
177        }
178
179        /**
180         * Read Dgg record (Drawing Group)
181         */
182        private function _readDgg()
183        {
184                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
185                $recordData = substr($this->_data, $this->_pos + 8, $length);
186
187                // move stream pointer to next record
188                $this->_pos += 8 + $length;
189        }
190
191        /**
192         * Read BstoreContainer record (Blip Store Container)
193         */
194        private function _readBstoreContainer()
195        {
196                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
197                $recordData = substr($this->_data, $this->_pos + 8, $length);
198
199                // move stream pointer to next record
200                $this->_pos += 8 + $length;
201
202                // record is a container, read contents
203                $bstoreContainer = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer();
204                $this->_object->setBstoreContainer($bstoreContainer);
205                $reader = new PHPExcel_Reader_Excel5_Escher($bstoreContainer);
206                $reader->load($recordData);
207        }
208
209        /**
210         * Read BSE record
211         */
212        private function _readBSE()
213        {
214                // offset: 0; size: 2; recVer and recInstance
215
216                // bit: 4-15; mask: 0xFFF0; recInstance
217                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
218
219                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
220                $recordData = substr($this->_data, $this->_pos + 8, $length);
221
222                // move stream pointer to next record
223                $this->_pos += 8 + $length;
224
225                // add BSE to BstoreContainer
226                $BSE = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE();
227                $this->_object->addBSE($BSE);
228
229                $BSE->setBLIPType($recInstance);
230
231                // offset: 0; size: 1; btWin32 (MSOBLIPTYPE)
232                $btWin32 = ord($recordData[0]);
233
234                // offset: 1; size: 1; btWin32 (MSOBLIPTYPE)
235                $btMacOS = ord($recordData[1]);
236
237                // offset: 2; size: 16; MD4 digest
238                $rgbUid = substr($recordData, 2, 16);
239
240                // offset: 18; size: 2; tag
241                $tag = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 18);
242
243                // offset: 20; size: 4; size of BLIP in bytes
244                $size = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 20);
245
246                // offset: 24; size: 4; number of references to this BLIP
247                $cRef = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 24);
248
249                // offset: 28; size: 4; MSOFO file offset
250                $foDelay = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 28);
251
252                // offset: 32; size: 1; unused1
253                $unused1 = ord($recordData{32});
254
255                // offset: 33; size: 1; size of nameData in bytes (including null terminator)
256                $cbName = ord($recordData{33});
257
258                // offset: 34; size: 1; unused2
259                $unused2 = ord($recordData{34});
260
261                // offset: 35; size: 1; unused3
262                $unused3 = ord($recordData{35});
263
264                // offset: 36; size: $cbName; nameData
265                $nameData = substr($recordData, 36, $cbName);
266
267                // offset: 36 + $cbName, size: var; the BLIP data
268                $blipData = substr($recordData, 36 + $cbName);
269
270                // record is a container, read contents
271                $reader = new PHPExcel_Reader_Excel5_Escher($BSE);
272                $reader->load($blipData);
273        }
274
275        /**
276         * Read BlipJPEG record. Holds raw JPEG image data
277         */
278        private function _readBlipJPEG()
279        {
280                // offset: 0; size: 2; recVer and recInstance
281
282                // bit: 4-15; mask: 0xFFF0; recInstance
283                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
284
285                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
286                $recordData = substr($this->_data, $this->_pos + 8, $length);
287
288                // move stream pointer to next record
289                $this->_pos += 8 + $length;
290
291                $pos = 0;
292
293                // offset: 0; size: 16; rgbUid1 (MD4 digest of)
294                $rgbUid1 = substr($recordData, 0, 16);
295                $pos += 16;
296
297                // offset: 16; size: 16; rgbUid2 (MD4 digest), only if $recInstance = 0x46B or 0x6E3
298                if (in_array($recInstance, array(0x046B, 0x06E3))) {
299                        $rgbUid2 = substr($recordData, 16, 16);
300                        $pos += 16;
301                }
302
303                // offset: var; size: 1; tag
304                $tag = ord($recordData{$pos});
305                $pos += 1;
306
307                // offset: var; size: var; the raw image data
308                $data = substr($recordData, $pos);
309
310                $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
311                $blip->setData($data);
312
313                $this->_object->setBlip($blip);
314        }
315
316        /**
317         * Read BlipPNG record. Holds raw PNG image data
318         */
319        private function _readBlipPNG()
320        {
321                // offset: 0; size: 2; recVer and recInstance
322
323                // bit: 4-15; mask: 0xFFF0; recInstance
324                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
325
326                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
327                $recordData = substr($this->_data, $this->_pos + 8, $length);
328
329                // move stream pointer to next record
330                $this->_pos += 8 + $length;
331
332                $pos = 0;
333
334                // offset: 0; size: 16; rgbUid1 (MD4 digest of)
335                $rgbUid1 = substr($recordData, 0, 16);
336                $pos += 16;
337
338                // offset: 16; size: 16; rgbUid2 (MD4 digest), only if $recInstance = 0x46B or 0x6E3
339                if ($recInstance == 0x06E1) {
340                        $rgbUid2 = substr($recordData, 16, 16);
341                        $pos += 16;
342                }
343
344                // offset: var; size: 1; tag
345                $tag = ord($recordData{$pos});
346                $pos += 1;
347
348                // offset: var; size: var; the raw image data
349                $data = substr($recordData, $pos);
350
351                $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
352                $blip->setData($data);
353
354                $this->_object->setBlip($blip);
355        }
356
357        /**
358         * Read OPT record. This record may occur within DggContainer record or SpContainer
359         */
360        private function _readOPT()
361        {
362                // offset: 0; size: 2; recVer and recInstance
363
364                // bit: 4-15; mask: 0xFFF0; recInstance
365                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
366
367                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
368                $recordData = substr($this->_data, $this->_pos + 8, $length);
369
370                // move stream pointer to next record
371                $this->_pos += 8 + $length;
372
373                $this->_readOfficeArtRGFOPTE($recordData, $recInstance);
374        }
375
376        /**
377         * Read TertiaryOPT record
378         */
379        private function _readTertiaryOPT()
380        {
381                // offset: 0; size: 2; recVer and recInstance
382
383                // bit: 4-15; mask: 0xFFF0; recInstance
384                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
385
386                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
387                $recordData = substr($this->_data, $this->_pos + 8, $length);
388
389                // move stream pointer to next record
390                $this->_pos += 8 + $length;
391        }
392
393        /**
394         * Read SplitMenuColors record
395         */
396        private function _readSplitMenuColors()
397        {
398                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
399                $recordData = substr($this->_data, $this->_pos + 8, $length);
400
401                // move stream pointer to next record
402                $this->_pos += 8 + $length;
403        }
404
405        /**
406         * Read DgContainer record (Drawing Container)
407         */
408        private function _readDgContainer()
409        {
410                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
411                $recordData = substr($this->_data, $this->_pos + 8, $length);
412
413                // move stream pointer to next record
414                $this->_pos += 8 + $length;
415
416                // record is a container, read contents
417                $dgContainer = new PHPExcel_Shared_Escher_DgContainer();
418                $this->_object->setDgContainer($dgContainer);
419                $reader = new PHPExcel_Reader_Excel5_Escher($dgContainer);
420                $escher = $reader->load($recordData);
421        }
422
423        /**
424         * Read Dg record (Drawing)
425         */
426        private function _readDg()
427        {
428                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
429                $recordData = substr($this->_data, $this->_pos + 8, $length);
430
431                // move stream pointer to next record
432                $this->_pos += 8 + $length;
433        }
434
435        /**
436         * Read SpgrContainer record (Shape Group Container)
437         */
438        private function _readSpgrContainer()
439        {
440                // context is either context DgContainer or SpgrContainer
441
442                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
443                $recordData = substr($this->_data, $this->_pos + 8, $length);
444
445                // move stream pointer to next record
446                $this->_pos += 8 + $length;
447
448                // record is a container, read contents
449                $spgrContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();
450
451                if ($this->_object instanceof PHPExcel_Shared_Escher_DgContainer) {
452                        // DgContainer
453                        $this->_object->setSpgrContainer($spgrContainer);
454                } else {
455                        // SpgrContainer
456                        $this->_object->addChild($spgrContainer);
457                }
458
459                $reader = new PHPExcel_Reader_Excel5_Escher($spgrContainer);
460                $escher = $reader->load($recordData);
461        }
462
463        /**
464         * Read SpContainer record (Shape Container)
465         */
466        private function _readSpContainer()
467        {
468                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
469                $recordData = substr($this->_data, $this->_pos + 8, $length);
470
471                // add spContainer to spgrContainer
472                $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
473                $this->_object->addChild($spContainer);
474
475                // move stream pointer to next record
476                $this->_pos += 8 + $length;
477
478                // record is a container, read contents
479                $reader = new PHPExcel_Reader_Excel5_Escher($spContainer);
480                $escher = $reader->load($recordData);
481        }
482
483        /**
484         * Read Spgr record (Shape Group)
485         */
486        private function _readSpgr()
487        {
488                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
489                $recordData = substr($this->_data, $this->_pos + 8, $length);
490
491                // move stream pointer to next record
492                $this->_pos += 8 + $length;
493        }
494
495        /**
496         * Read Sp record (Shape)
497         */
498        private function _readSp()
499        {
500                // offset: 0; size: 2; recVer and recInstance
501
502                // bit: 4-15; mask: 0xFFF0; recInstance
503                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
504
505                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
506                $recordData = substr($this->_data, $this->_pos + 8, $length);
507
508                // move stream pointer to next record
509                $this->_pos += 8 + $length;
510        }
511
512        /**
513         * Read ClientTextbox record
514         */
515        private function _readClientTextbox()
516        {
517                // offset: 0; size: 2; recVer and recInstance
518
519                // bit: 4-15; mask: 0xFFF0; recInstance
520                $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
521
522                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
523                $recordData = substr($this->_data, $this->_pos + 8, $length);
524
525                // move stream pointer to next record
526                $this->_pos += 8 + $length;
527        }
528
529        /**
530         * Read ClientAnchor record. This record holds information about where the shape is anchored in worksheet
531         */
532        private function _readClientAnchor()
533        {
534                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
535                $recordData = substr($this->_data, $this->_pos + 8, $length);
536
537                // move stream pointer to next record
538                $this->_pos += 8 + $length;
539
540                // offset: 2; size: 2; upper-left corner column index (0-based)
541                $c1 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 2);
542
543                // offset: 4; size: 2; upper-left corner horizontal offset in 1/1024 of column width
544                $startOffsetX = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 4);
545
546                // offset: 6; size: 2; upper-left corner row index (0-based)
547                $r1 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 6);
548
549                // offset: 8; size: 2; upper-left corner vertical offset in 1/256 of row height
550                $startOffsetY = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 8);
551
552                // offset: 10; size: 2; bottom-right corner column index (0-based)
553                $c2 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 10);
554
555                // offset: 12; size: 2; bottom-right corner horizontal offset in 1/1024 of column width
556                $endOffsetX = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 12);
557
558                // offset: 14; size: 2; bottom-right corner row index (0-based)
559                $r2 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 14);
560
561                // offset: 16; size: 2; bottom-right corner vertical offset in 1/256 of row height
562                $endOffsetY = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 16);
563
564                // set the start coordinates
565                $this->_object->setStartCoordinates(PHPExcel_Cell::stringFromColumnIndex($c1) . ($r1 + 1));
566
567                // set the start offsetX
568                $this->_object->setStartOffsetX($startOffsetX);
569
570                // set the start offsetY
571                $this->_object->setStartOffsetY($startOffsetY);
572
573                // set the end coordinates
574                $this->_object->setEndCoordinates(PHPExcel_Cell::stringFromColumnIndex($c2) . ($r2 + 1));
575
576                // set the end offsetX
577                $this->_object->setEndOffsetX($endOffsetX);
578
579                // set the end offsetY
580                $this->_object->setEndOffsetY($endOffsetY);
581        }
582
583        /**
584         * Read ClientData record
585         */
586        private function _readClientData()
587        {
588                $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
589                $recordData = substr($this->_data, $this->_pos + 8, $length);
590
591                // move stream pointer to next record
592                $this->_pos += 8 + $length;
593        }
594
595        /**
596         * Read OfficeArtRGFOPTE table of property-value pairs
597         *
598         * @param string $data Binary data
599         * @param int $n Number of properties
600         */
601        private function _readOfficeArtRGFOPTE($data, $n) {
602
603                $splicedComplexData = substr($data, 6 * $n);
604
605                // loop through property-value pairs
606                for ($i = 0; $i < $n; ++$i) {
607                        // read 6 bytes at a time
608                        $fopte = substr($data, 6 * $i, 6);
609
610                        // offset: 0; size: 2; opid
611                        $opid = PHPExcel_Reader_Excel5::_GetInt2d($fopte, 0);
612
613                        // bit: 0-13; mask: 0x3FFF; opid.opid
614                        $opidOpid = (0x3FFF & $opid) >> 0;
615
616                        // bit: 14; mask 0x4000; 1 = value in op field is BLIP identifier
617                        $opidFBid = (0x4000 & $opid) >> 14;
618
619                        // bit: 15; mask 0x8000; 1 = this is a complex property, op field specifies size of complex data
620                        $opidFComplex = (0x8000 & $opid) >> 15;
621
622                        // offset: 2; size: 4; the value for this property
623                        $op = PHPExcel_Reader_Excel5::_GetInt4d($fopte, 2);
624
625                        if ($opidFComplex) {
626                                $complexData = substr($splicedComplexData, 0, $op);
627                                $splicedComplexData = substr($splicedComplexData, $op);
628
629                                // we store string value with complex data
630                                $value = $complexData;
631                        } else {
632                                // we store integer value
633                                $value = $op;
634                        }
635
636                        $this->_object->setOPT($opidOpid, $value);
637                }
638        }
639
640}
Note: See TracBrowser for help on using the repository browser.