PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 2.2.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v2.2.0
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpexcel / Classes / PHPExcel / Shared / OLERead.php

OLERead.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 2.2.0, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Shared/OLERead.php

318 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PHPExcel
4 *
5 * Copyright (c) 2006 - 2014 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 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25 * @version ##VERSION##, ##DATE##
26 */
27
28 defined('IDENTIFIER_OLE') ||
29 define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
30
31 class PHPExcel_Shared_OLERead {
32 private $data = '';
33
34 // OLE identifier
35 const IDENTIFIER_OLE = IDENTIFIER_OLE;
36
37 // Size of a sector = 512 bytes
38 const BIG_BLOCK_SIZE = 0x200;
39
40 // Size of a short sector = 64 bytes
41 const SMALL_BLOCK_SIZE = 0x40;
42
43 // Size of a directory entry always = 128 bytes
44 const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
45
46 // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
47 const SMALL_BLOCK_THRESHOLD = 0x1000;
48
49 // header offsets
50 const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
51 const ROOT_START_BLOCK_POS = 0x30;
52 const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
53 const EXTENSION_BLOCK_POS = 0x44;
54 const NUM_EXTENSION_BLOCK_POS = 0x48;
55 const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
56
57 // property storage offsets (directory offsets)
58 const SIZE_OF_NAME_POS = 0x40;
59 const TYPE_POS = 0x42;
60 const START_BLOCK_POS = 0x74;
61 const SIZE_POS = 0x78;
62
63
64
65 public $wrkbook = null;
66 public $summaryInformation = null;
67 public $documentSummaryInformation = null;
68
69
70 /**
71 * Read the file
72 *
73 * @param $sFileName string Filename
74 * @throws PHPExcel_Reader_Exception
75 */
76 public function read($sFileName)
77 {
78 // Check if file exists and is readable
79 if(!is_readable($sFileName)) {
80 throw new PHPExcel_Reader_Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable.");
81 }
82
83 // Get the file identifier
84 // Don't bother reading the whole file until we know it's a valid OLE file
85 $this->data = file_get_contents($sFileName, FALSE, NULL, 0, 8);
86
87 // Check OLE identifier
88 if ($this->data != self::IDENTIFIER_OLE) {
89 throw new PHPExcel_Reader_Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
90 }
91
92 // Get the file data
93 $this->data = file_get_contents($sFileName);
94
95 // Total number of sectors used for the SAT
96 $this->numBigBlockDepotBlocks = self::_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
97
98 // SecID of the first sector of the directory stream
99 $this->rootStartBlock = self::_GetInt4d($this->data, self::ROOT_START_BLOCK_POS);
100
101 // SecID of the first sector of the SSAT (or -2 if not extant)
102 $this->sbdStartBlock = self::_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
103
104 // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
105 $this->extensionBlock = self::_GetInt4d($this->data, self::EXTENSION_BLOCK_POS);
106
107 // Total number of sectors used by MSAT
108 $this->numExtensionBlocks = self::_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
109
110 $bigBlockDepotBlocks = array();
111 $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
112
113 $bbdBlocks = $this->numBigBlockDepotBlocks;
114
115 if ($this->numExtensionBlocks != 0) {
116 $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
117 }
118
119 for ($i = 0; $i < $bbdBlocks; ++$i) {
120 $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
121 $pos += 4;
122 }
123
124 for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
125 $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
126 $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
127
128 for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
129 $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
130 $pos += 4;
131 }
132
133 $bbdBlocks += $blocksToRead;
134 if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
135 $this->extensionBlock = self::_GetInt4d($this->data, $pos);
136 }
137 }
138
139 $pos = 0;
140 $this->bigBlockChain = '';
141 $bbs = self::BIG_BLOCK_SIZE / 4;
142 for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
143 $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
144
145 $this->bigBlockChain .= substr($this->data, $pos, 4*$bbs);
146 $pos += 4*$bbs;
147 }
148
149 $pos = 0;
150 $sbdBlock = $this->sbdStartBlock;
151 $this->smallBlockChain = '';
152 while ($sbdBlock != -2) {
153 $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
154
155 $this->smallBlockChain .= substr($this->data, $pos, 4*$bbs);
156 $pos += 4*$bbs;
157
158 $sbdBlock = self::_GetInt4d($this->bigBlockChain, $sbdBlock*4);
159 }
160
161 // read the directory stream
162 $block = $this->rootStartBlock;
163 $this->entry = $this->_readData($block);
164
165 $this->_readPropertySets();
166 }
167
168 /**
169 * Extract binary stream data
170 *
171 * @return string
172 */
173 public function getStream($stream)
174 {
175 if ($stream === NULL) {
176 return null;
177 }
178
179 $streamData = '';
180
181 if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
182 $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']);
183
184 $block = $this->props[$stream]['startBlock'];
185
186 while ($block != -2) {
187 $pos = $block * self::SMALL_BLOCK_SIZE;
188 $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
189
190 $block = self::_GetInt4d($this->smallBlockChain, $block*4);
191 }
192
193 return $streamData;
194 } else {
195 $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
196 if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
197 ++$numBlocks;
198 }
199
200 if ($numBlocks == 0) return '';
201
202 $block = $this->props[$stream]['startBlock'];
203
204 while ($block != -2) {
205 $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
206 $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
207 $block = self::_GetInt4d($this->bigBlockChain, $block*4);
208 }
209
210 return $streamData;
211 }
212 }
213
214 /**
215 * Read a standard stream (by joining sectors using information from SAT)
216 *
217 * @param int $bl Sector ID where the stream starts
218 * @return string Data for standard stream
219 */
220 private function _readData($bl)
221 {
222 $block = $bl;
223 $data = '';
224
225 while ($block != -2) {
226 $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
227 $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
228 $block = self::_GetInt4d($this->bigBlockChain, $block*4);
229 }
230 return $data;
231 }
232
233 /**
234 * Read entries in the directory stream.
235 */
236 private function _readPropertySets() {
237 $offset = 0;
238
239 // loop through entires, each entry is 128 bytes
240 $entryLen = strlen($this->entry);
241 while ($offset < $entryLen) {
242 // entry data (128 bytes)
243 $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
244
245 // size in bytes of name
246 $nameSize = ord($d[self::SIZE_OF_NAME_POS]) | (ord($d[self::SIZE_OF_NAME_POS+1]) << 8);
247
248 // type of entry
249 $type = ord($d[self::TYPE_POS]);
250
251 // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
252 // sectorID of first sector of the short-stream container stream, if this entry is root entry
253 $startBlock = self::_GetInt4d($d, self::START_BLOCK_POS);
254
255 $size = self::_GetInt4d($d, self::SIZE_POS);
256
257 $name = str_replace("\x00", "", substr($d,0,$nameSize));
258
259
260 $this->props[] = array (
261 'name' => $name,
262 'type' => $type,
263 'startBlock' => $startBlock,
264 'size' => $size);
265
266 // tmp helper to simplify checks
267 $upName = strtoupper($name);
268
269 // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
270 if (($upName === 'WORKBOOK') || ($upName === 'BOOK')) {
271 $this->wrkbook = count($this->props) - 1;
272 }
273 else if ( $upName === 'ROOT ENTRY' || $upName === 'R') {
274 // Root entry
275 $this->rootentry = count($this->props) - 1;
276 }
277
278 // Summary information
279 if ($name == chr(5) . 'SummaryInformation') {
280 // echo 'Summary Information<br />';
281 $this->summaryInformation = count($this->props) - 1;
282 }
283
284 // Additional Document Summary information
285 if ($name == chr(5) . 'DocumentSummaryInformation') {
286 // echo 'Document Summary Information<br />';
287 $this->documentSummaryInformation = count($this->props) - 1;
288 }
289
290 $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
291 }
292
293 }
294
295 /**
296 * Read 4 bytes of data at specified position
297 *
298 * @param string $data
299 * @param int $pos
300 * @return int
301 */
302 private static function _GetInt4d($data, $pos)
303 {
304 // FIX: represent numbers correctly on 64-bit system
305 // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
306 // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
307 $_or_24 = ord($data[$pos + 3]);
308 if ($_or_24 >= 128) {
309 // negative number
310 $_ord_24 = -abs((256 - $_or_24) << 24);
311 } else {
312 $_ord_24 = ($_or_24 & 127) << 24;
313 }
314 return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24;
315 }
316
317 }
318