PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / 6.5.1.7
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin v6.5.1.7
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / lib / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Shared / OLERead.php

OLERead.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/OLERead.php

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