File Source for Escher.php

PHPExcel_Reader_Excel5

# Source for file Escher.php

Documentation is available at Escher.php

1. <?php
2. /**
3. * PHPExcel
4. *
5. * Copyright (c) 2006 - 2011 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 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25. * @version 1.7.6, 2011-02-27
26. */
28. /**
29. * PHPExcel_Reader_Excel5_Escher
30. *
31. * @category PHPExcel
32. * @package PHPExcel_Reader_Excel5
33. * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
34. */
35. class 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;
56. /**
57. * Escher stream data (binary)
58. *
59. * @var string
60. */
61. private $_data;
63. /**
64. * Size in bytes of the Escher stream data
65. *
66. * @var int
67. */
68. private $_dataSize;
70. /**
71. * Current position of stream pointer in Escher stream data
72. *
73. * @var int
74. */
75. private $_pos;
77. /**
78. * The object to be returned by the reader. Modified during load.
79. *
80. * @var mixed
81. */
82. private $_object;
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. }
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;
103. // total byte size of Excel data (workbook global substream + sheet substreams)
104. $this->_dataSize = strlen($this->_data);
106. $this->_pos = 0;
108. // Parse Escher stream
109. while ($this->_pos < $this->_dataSize) {
111. // offset: 2; size: 2: Record Type
112. $fbt = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos + 2);
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. }
137. return $this->_object;
138. }
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);
148. // offset: 2; size: 2: Record Type
149. $fbt = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos + 2);
151. // bit: 0-3; mask: 0x000F; recVer
152. $recVer = (0x000F & $verInstance) >> 0;
154. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
155. $recordData = substr($this->_data, $this->_pos + 8, $length);
157. // move stream pointer to next record
158. $this->_pos += 8 + $length;
159. }
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);
169. // move stream pointer to next record
170. $this->_pos += 8 + $length;
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. }
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);
187. // move stream pointer to next record
188. $this->_pos += 8 + $length;
189. }
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);
199. // move stream pointer to next record
200. $this->_pos += 8 + $length;
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. }
209. /**
210. * Read BSE record
211. */
212. private function _readBSE()
213. {
214. // offset: 0; size: 2; recVer and recInstance
216. // bit: 4-15; mask: 0xFFF0; recInstance
217. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
219. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
220. $recordData = substr($this->_data, $this->_pos + 8, $length);
222. // move stream pointer to next record
223. $this->_pos += 8 + $length;
225. // add BSE to BstoreContainer
226. $BSE = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE();
227. $this->_object->addBSE($BSE);
229. $BSE->setBLIPType($recInstance);
231. // offset: 0; size: 1; btWin32 (MSOBLIPTYPE)
232. $btWin32 = ord($recordData[0]);
234. // offset: 1; size: 1; btWin32 (MSOBLIPTYPE)
235. $btMacOS = ord($recordData[1]);
237. // offset: 2; size: 16; MD4 digest
238. $rgbUid = substr($recordData, 2, 16);
240. // offset: 18; size: 2; tag
241. $tag = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 18);
243. // offset: 20; size: 4; size of BLIP in bytes
244. $size = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 20);
246. // offset: 24; size: 4; number of references to this BLIP
247. $cRef = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 24);
249. // offset: 28; size: 4; MSOFO file offset
250. $foDelay = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 28);
252. // offset: 32; size: 1; unused1
253. $unused1 = ord($recordData{32});
255. // offset: 33; size: 1; size of nameData in bytes (including null terminator)
256. $cbName = ord($recordData{33});
258. // offset: 34; size: 1; unused2
259. $unused2 = ord($recordData{34});
261. // offset: 35; size: 1; unused3
262. $unused3 = ord($recordData{35});
264. // offset: 36; size: $cbName; nameData
265. $nameData = substr($recordData, 36, $cbName);
267. // offset: 36 + $cbName, size: var; the BLIP data
268. $blipData = substr($recordData, 36 + $cbName);
270. // record is a container, read contents
271. $reader = new PHPExcel_Reader_Excel5_Escher($BSE);
272. $reader->load($blipData);
273. }
275. /**
276. * Read BlipJPEG record. Holds raw JPEG image data
277. */
278. private function _readBlipJPEG()
279. {
280. // offset: 0; size: 2; recVer and recInstance
282. // bit: 4-15; mask: 0xFFF0; recInstance
283. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
285. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
286. $recordData = substr($this->_data, $this->_pos + 8, $length);
288. // move stream pointer to next record
289. $this->_pos += 8 + $length;
291. $pos = 0;
293. // offset: 0; size: 16; rgbUid1 (MD4 digest of)
294. $rgbUid1 = substr($recordData, 0, 16);
295. $pos += 16;
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. }
303. // offset: var; size: 1; tag
304. $tag = ord($recordData{$pos});
305. $pos += 1;
307. // offset: var; size: var; the raw image data
308. $data = substr($recordData, $pos);
310. $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
311. $blip->setData($data);
313. $this->_object->setBlip($blip);
314. }
316. /**
317. * Read BlipPNG record. Holds raw PNG image data
318. */
319. private function _readBlipPNG()
320. {
321. // offset: 0; size: 2; recVer and recInstance
323. // bit: 4-15; mask: 0xFFF0; recInstance
324. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
326. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
327. $recordData = substr($this->_data, $this->_pos + 8, $length);
329. // move stream pointer to next record
330. $this->_pos += 8 + $length;
332. $pos = 0;
334. // offset: 0; size: 16; rgbUid1 (MD4 digest of)
335. $rgbUid1 = substr($recordData, 0, 16);
336. $pos += 16;
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. }
344. // offset: var; size: 1; tag
345. $tag = ord($recordData{$pos});
346. $pos += 1;
348. // offset: var; size: var; the raw image data
349. $data = substr($recordData, $pos);
351. $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
352. $blip->setData($data);
354. $this->_object->setBlip($blip);
355. }
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
364. // bit: 4-15; mask: 0xFFF0; recInstance
365. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
367. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
368. $recordData = substr($this->_data, $this->_pos + 8, $length);
370. // move stream pointer to next record
371. $this->_pos += 8 + $length;
373. $this->_readOfficeArtRGFOPTE($recordData, $recInstance);
374. }
376. /**
377. * Read TertiaryOPT record
378. */
379. private function _readTertiaryOPT()
380. {
381. // offset: 0; size: 2; recVer and recInstance
383. // bit: 4-15; mask: 0xFFF0; recInstance
384. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
386. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
387. $recordData = substr($this->_data, $this->_pos + 8, $length);
389. // move stream pointer to next record
390. $this->_pos += 8 + $length;
391. }
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);
401. // move stream pointer to next record
402. $this->_pos += 8 + $length;
403. }
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);
413. // move stream pointer to next record
414. $this->_pos += 8 + $length;
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. }
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);
431. // move stream pointer to next record
432. $this->_pos += 8 + $length;
433. }
435. /**
436. * Read SpgrContainer record (Shape Group Container)
437. */
438. private function _readSpgrContainer()
439. {
440. // context is either context DgContainer or SpgrContainer
442. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
443. $recordData = substr($this->_data, $this->_pos + 8, $length);
445. // move stream pointer to next record
446. $this->_pos += 8 + $length;
448. // record is a container, read contents
449. $spgrContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();
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. }
459. $reader = new PHPExcel_Reader_Excel5_Escher($spgrContainer);
460. $escher = $reader->load($recordData);
461. }
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);
471. // add spContainer to spgrContainer
472. $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
473. $this->_object->addChild($spContainer);
475. // move stream pointer to next record
476. $this->_pos += 8 + $length;
478. // record is a container, read contents
479. $reader = new PHPExcel_Reader_Excel5_Escher($spContainer);
480. $escher = $reader->load($recordData);
481. }
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);
491. // move stream pointer to next record
492. $this->_pos += 8 + $length;
493. }
495. /**
496. * Read Sp record (Shape)
497. */
498. private function _readSp()
499. {
500. // offset: 0; size: 2; recVer and recInstance
502. // bit: 4-15; mask: 0xFFF0; recInstance
503. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
505. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
506. $recordData = substr($this->_data, $this->_pos + 8, $length);
508. // move stream pointer to next record
509. $this->_pos += 8 + $length;
510. }
512. /**
513. * Read ClientTextbox record
514. */
515. private function _readClientTextbox()
516. {
517. // offset: 0; size: 2; recVer and recInstance
519. // bit: 4-15; mask: 0xFFF0; recInstance
520. $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4;
522. $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4);
523. $recordData = substr($this->_data, $this->_pos + 8, $length);
525. // move stream pointer to next record
526. $this->_pos += 8 + $length;
527. }
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);
537. // move stream pointer to next record
538. $this->_pos += 8 + $length;
540. // offset: 2; size: 2; upper-left corner column index (0-based)
541. $c1 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 2);
543. // offset: 4; size: 2; upper-left corner horizontal offset in 1/1024 of column width
544. $startOffsetX = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 4);
546. // offset: 6; size: 2; upper-left corner row index (0-based)
547. $r1 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 6);
549. // offset: 8; size: 2; upper-left corner vertical offset in 1/256 of row height
550. $startOffsetY = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 8);
552. // offset: 10; size: 2; bottom-right corner column index (0-based)
553. $c2 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 10);
555. // offset: 12; size: 2; bottom-right corner horizontal offset in 1/1024 of column width
556. $endOffsetX = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 12);
558. // offset: 14; size: 2; bottom-right corner row index (0-based)
559. $r2 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 14);
561. // offset: 16; size: 2; bottom-right corner vertical offset in 1/256 of row height
562. $endOffsetY = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 16);
564. // set the start coordinates
565. $this->_object->setStartCoordinates( PHPExcel_Cell:: stringFromColumnIndex($c1) . ($r1 + 1));
567. // set the start offsetX
568. $this->_object->setStartOffsetX($startOffsetX);
570. // set the start offsetY
571. $this->_object->setStartOffsetY($startOffsetY);
573. // set the end coordinates
574. $this->_object->setEndCoordinates( PHPExcel_Cell:: stringFromColumnIndex($c2) . ($r2 + 1));
576. // set the end offsetX
577. $this->_object->setEndOffsetX($endOffsetX);
579. // set the end offsetY
580. $this->_object->setEndOffsetY($endOffsetY);
581. }
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);
591. // move stream pointer to next record
592. $this->_pos += 8 + $length;
593. }
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) {
603. $splicedComplexData = substr($data, 6 * $n);
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);
610. // offset: 0; size: 2; opid
611. $opid = PHPExcel_Reader_Excel5::_GetInt2d($fopte, 0);
613. // bit: 0-13; mask: 0x3FFF; opid.opid
614. $opidOpid = (0x3FFF & $opid) >> 0;
616. // bit: 14; mask 0x4000; 1 = value in op field is BLIP identifier
617. $opidFBid = (0x4000 & $opid) >> 14;
619. // bit: 15; mask 0x8000; 1 = this is a complex property, op field specifies size of complex data
620. $opidFComplex = (0x8000 & $opid) >> 15;
622. // offset: 2; size: 4; the value for this property
623. $op = PHPExcel_Reader_Excel5::_GetInt4d($fopte, 2);
625. if ($opidFComplex) {
626. $complexData = substr($splicedComplexData, 0, $op);
627. $splicedComplexData = substr($splicedComplexData, $op);
629. // we store string value with complex data
630. $value = $complexData;
631. } else {
632. // we store integer value
633. $value = $op;
634. }
636. $this->_object->setOPT($opidOpid, $value);
637. }
638. }
640. }

Documentation generated on Sun, 27 Feb 2011 16:30:35 -0800 by phpDocumentor 1.4.3