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