ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
Escher.php
Go to the documentation of this file.
1 <?php
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 
61  private $_data;
62 
68  private $_dataSize;
69 
75  private $_pos;
76 
82  private $_object;
83 
89  public function __construct($object)
90  {
91  $this->_object = $object;
92  }
93 
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 
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 
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 
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 
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
204  $this->_object->setBstoreContainer($bstoreContainer);
205  $reader = new PHPExcel_Reader_Excel5_Escher($bstoreContainer);
206  $reader->load($recordData);
207  }
208 
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
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
272  $reader->load($blipData);
273  }
274 
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 
311  $blip->setData($data);
312 
313  $this->_object->setBlip($blip);
314  }
315 
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 
352  $blip->setData($data);
353 
354  $this->_object->setBlip($blip);
355  }
356 
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 
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 
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 
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 
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 
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
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 
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
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 
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 
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 
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 
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 
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 
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 }