28 define(
'IDENTIFIER_OLE', pack(
'CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
68 public function read($sFileName)
71 if(!is_readable($sFileName)) {
72 throw new Exception(
"Could not open " . $sFileName .
" for reading! File does not exist, or it is not readable.");
76 $this->data = file_get_contents($sFileName);
80 throw new Exception(
'The filename ' . $sFileName .
' is not recognised as an OLE file');
84 $this->numBigBlockDepotBlocks = $this->
_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
87 $this->rootStartBlock = $this->
_GetInt4d($this->data, self::ROOT_START_BLOCK_POS);
90 $this->sbdStartBlock = $this->
_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
93 $this->extensionBlock = $this->
_GetInt4d($this->data, self::EXTENSION_BLOCK_POS);
96 $this->numExtensionBlocks = $this->
_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
98 $bigBlockDepotBlocks = array();
101 $bbdBlocks = $this->numBigBlockDepotBlocks;
103 if ($this->numExtensionBlocks != 0) {
107 for ($i = 0; $i < $bbdBlocks; ++$i) {
108 $bigBlockDepotBlocks[$i] = $this->
_GetInt4d($this->data, $pos);
112 for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
113 $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
114 $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
116 for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
117 $bigBlockDepotBlocks[$i] = $this->
_GetInt4d($this->data, $pos);
121 $bbdBlocks += $blocksToRead;
122 if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
123 $this->extensionBlock = $this->
_GetInt4d($this->data, $pos);
129 $this->bigBlockChain = array();
131 for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
132 $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
134 for ($j = 0 ; $j < self::BIG_BLOCK_SIZE / 4; ++$j) {
135 $this->bigBlockChain[$index] = $this->
_GetInt4d($this->data, $pos);
143 $sbdBlock = $this->sbdStartBlock;
144 $this->smallBlockChain = array();
146 while ($sbdBlock != -2) {
147 $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
149 for ($j = 0; $j < self::BIG_BLOCK_SIZE / 4; ++$j) {
150 $this->smallBlockChain[$index] = $this->
_GetInt4d($this->data, $pos);
155 $sbdBlock = $this->bigBlockChain[$sbdBlock];
158 $block = $this->rootStartBlock;
175 if ($this->props[$this->wrkbook][
'size'] < self::SMALL_BLOCK_THRESHOLD){
176 $rootdata = $this->
_readData($this->props[$this->rootentry][
'startBlock']);
179 $block = $this->props[$this->wrkbook][
'startBlock'];
182 while ($block != -2) {
184 $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
186 $block = $this->smallBlockChain[$block];
194 if ($this->props[$this->wrkbook][
'size'] % self::BIG_BLOCK_SIZE != 0) {
198 if ($numBlocks == 0)
return '';
202 $block = $this->props[$this->wrkbook][
'startBlock'];
206 while ($block != -2) {
207 $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
208 $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
209 $block = $this->bigBlockChain[$block];
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];
244 while ($offset < strlen($this->entry)) {
246 $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
249 $nameSize = ord(
$d[self::SIZE_OF_NAME_POS]) | (ord(
$d[self::SIZE_OF_NAME_POS+1]) << 8);
252 $type = ord(
$d[self::TYPE_POS]);
256 $startBlock = $this->
_GetInt4d(
$d, self::START_BLOCK_POS);
261 for ($i = 0; $i < $nameSize ; ++$i) {
267 $this->props[] = array (
270 'startBlock' => $startBlock,
274 if ((
$name ==
'Workbook') || (
$name ==
'Book') || (
$name ==
'WORKBOOK')) {
275 $this->wrkbook = count($this->props) - 1;
280 $this->rootentry = count($this->props) - 1;
298 $_or_24 = ord(
$data[$pos+3]);
299 if ($_or_24>=128) $_ord_24 = -abs((256-$_or_24) << 24);
300 else $_ord_24 = ($_or_24&127) << 24;
302 return ord(
$data[$pos]) | (ord(
$data[$pos+1]) << 8) | (ord(
$data[$pos+2]) << 16) | $_ord_24;