PHPExcel_Shared
[ class tree: PHPExcel_Shared ] [ index: PHPExcel_Shared ] [ all elements ]

Source for file OLERead.php

Documentation is available at OLERead.php

  1. <?php
  2. /**
  3.  * PHPExcel
  4.  *
  5.  * Copyright (c) 2006 - 2009 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_Shared
  23.  * @copyright  Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version    1.6.5, 2009-01-05
  26.  */
  27.  
  28. define('IDENTIFIER_OLE', pack("CCCCCCCC", 0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1));
  29. define('IDENTIFIER_BIFF7', pack("CCCCCCCC", 0x09,0x08,0x08,0x00,0x00,0x05,0x05,0x00));
  30. define('IDENTIFIER_BIFF8', pack("CCCCCCCC", 0x09,0x08,0x10,0x00,0x00,0x06,0x05,0x00));
  31. // OpenOffice and Excel 97-2004 for Mac.
  32. define('IDENTIFIER_OOF', pack("CCCCCCCC", 0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff));
  33. define('IDENTIFIER_MAC04', pack("CCCCCCCC", 0xfd,0xff,0xff,0xff,0x23,0x00,0x00,0x00));
  34.  
  35.  
  36.     public $data = '';
  37.  
  38.     const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
  39.     const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
  40.     const ROOT_START_BLOCK_POS = 0x30;
  41.     const BIG_BLOCK_SIZE = 0x200;
  42.     const SMALL_BLOCK_SIZE = 0x40;
  43.     const EXTENSION_BLOCK_POS = 0x44;
  44.     const NUM_EXTENSION_BLOCK_POS = 0x48;
  45.     const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
  46.     const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
  47.     const SMALL_BLOCK_THRESHOLD = 0x1000;
  48.     // property storage offsets
  49.     const SIZE_OF_NAME_POS = 0x40;
  50.     const TYPE_POS = 0x42;
  51.     const START_BLOCK_POS = 0x74;
  52.     const SIZE_POS = 0x78;
  53.     const IDENTIFIER_OLE = IDENTIFIER_OLE;
  54.     const IDENTIFIER_BIFF7 = IDENTIFIER_BIFF7;
  55.     const IDENTIFIER_BIFF8 = IDENTIFIER_BIFF8;
  56.     // OpenOffice and Excel 97-2004 for Mac.
  57.     const IDENTIFIER_OOF = IDENTIFIER_OOF;
  58.     const IDENTIFIER_MAC04 = IDENTIFIER_MAC04;
  59.  
  60.     public function read($sFileName)
  61.     {
  62.         // check if file exist and is readable (Darko Miljanovic)
  63.         if(!is_readable($sFileName)) {
  64.             $this->error = 1;
  65.             return false;
  66.         }
  67.  
  68.         $this->data = file_get_contents($sFileName);
  69.         if (!$this->data) {
  70.             $this->error = 1;
  71.             return false;
  72.         }
  73.  
  74.         if (substr($this->data, 0, 8) != self::IDENTIFIER_OLE) {
  75.             $this->error = 1;
  76.             return false;
  77.         }
  78.  
  79.         // Check the start of the first block for a signature found in valid
  80.         // Excel files
  81.  
  82.         // Incorrectly throws out some valid Excel files. Removing for now.
  83.         /*$identifiers = array(
  84.             IDENTIFIER_BIFF7,
  85.             IDENTIFIER_BIFF8,
  86.             IDENTIFIER_OOF,
  87.             IDENTIFIER_MAC04
  88.         );
  89.  
  90.         if (!in_array(substr($this->data, 512, 8), $identifiers)) {
  91.             $this->error = 2;
  92.             return false;
  93.         }*/
  94.  
  95.         $this->numBigBlockDepotBlocks = $this->_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
  96.         $this->sbdStartBlock = $this->_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
  97.         $this->rootStartBlock = $this->_GetInt4d($this->data, self::ROOT_START_BLOCK_POS);
  98.         $this->extensionBlock = $this->_GetInt4d($this->data, self::EXTENSION_BLOCK_POS);
  99.         $this->numExtensionBlocks = $this->_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
  100.  
  101.         $bigBlockDepotBlocks = array();
  102.         $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
  103.  
  104.         $bbdBlocks = $this->numBigBlockDepotBlocks;
  105.  
  106.         if ($this->numExtensionBlocks != 0) {
  107.             $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
  108.         }
  109.  
  110.         for ($i = 0; $i < $bbdBlocks; ++$i) {
  111.               $bigBlockDepotBlocks[$i] = $this->_GetInt4d($this->data, $pos);
  112.               $pos += 4;
  113.         }
  114.  
  115.         for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
  116.             $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
  117.             $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
  118.  
  119.             for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
  120.                 $bigBlockDepotBlocks[$i] = $this->_GetInt4d($this->data, $pos);
  121.                 $pos += 4;
  122.             }
  123.  
  124.             $bbdBlocks += $blocksToRead;
  125.             if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
  126.                 $this->extensionBlock = $this->_GetInt4d($this->data, $pos);
  127.             }
  128.         }
  129.  
  130.         $pos = 0;
  131.         $index = 0;
  132.         $this->bigBlockChain = array();
  133.  
  134.         for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
  135.             $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
  136.  
  137.             for ($j = 0 ; $j < self::BIG_BLOCK_SIZE / 4; ++$j) {
  138.                 $this->bigBlockChain[$index] = $this->_GetInt4d($this->data, $pos);
  139.                 $pos += 4 ;
  140.                 ++$index;
  141.             }
  142.         }
  143.  
  144.         $pos = 0;
  145.         $index = 0;
  146.         $sbdBlock = $this->sbdStartBlock;
  147.         $this->smallBlockChain = array();
  148.  
  149.         while ($sbdBlock != -2) {
  150.             $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
  151.  
  152.             for ($j = 0; $j < self::BIG_BLOCK_SIZE / 4; ++$j) {
  153.                 $this->smallBlockChain[$index] = $this->_GetInt4d($this->data, $pos);
  154.                 $pos += 4;
  155.                 ++$index;
  156.             }
  157.  
  158.             $sbdBlock = $this->bigBlockChain[$sbdBlock];
  159.         }
  160.  
  161.         $block = $this->rootStartBlock;
  162.         $pos = 0;
  163.         $this->entry = $this->_readData($block);
  164.  
  165.         $this->_readPropertySets();
  166.  
  167.     }
  168.  
  169.     public function getWorkBook()
  170.     {
  171.         if ($this->props[$this->wrkbook]['size'] < self::SMALL_BLOCK_THRESHOLD){
  172.             $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']);
  173.  
  174.             $streamData = '';
  175.             $block = $this->props[$this->wrkbook]['startBlock'];
  176.  
  177.             $pos = 0;
  178.             while ($block != -2) {
  179.                   $pos = $block * self::SMALL_BLOCK_SIZE;
  180.                 $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
  181.  
  182.                 $block = $this->smallBlockChain[$block];
  183.             }
  184.  
  185.             return $streamData;
  186.  
  187.  
  188.         } else {
  189.             $numBlocks = $this->props[$this->wrkbook]['size'] / self::BIG_BLOCK_SIZE;
  190.             if ($this->props[$this->wrkbook]['size'] % self::BIG_BLOCK_SIZE != 0) {
  191.                 ++$numBlocks;
  192.             }
  193.  
  194.             if ($numBlocks == 0) return '';
  195.  
  196.  
  197.             $streamData = '';
  198.             $block = $this->props[$this->wrkbook]['startBlock'];
  199.  
  200.             $pos = 0;
  201.  
  202.             while ($block != -2) {
  203.                 $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
  204.                 $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
  205.                 $block = $this->bigBlockChain[$block];
  206.             }
  207.  
  208.             return $streamData;
  209.         }
  210.     }
  211.  
  212.     public function _GetInt4d($data, $pos)
  213.     {
  214.         // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
  215.         $_or_24 = ord($data[$pos+3]);
  216.         if ($_or_24>=128) $_ord_24 = -abs((256-$_or_24) << 24);
  217.         else $_ord_24 = ($_or_24&127) << 24;
  218.  
  219.         return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24;
  220.     }
  221.  
  222.      public function _readData($bl)
  223.      {
  224.         $block = $bl;
  225.         $pos = 0;
  226.         $data = '';
  227.  
  228.         while ($block != -2)  {
  229.             $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
  230.             $data = $data.substr($this->data, $pos, self::BIG_BLOCK_SIZE);
  231.             $block = $this->bigBlockChain[$block];
  232.         }
  233.         return $data;
  234.      }
  235.  
  236.     public function _readPropertySets()
  237.     {
  238.         $offset = 0;
  239.  
  240.         while ($offset < strlen($this->entry)) {
  241.             $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
  242.  
  243.             $nameSize = ord($d[self::SIZE_OF_NAME_POS]) | (ord($d[self::SIZE_OF_NAME_POS+1]) << 8);
  244.  
  245.             $type = ord($d[self::TYPE_POS]);
  246.  
  247.             $startBlock = $this->_GetInt4d($d, self::START_BLOCK_POS);
  248.             $size = $this->_GetInt4d($d, self::SIZE_POS);
  249.  
  250.             $name = '';
  251.             for ($i = 0; $i < $nameSize ; ++$i) {
  252.                 $name .= $d[$i];
  253.             }
  254.  
  255.             $name = str_replace("\x00", "", $name);
  256.  
  257.             $this->props[] = array (
  258.                 'name' => $name,
  259.                 'type' => $type,
  260.                 'startBlock' => $startBlock,
  261.                 'size' => $size);
  262.  
  263.             if (($name == "Workbook") || ($name == "Book") || ($name == "WORKBOOK")) {
  264.                 $this->wrkbook = count($this->props) - 1;
  265.             }
  266.  
  267.             if ($name == "Root Entry" || $name == "ROOT ENTRY") {
  268.                 $this->rootentry = count($this->props) - 1;
  269.             }
  270.  
  271.             $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
  272.         }
  273.  
  274.     }
  275. }

Documentation generated on Mon, 05 Jan 2009 20:38:11 +0100 by phpDocumentor 1.4.1