Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * |
3 | | * Copyright 2004 Komarov Valery |
4 | | * Copyright 2006 Christophe Leitienne |
5 | | * Copyright 2008-2017 David Hoerl |
6 | | * Copyright 2013 Bob Colbert |
7 | | * Copyright 2013-2018 Evan Miller |
8 | | * |
9 | | * This file is part of libxls -- A multiplatform, C/C++ library for parsing |
10 | | * Excel(TM) files. |
11 | | * |
12 | | * Redistribution and use in source and binary forms, with or without |
13 | | * modification, are permitted provided that the following conditions are met: |
14 | | * |
15 | | * 1. Redistributions of source code must retain the above copyright notice, |
16 | | * this list of conditions and the following disclaimer. |
17 | | * |
18 | | * 2. Redistributions in binary form must reproduce the above copyright |
19 | | * notice, this list of conditions and the following disclaimer in the |
20 | | * documentation and/or other materials provided with the distribution. |
21 | | * |
22 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS |
23 | | * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
24 | | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
25 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR |
26 | | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
27 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
28 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
29 | | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
30 | | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
31 | | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
32 | | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | | * |
34 | | */ |
35 | | |
36 | | #include "config.h" |
37 | | |
38 | | #include <memory.h> |
39 | | #include <string.h> |
40 | | #include <stdio.h> |
41 | | #include <stdlib.h> |
42 | | |
43 | | #include "../include/libxls/ole.h" |
44 | | #include "../include/libxls/xlstool.h" |
45 | | #include "../include/libxls/endian.h" |
46 | | |
47 | | extern int xls_debug; |
48 | | |
49 | | //#define OLE_DEBUG |
50 | | |
51 | | //static const DWORD MSATSECT = 0xFFFFFFFC; // -4 |
52 | | //static const DWORD FATSECT = 0xFFFFFFFD; // -3 |
53 | | static const DWORD ENDOFCHAIN = 0xFFFFFFFE; // -2 |
54 | | static const DWORD FREESECT = 0xFFFFFFFF; // -1 |
55 | | |
56 | | static size_t sector_pos(OLE2* ole2, DWORD sid); |
57 | | static ssize_t sector_read(OLE2* ole2, void *buffer, size_t buffer_len, DWORD sid); |
58 | | static ssize_t read_MSAT(OLE2* ole2, OLE2Header *oleh); |
59 | | static void *ole_malloc(size_t len); |
60 | | |
61 | 14.0k | static void *ole_malloc(size_t len) { |
62 | 14.0k | if (len > (1<<24) || len == 0) { |
63 | 65 | return NULL; |
64 | 65 | } |
65 | 13.9k | return calloc(1, len); |
66 | 14.0k | } |
67 | | |
68 | | /* Reallocates memory and zero-fills only the newly grown region (from old_len to new_len). Frees ptr on failure. */ |
69 | 1.48k | static void *ole_realloc_zero(void *ptr, size_t old_len, size_t new_len) { |
70 | 1.48k | if (new_len > (1<<24) || new_len == 0) { |
71 | 17 | free(ptr); |
72 | 17 | return NULL; |
73 | 17 | } |
74 | 1.47k | void *new_ptr = realloc(ptr, new_len); |
75 | 1.47k | if (!new_ptr) { |
76 | 0 | free(ptr); |
77 | 0 | return NULL; |
78 | 0 | } |
79 | 1.47k | if (new_len > old_len) { |
80 | 1.40k | memset((char *)new_ptr + old_len, 0, new_len - old_len); |
81 | 1.40k | } |
82 | 1.47k | return new_ptr; |
83 | 1.47k | } |
84 | | |
85 | 4.89k | static int ole2_validate_sector_chain(DWORD *chain, DWORD chain_count, DWORD chain_start) { |
86 | 4.89k | if (chain == NULL || chain_count == 0) |
87 | 10 | return 0; |
88 | 4.88k | DWORD count = 0; |
89 | 4.88k | DWORD sector = chain_start; |
90 | 27.5M | while (sector != ENDOFCHAIN) { |
91 | 27.5M | if (sector >= chain_count) |
92 | 308 | return 0; |
93 | | |
94 | 27.5M | if (++count >= chain_count) |
95 | 37 | return 0; |
96 | | |
97 | 27.5M | sector = xlsIntVal(chain[sector]); |
98 | 27.5M | } |
99 | 4.54k | return 1; |
100 | 4.88k | } |
101 | | |
102 | 4.27M | static int ole2_validate_sector(DWORD sector, OLE2 *ole) { |
103 | 4.27M | if (sector >= ole->SecIDCount) { |
104 | 2.81k | if (xls_debug) fprintf(stderr, "Error: fatpos %d out-of-bounds for SecID[%d]\n", |
105 | 0 | (int)sector, ole->SecIDCount); |
106 | 2.81k | return 0; |
107 | 2.81k | } |
108 | | |
109 | 4.27M | if (sector == xlsIntVal(ole->SecID[sector])) { |
110 | 3 | if (xls_debug) fprintf(stderr, "Error: Sector loop detected, SecID[%d] = %d\n", |
111 | 0 | (int)sector, (int)sector); |
112 | 3 | return 0; |
113 | 3 | } |
114 | | |
115 | 4.27M | return 1; |
116 | 4.27M | } |
117 | | |
118 | | // Read next sector of stream |
119 | | static int ole2_bufread(OLE2Stream* olest) |
120 | 679k | { |
121 | 679k | BYTE *ptr; |
122 | | |
123 | | #ifdef OLE_DEBUG |
124 | | fprintf(stderr, "----------------------------------------------\n"); |
125 | | fprintf(stderr, "ole2_bufread (start)\n"); |
126 | | #endif |
127 | | |
128 | 679k | if (olest == NULL || olest->ole == NULL) |
129 | 0 | return -1; |
130 | | |
131 | 679k | if ((DWORD)olest->fatpos!=ENDOFCHAIN) |
132 | 666k | { |
133 | 666k | if(olest->sfat) { |
134 | 229k | if (olest->ole->SSAT == NULL || olest->buf == NULL || olest->ole->SSecID == NULL) |
135 | 16 | return -1; |
136 | | |
137 | 229k | if (olest->fatpos*olest->ole->lssector + olest->bufsize > olest->ole->SSATCount) { |
138 | 144 | if (xls_debug) fprintf(stderr, "Error: fatpos %d out-of-bounds for SSAT\n", (int)olest->fatpos); |
139 | 144 | return -1; |
140 | 144 | } |
141 | | |
142 | 229k | ptr = olest->ole->SSAT + olest->fatpos*olest->ole->lssector; |
143 | 229k | memcpy(olest->buf, ptr, olest->bufsize); |
144 | | |
145 | 229k | if (olest->fatpos >= olest->ole->SSecIDCount) { |
146 | 0 | if (xls_debug) fprintf(stderr, "Error: fatpos %d out-of-bounds for SSecID[%d]\n", |
147 | 0 | (int)olest->fatpos, olest->ole->SSecIDCount); |
148 | 0 | return -1; |
149 | 0 | } |
150 | | |
151 | 229k | olest->fatpos=xlsIntVal(olest->ole->SSecID[olest->fatpos]); |
152 | 229k | olest->pos=0; |
153 | 229k | olest->cfat++; |
154 | 437k | } else { |
155 | 437k | if ((int)olest->fatpos < 0 || |
156 | 437k | sector_read(olest->ole, olest->buf, olest->bufsize, olest->fatpos) == -1) { |
157 | 8.54k | if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", (int)olest->fatpos); |
158 | 8.54k | return -1; |
159 | 8.54k | } |
160 | | |
161 | 428k | if (!ole2_validate_sector(olest->fatpos, olest->ole)) { |
162 | 0 | return -1; |
163 | 0 | } |
164 | | |
165 | 428k | olest->fatpos = xlsIntVal(olest->ole->SecID[olest->fatpos]); |
166 | 428k | olest->pos=0; |
167 | 428k | olest->cfat++; |
168 | 428k | } |
169 | 666k | } |
170 | | #ifdef OLE_DEBUG |
171 | | fprintf(stderr, "----------------------------------------------\n"); |
172 | | fprintf(stderr, "ole2_bufread (end)\n"); |
173 | | #endif |
174 | | // else printf("ENDOFCHAIN!!!\n"); |
175 | 670k | return 0; |
176 | 679k | } |
177 | | |
178 | | // Read part of stream |
179 | | ssize_t ole2_read(void* buf, size_t size, size_t count, OLE2Stream* olest) |
180 | 4.32M | { |
181 | 4.32M | size_t didReadCount=0; |
182 | 4.32M | size_t totalReadCount; |
183 | | |
184 | 4.32M | totalReadCount=size*count; |
185 | 4.32M | if (buf && totalReadCount > 0) { |
186 | 4.32M | memset(buf, 0, totalReadCount); |
187 | 4.32M | } |
188 | | |
189 | | // olest->size inited to -1 |
190 | | // printf("===== ole2_read(%ld bytes)\n", totalReadCount); |
191 | | |
192 | 4.32M | if ((long)olest->size>=0 && !olest->sfat) // directory is -1 |
193 | 2.29M | { |
194 | 2.29M | size_t rem; |
195 | 2.29M | rem = olest->size - (olest->cfat*olest->ole->lsector+olest->pos); |
196 | 2.29M | totalReadCount = rem<totalReadCount?rem:totalReadCount; |
197 | 2.29M | if (rem<=0) olest->eof=1; |
198 | | |
199 | | // printf(" rem=%ld olest->size=%d - subfunc=%d\n", rem, olest->size, (olest->cfat*olest->ole->lsector+olest->pos) ); |
200 | | //printf(" totalReadCount=%d (rem=%d size*count=%ld)\n", totalReadCount, rem, size*count); |
201 | 2.29M | } |
202 | | |
203 | 9.19M | while ((!olest->eof) && (didReadCount < totalReadCount)) |
204 | 4.88M | { |
205 | 4.88M | unsigned long remainingBytes; |
206 | 4.88M | size_t needToReadCount; |
207 | | |
208 | 4.88M | needToReadCount = totalReadCount - didReadCount; |
209 | 4.88M | remainingBytes = olest->bufsize - olest->pos; |
210 | | |
211 | 4.88M | if (needToReadCount < remainingBytes) { // does the current sector contain all the data I need? |
212 | 4.23M | memcpy((BYTE*)buf + didReadCount, olest->buf + olest->pos, needToReadCount); |
213 | 4.23M | olest->pos += needToReadCount; |
214 | 4.23M | didReadCount += needToReadCount; |
215 | 4.23M | } else { |
216 | 642k | memcpy((BYTE*)buf + didReadCount, olest->buf + olest->pos, remainingBytes); |
217 | 642k | olest->pos += remainingBytes; |
218 | 642k | didReadCount += remainingBytes; |
219 | 642k | if (ole2_bufread(olest) == -1) |
220 | 8.02k | return -1; |
221 | 642k | } |
222 | 4.87M | if (((DWORD)olest->fatpos == ENDOFCHAIN) && (olest->pos >= olest->bufsize)) { |
223 | 12.2k | olest->eof=1; |
224 | 12.2k | } |
225 | 4.87M | } |
226 | 4.31M | if (didReadCount > totalReadCount) |
227 | 0 | return -1; |
228 | | |
229 | | // printf(" didReadCount=%ld EOF=%d\n", didReadCount, olest->eof); |
230 | | // printf("=====\n"); |
231 | | |
232 | | #ifdef OLE_DEBUG |
233 | | fprintf(stderr, "----------------------------------------------\n"); |
234 | | fprintf(stderr, "ole2_read (end)\n"); |
235 | | fprintf(stderr, "start: %d \n",olest->start); |
236 | | fprintf(stderr, "pos: %d \n",(int)olest->pos); |
237 | | fprintf(stderr, "cfat: %d \n",(int)olest->cfat); |
238 | | fprintf(stderr, "size: %d \n",(int)olest->size); |
239 | | fprintf(stderr, "fatpos: %d \n",(int)olest->fatpos); |
240 | | fprintf(stderr, "bufsize: %d \n",(int)olest->bufsize); |
241 | | fprintf(stderr, "eof: %d \n",olest->eof); |
242 | | #endif |
243 | | |
244 | 4.31M | return didReadCount; |
245 | 4.31M | } |
246 | | |
247 | | // Open stream in logical ole file |
248 | | OLE2Stream* ole2_sopen(OLE2* ole,DWORD start, size_t size) |
249 | 4.89k | { |
250 | 4.89k | OLE2Stream* olest=NULL; |
251 | 4.89k | int success = 1; |
252 | | |
253 | | #ifdef OLE_DEBUG |
254 | | fprintf(stderr, "----------------------------------------------\n"); |
255 | | fprintf(stderr, "ole2_sopen start=%Xh\n", start); |
256 | | #endif |
257 | | |
258 | 4.89k | olest = calloc(1, sizeof(OLE2Stream)); |
259 | 4.89k | if (olest == NULL) |
260 | 0 | return NULL; |
261 | 4.89k | olest->ole=ole; |
262 | 4.89k | olest->size=size; |
263 | 4.89k | olest->fatpos=start; |
264 | 4.89k | olest->start=start; |
265 | 4.89k | olest->cfat=-1; |
266 | 4.89k | if((long)size > 0 && size < (size_t)ole->sectorcutoff) { |
267 | 1.01k | olest->bufsize=ole->lssector; |
268 | 1.01k | olest->sfat = 1; |
269 | 3.87k | } else { |
270 | 3.87k | olest->bufsize=ole->lsector; |
271 | 3.87k | } |
272 | 4.89k | if ((olest->buf = ole_malloc(olest->bufsize)) == NULL) { |
273 | 0 | success = 0; |
274 | 0 | goto cleanup; |
275 | 0 | } |
276 | | |
277 | 4.89k | if (olest->sfat) { |
278 | 1.01k | if (!ole2_validate_sector_chain(ole->SSecID, ole->SSecIDCount, start)) { |
279 | 134 | success = 0; |
280 | 134 | goto cleanup; |
281 | 134 | } |
282 | 3.87k | } else { |
283 | 3.87k | if (!ole2_validate_sector_chain(ole->SecID, ole->SecIDCount, start)) { |
284 | 221 | success = 0; |
285 | 221 | goto cleanup; |
286 | 221 | } |
287 | 3.87k | } |
288 | | |
289 | 4.54k | if (ole2_bufread(olest) == -1) { |
290 | 39 | success = 0; |
291 | 39 | goto cleanup; |
292 | 39 | } |
293 | | |
294 | 4.89k | cleanup: |
295 | 4.89k | if (!success) { |
296 | 394 | ole2_fclose(olest); |
297 | 394 | olest = NULL; |
298 | 394 | } |
299 | | |
300 | | // if(xls_debug) printf("sopen: sector=%d next=%d\n", start, olest->fatpos); |
301 | 4.89k | return olest; |
302 | 4.54k | } |
303 | | |
304 | | // Move in stream |
305 | | int ole2_seek(OLE2Stream* olest,DWORD ofs) |
306 | 36.2k | { |
307 | | #ifdef OLE_DEBUG |
308 | | fprintf(stderr, "SEEK %x\n", ofs); |
309 | | #endif |
310 | 36.2k | if(olest->sfat) { |
311 | 10.2k | ldiv_t div_rez=ldiv(ofs,olest->ole->lssector); |
312 | 10.2k | int i; |
313 | 10.2k | olest->fatpos=olest->start; |
314 | | |
315 | 10.2k | if (div_rez.quot!=0) |
316 | 6.13k | { |
317 | 76.1k | for (i=0;i<div_rez.quot;i++) { |
318 | 71.1k | if (olest->fatpos >= olest->ole->SSecIDCount) |
319 | 1.12k | return -1; |
320 | 70.0k | olest->fatpos=xlsIntVal(olest->ole->SSecID[olest->fatpos]); |
321 | 70.0k | } |
322 | 6.13k | } |
323 | | |
324 | 9.11k | if (ole2_bufread(olest) == -1) |
325 | 56 | return -1; |
326 | | |
327 | 9.05k | olest->pos=div_rez.rem; |
328 | 9.05k | olest->eof=0; |
329 | 9.05k | olest->cfat=div_rez.quot; |
330 | | //printf("%i=%i %i\n",ofs,div_rez.quot,div_rez.rem); |
331 | 25.9k | } else { |
332 | 25.9k | ldiv_t div_rez=ldiv(ofs,olest->ole->lsector); |
333 | 25.9k | int i; |
334 | | #ifdef OLE_DEBUG |
335 | | fprintf(stderr, "seeking fatpos%lu start %u\n", olest->fatpos, olest->start); |
336 | | #endif |
337 | 25.9k | olest->fatpos=olest->start; |
338 | | |
339 | 25.9k | if (div_rez.quot!=0) |
340 | 4.76k | { |
341 | 129k | for (i=0;i<div_rez.quot;i++) { |
342 | 127k | if (!ole2_validate_sector(olest->fatpos, olest->ole)) |
343 | 2.72k | return -1; |
344 | 125k | olest->fatpos=xlsIntVal(olest->ole->SecID[olest->fatpos]); |
345 | 125k | } |
346 | 4.76k | } |
347 | | |
348 | 23.2k | if (ole2_bufread(olest) == -1) |
349 | 584 | return -1; |
350 | | |
351 | 22.6k | olest->pos=div_rez.rem; |
352 | 22.6k | olest->eof=0; |
353 | 22.6k | olest->cfat=div_rez.quot; |
354 | | //printf("%i=%i %i\n",ofs,div_rez.quot,div_rez.rem); |
355 | 22.6k | } |
356 | 31.7k | return 0; |
357 | 36.2k | } |
358 | | |
359 | | // Open logical file contained in physical OLE file |
360 | | OLE2Stream* ole2_fopen(OLE2* ole, const char *file) |
361 | 7.22k | { |
362 | 7.22k | int i; |
363 | | |
364 | | #ifdef OLE_DEBUG |
365 | | fprintf(stderr, "----------------------------------------------\n"); |
366 | | fprintf(stderr, "ole2_fopen %s\n", file); |
367 | | #endif |
368 | | |
369 | 19.1k | for (i=0;i<ole->files.count;i++) { |
370 | 14.0k | char *str = ole->files.file[i].name; |
371 | | #ifdef OLE_DEBUG |
372 | | fprintf(stderr, "----------------------------------------------\n"); |
373 | | fprintf(stderr, "ole2_fopen found %s\n", str); |
374 | | #endif |
375 | 14.0k | if (str && strcmp(str,file)==0) // newer versions of Excel don't write the "Root Entry" string for the first set of data |
376 | 2.18k | { |
377 | 2.18k | return ole2_sopen(ole,ole->files.file[i].start,ole->files.file[i].size); |
378 | 2.18k | } |
379 | 14.0k | } |
380 | 5.04k | return NULL; |
381 | 7.22k | } |
382 | | |
383 | 4.35M | static int ole2_fseek(OLE2 *ole2, size_t pos) { |
384 | 4.35M | if (ole2->file) |
385 | 0 | return fseek(ole2->file, pos, SEEK_SET); |
386 | | |
387 | 4.35M | if (pos > ole2->buffer_len) |
388 | 8.55k | return -1; |
389 | | |
390 | 4.34M | ole2->buffer_pos = pos; |
391 | 4.34M | return 0; |
392 | 4.35M | } |
393 | | |
394 | | // Will read up to `size' bytes from the input, and pad the rest of `size' with |
395 | | // zeros if the input file or buffer is short. |
396 | 4.34M | static size_t ole2_fread(OLE2 *ole2, void *buffer, size_t buffer_len, size_t size) { |
397 | 4.34M | if (size > buffer_len) |
398 | 10 | return 0; |
399 | | |
400 | 4.34M | memset(buffer, 0, size); |
401 | | |
402 | 4.34M | if (ole2->file) |
403 | 0 | return fread(buffer, 1, size, ole2->file) > 0; |
404 | | |
405 | 4.34M | if (ole2->buffer_pos >= ole2->buffer_len) |
406 | 462 | return 0; |
407 | | |
408 | 4.34M | if (ole2->buffer_pos + size > ole2->buffer_len) |
409 | 1.87M | size = ole2->buffer_len - ole2->buffer_pos; |
410 | | |
411 | 4.34M | memcpy(buffer, (const char *)ole2->buffer + ole2->buffer_pos, size); |
412 | 4.34M | ole2->buffer_pos += size; |
413 | | |
414 | 4.34M | return 1; |
415 | 4.34M | } |
416 | | |
417 | | // read header and check magic numbers |
418 | 3.50k | static ssize_t ole2_read_header(OLE2 *ole) { |
419 | 3.50k | ssize_t bytes_read = 0, total_bytes_read = 0; |
420 | 3.50k | OLE2Header *oleh = calloc(1, sizeof(OLE2Header)); |
421 | 3.50k | if (oleh == NULL) |
422 | 0 | return -1; |
423 | 3.50k | if (ole2_fread(ole, oleh, sizeof(OLE2Header), sizeof(OLE2Header)) != 1) { |
424 | 0 | total_bytes_read = -1; |
425 | 0 | goto cleanup; |
426 | 0 | } |
427 | 3.50k | total_bytes_read += sizeof(OLE2Header); |
428 | 3.50k | xlsConvertHeader(oleh); |
429 | | |
430 | | // make sure the file looks good. Note: this code only works on Little Endian machines |
431 | 3.50k | if(oleh->id[0] != 0xE011CFD0 || oleh->id[1] != 0xE11AB1A1 || oleh->byteorder != 0xFFFE) { |
432 | 153 | if (xls_debug) fprintf(stderr, "Not an excel file\n"); |
433 | 153 | total_bytes_read = -1; |
434 | 153 | goto cleanup; |
435 | 153 | } |
436 | | |
437 | | //ole->lsector=(WORD)pow(2,oleh->lsector); |
438 | | //ole->lssector=(WORD)pow(2,oleh->lssector); |
439 | 3.35k | ole->lsector=512; |
440 | 3.35k | ole->lssector=64; |
441 | | |
442 | 3.35k | if (oleh->lsectorB != 9 || oleh->lssectorB != 6) { // 2**9 == 512, 2**6 == 64 |
443 | 36 | if (xls_debug) fprintf(stderr, "Unexpected sector size\n"); |
444 | 36 | total_bytes_read = -1; |
445 | 36 | goto cleanup; |
446 | 36 | } |
447 | | |
448 | 3.31k | ole->cfat=oleh->cfat; |
449 | 3.31k | ole->dirstart=oleh->dirstart; |
450 | 3.31k | ole->sectorcutoff=oleh->sectorcutoff; |
451 | 3.31k | ole->sfatstart=oleh->sfatstart; |
452 | 3.31k | ole->csfat=oleh->csfat; |
453 | 3.31k | ole->difstart=oleh->difstart; |
454 | 3.31k | ole->cdif=oleh->cdif; |
455 | 3.31k | ole->files.count=0; |
456 | | |
457 | | #ifdef OLE_DEBUG |
458 | | fprintf(stderr, "==== OLE HEADER ====\n"); |
459 | | //printf ("Header Size: %i \n", sizeof(OLE2Header)); |
460 | | //printf ("id[0]-id[1]: %X-%X \n", oleh->id[0], oleh->id[1]); |
461 | | fprintf(stderr, "verminor: %X \n",oleh->verminor); |
462 | | fprintf(stderr, "verdll: %X \n",oleh->verdll); |
463 | | //printf ("Byte order: %X \n",oleh->byteorder); |
464 | | fprintf(stderr, "sect len: %X (%i)\n",ole->lsector,ole->lsector); // ole |
465 | | fprintf(stderr, "mini len: %X (%i)\n",ole->lssector,ole->lssector); // ole |
466 | | fprintf(stderr, "Fat sect.: %i \n",oleh->cfat); |
467 | | fprintf(stderr, "Dir Start: %i \n",oleh->dirstart); |
468 | | |
469 | | fprintf(stderr, "Mini Cutoff: %i \n",oleh->sectorcutoff); |
470 | | fprintf(stderr, "MiniFat Start: %X \n",oleh->sfatstart); |
471 | | fprintf(stderr, "Count MFat: %i \n",oleh->csfat); |
472 | | fprintf(stderr, "Dif start: %X \n",oleh->difstart); |
473 | | fprintf(stderr, "Count Dif: %i \n",oleh->cdif); |
474 | | fprintf(stderr, "Fat Size: %u (0x%X) \n",oleh->cfat*ole->lsector,oleh->cfat*ole->lsector); |
475 | | #endif |
476 | | // read directory entries |
477 | 3.31k | if ((bytes_read = read_MSAT(ole, oleh)) == -1) { |
478 | 598 | total_bytes_read = -1; |
479 | 598 | goto cleanup; |
480 | 598 | } |
481 | 2.71k | total_bytes_read += bytes_read; |
482 | | |
483 | 3.50k | cleanup: |
484 | 3.50k | free(oleh); |
485 | | |
486 | 3.50k | return total_bytes_read; |
487 | 2.71k | } |
488 | | |
489 | 2.71k | static ssize_t ole2_read_body(OLE2 *ole) { |
490 | | // reuse this buffer |
491 | 2.71k | PSS *pss = NULL; |
492 | 2.71k | OLE2Stream *olest = NULL; |
493 | 2.71k | char* name = NULL; |
494 | 2.71k | ssize_t bytes_read = 0, total_bytes_read = 0; |
495 | | |
496 | 2.71k | if ((olest = ole2_sopen(ole,ole->dirstart, -1)) == NULL) { |
497 | 176 | total_bytes_read = -1; |
498 | 176 | goto cleanup; |
499 | 176 | } |
500 | 2.54k | pss = calloc(1, sizeof(PSS)); |
501 | 2.54k | if (pss == NULL) { |
502 | 0 | total_bytes_read = -1; |
503 | 0 | goto cleanup; |
504 | 0 | } |
505 | 12.0k | do { |
506 | 12.0k | if ((bytes_read = ole2_read(pss,1,sizeof(PSS),olest)) == -1) { |
507 | 16 | total_bytes_read = -1; |
508 | 16 | goto cleanup; |
509 | 16 | } |
510 | 12.0k | total_bytes_read += bytes_read; |
511 | 12.0k | xlsConvertPss(pss); |
512 | 12.0k | if (pss->bsize > sizeof(pss->name)) { |
513 | 43 | total_bytes_read = -1; |
514 | 43 | goto cleanup; |
515 | 43 | } |
516 | 11.9k | name=transcode_utf16_to_utf8(pss->name, pss->bsize); |
517 | | #ifdef OLE_DEBUG |
518 | | fprintf(stderr, "OLE NAME: %s count=%d\n", name, (int)ole->files.count); |
519 | | #endif |
520 | 11.9k | if (pss->type == PS_USER_ROOT || pss->type == PS_USER_STREAM) // (name!=NULL) // |
521 | 4.91k | { |
522 | | |
523 | | #ifdef OLE_DEBUG |
524 | | fprintf(stderr, "OLE TYPE: %s file=%d size=%d\n", |
525 | | pss->type == PS_USER_ROOT ? "root" : "user", |
526 | | (int)ole->files.count, (int)pss->size); |
527 | | #endif |
528 | 4.91k | struct st_olefiles_data *new_files = realloc(ole->files.file, |
529 | 4.91k | (ole->files.count+1)*sizeof(struct st_olefiles_data)); |
530 | 4.91k | if (new_files == NULL) { |
531 | 0 | free(name); |
532 | 0 | total_bytes_read = -1; |
533 | 0 | goto cleanup; |
534 | 0 | } |
535 | 4.91k | ole->files.file = new_files; |
536 | 4.91k | ole->files.file[ole->files.count].name=name; |
537 | 4.91k | ole->files.file[ole->files.count].start=pss->sstart; |
538 | 4.91k | ole->files.file[ole->files.count].size=pss->size; |
539 | 4.91k | ole->files.count++; |
540 | | |
541 | | #ifdef OLE_DEBUG |
542 | | fprintf(stderr, "----------------------------------------------\n"); |
543 | | fprintf(stderr, "name: %s (size=%d [c=%c])\n", name, pss->bsize, name ? name[0]:' '); |
544 | | fprintf(stderr, "bsize %i\n",pss->bsize); |
545 | | fprintf(stderr, "type %i\n",pss->type); |
546 | | fprintf(stderr, "flag %i\n",pss->flag); |
547 | | fprintf(stderr, "left %X\n",pss->left); |
548 | | fprintf(stderr, "right %X\n",pss->right); |
549 | | fprintf(stderr, "child %X\n",pss->child); |
550 | | fprintf(stderr, "guid %.4X-%.4X-%.4X-%.4X %.4X-%.4X-%.4X-%.4X\n", |
551 | | pss->guid[0],pss->guid[1],pss->guid[2],pss->guid[3], |
552 | | pss->guid[4],pss->guid[5],pss->guid[6],pss->guid[7]); |
553 | | fprintf(stderr, "user flag %.4X\n",pss->userflags); |
554 | | fprintf(stderr, "sstart %.4d\n",pss->sstart); |
555 | | fprintf(stderr, "size %.4d\n",pss->size); |
556 | | #endif |
557 | 4.91k | if(pss->sstart == ENDOFCHAIN) { |
558 | 73 | if (xls_debug) verbose("END OF CHAIN\n"); |
559 | 4.84k | } else if(pss->type == PS_USER_STREAM) { |
560 | 3.32k | } else if(pss->type == PS_USER_ROOT) { |
561 | 1.52k | DWORD sector, k, blocks; |
562 | 1.52k | BYTE *wptr; |
563 | 1.52k | size_t bytes_left; |
564 | | |
565 | 1.52k | blocks = (pss->size + (ole->lsector - 1)) / ole->lsector; // count partial |
566 | 1.52k | if (ole->lsector == 0 || blocks > (1u << 24) / ole->lsector) { |
567 | 31 | total_bytes_read = -1; |
568 | 31 | goto cleanup; |
569 | 31 | } |
570 | | #ifdef OLE_DEBUG |
571 | | fprintf(stderr, "OLE BLOCKS: %d = (%d + (%d - 1))/%d\n", |
572 | | (int)blocks, (int)pss->size, (int)ole->lsector, (int)ole->lsector); |
573 | | #endif |
574 | 1.48k | size_t old_ssat_bytes = ole->SSATCount; |
575 | 1.48k | if ((ole->SSAT = ole_realloc_zero(ole->SSAT, old_ssat_bytes, blocks*ole->lsector)) == NULL) { |
576 | 17 | total_bytes_read = -1; |
577 | 17 | goto cleanup; |
578 | 17 | } |
579 | 1.47k | ole->SSATCount = blocks*ole->lsector; |
580 | | // printf("blocks %d\n", blocks); |
581 | | |
582 | 1.47k | sector = pss->sstart; |
583 | 1.47k | wptr = (BYTE*)ole->SSAT; |
584 | 1.47k | bytes_left = blocks*ole->lsector; |
585 | 1.65M | for(k=0; k<blocks; ++k) { |
586 | | // printf("block %d sector %d\n", k, sector); |
587 | 1.65M | if (sector == ENDOFCHAIN || sector_read(ole, wptr, bytes_left, sector) == -1) { |
588 | 103 | if (xls_debug) fprintf(stderr, "Unable to read sector #%d\n", sector); |
589 | 103 | total_bytes_read = -1; |
590 | 103 | goto cleanup; |
591 | 103 | } |
592 | 1.65M | if (!ole2_validate_sector(sector, ole)) { |
593 | 46 | total_bytes_read = -1; |
594 | 46 | goto cleanup; |
595 | 46 | } |
596 | 1.65M | total_bytes_read += ole->lsector; |
597 | 1.65M | wptr += ole->lsector; |
598 | 1.65M | bytes_left -= ole->lsector; |
599 | 1.65M | sector = xlsIntVal(ole->SecID[sector]); |
600 | 1.65M | } |
601 | 1.47k | } |
602 | 7.08k | } else { |
603 | 7.08k | free(name); |
604 | 7.08k | } |
605 | 11.9k | } while (!olest->eof); |
606 | | |
607 | 2.71k | cleanup: |
608 | 2.71k | if (olest) |
609 | 2.54k | ole2_fclose(olest); |
610 | 2.71k | if (pss) |
611 | 2.54k | free(pss); |
612 | | |
613 | | #ifdef OLE_DEBUG |
614 | | fprintf(stderr, "----------------------------------------------\n"); |
615 | | fprintf(stderr, "ole2_read_body: %d bytes\n", (int)total_bytes_read); |
616 | | #endif |
617 | | |
618 | 2.71k | return total_bytes_read; |
619 | 2.54k | } |
620 | | |
621 | 3.50k | OLE2 *ole2_read_header_and_body(OLE2 *ole) { |
622 | 3.50k | if (ole2_read_header(ole) == -1) { |
623 | 787 | ole2_close(ole); |
624 | 787 | return NULL; |
625 | 787 | } |
626 | | |
627 | 2.71k | if (ole2_read_body(ole) == -1) { |
628 | 432 | ole2_close(ole); |
629 | 432 | return NULL; |
630 | 432 | } |
631 | | |
632 | 2.28k | return ole; |
633 | 2.71k | } |
634 | | |
635 | | // Open in-memory buffer |
636 | 3.50k | OLE2 *ole2_open_buffer(const void *buffer, size_t len) { |
637 | 3.50k | OLE2 *ole = calloc(1, sizeof(OLE2)); |
638 | 3.50k | if (ole == NULL) |
639 | 0 | return NULL; |
640 | | |
641 | 3.50k | ole->buffer = buffer; |
642 | 3.50k | ole->buffer_len = len; |
643 | | |
644 | 3.50k | return ole2_read_header_and_body(ole); |
645 | 3.50k | } |
646 | | |
647 | | // Open physical file |
648 | | #ifdef _WIN32 |
649 | | /* Convert a UTF-8 string to UTF-16 for _wfopen(). Returns NULL if the input |
650 | | * is not well-formed UTF-8 (the path is probably in the ANSI code page then). |
651 | | * Written by hand so that ole.c does not need <windows.h>, whose DWORD typedef |
652 | | * conflicts with the one in xlstypes.h. */ |
653 | | static wchar_t *ole2_utf8_to_utf16(const char *str) { |
654 | | const unsigned char *in = (const unsigned char *)str; |
655 | | size_t n = strlen(str); |
656 | | wchar_t *out = malloc((n + 1) * sizeof(wchar_t)); |
657 | | size_t i = 0, o = 0; |
658 | | |
659 | | if (out == NULL) |
660 | | return NULL; |
661 | | |
662 | | while (i < n) { |
663 | | uint32_t cp; |
664 | | size_t extra; |
665 | | if (in[i] < 0x80) { |
666 | | cp = in[i]; extra = 0; |
667 | | } else if ((in[i] & 0xE0) == 0xC0 && in[i] >= 0xC2) { |
668 | | cp = in[i] & 0x1F; extra = 1; |
669 | | } else if ((in[i] & 0xF0) == 0xE0) { |
670 | | cp = in[i] & 0x0F; extra = 2; |
671 | | } else if ((in[i] & 0xF8) == 0xF0 && in[i] <= 0xF4) { |
672 | | cp = in[i] & 0x07; extra = 3; |
673 | | } else { |
674 | | goto invalid; |
675 | | } |
676 | | for (size_t k = 1; k <= extra; k++) { |
677 | | if (i + k >= n || (in[i + k] & 0xC0) != 0x80) |
678 | | goto invalid; |
679 | | cp = (cp << 6) | (in[i + k] & 0x3F); |
680 | | } |
681 | | if ((extra == 2 && cp < 0x800) || (extra == 3 && cp < 0x10000) || |
682 | | cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) |
683 | | goto invalid; |
684 | | i += extra + 1; |
685 | | if (cp >= 0x10000) { |
686 | | cp -= 0x10000; |
687 | | out[o++] = (wchar_t)(0xD800 | (cp >> 10)); |
688 | | out[o++] = (wchar_t)(0xDC00 | (cp & 0x3FF)); |
689 | | } else { |
690 | | out[o++] = (wchar_t)cp; |
691 | | } |
692 | | } |
693 | | out[o] = L'\0'; |
694 | | return out; |
695 | | |
696 | | invalid: |
697 | | free(out); |
698 | | return NULL; |
699 | | } |
700 | | #endif |
701 | | |
702 | | /* Open a file by path. On Windows fopen() interprets the path in the ANSI code |
703 | | * page, so a UTF-8 path with non-ASCII characters fails; retry it as UTF-16. |
704 | | * See https://github.com/libxls/libxls/issues/146 */ |
705 | | static FILE *ole2_fopen_path(const char *file) |
706 | 0 | { |
707 | 0 | FILE *fp = fopen(file, "rb"); |
708 | | #ifdef _WIN32 |
709 | | if (fp == NULL) { |
710 | | wchar_t *wfile = ole2_utf8_to_utf16(file); |
711 | | if (wfile) { |
712 | | fp = _wfopen(wfile, L"rb"); |
713 | | free(wfile); |
714 | | } |
715 | | } |
716 | | #endif |
717 | 0 | return fp; |
718 | 0 | } |
719 | | |
720 | | OLE2* ole2_open_file(const char *file) |
721 | 0 | { |
722 | 0 | OLE2* ole = NULL; |
723 | |
|
724 | | #ifdef OLE_DEBUG |
725 | | fprintf(stderr, "----------------------------------------------\n"); |
726 | | fprintf(stderr, "ole2_open_file %s\n", file); |
727 | | #endif |
728 | |
|
729 | 0 | if(xls_debug) printf("ole2_open: %s\n", file); |
730 | 0 | ole = calloc(1, sizeof(OLE2)); |
731 | 0 | if (ole == NULL) |
732 | 0 | return NULL; |
733 | | |
734 | 0 | if (!(ole->file=ole2_fopen_path(file))) { |
735 | 0 | if(xls_debug) fprintf(stderr, "File not found\n"); |
736 | 0 | free(ole); |
737 | 0 | return NULL; |
738 | 0 | } |
739 | | |
740 | 0 | return ole2_read_header_and_body(ole); |
741 | 0 | } |
742 | | |
743 | | void ole2_close(OLE2* ole2) |
744 | 3.50k | { |
745 | 3.50k | int i; |
746 | 3.50k | if (ole2->file) |
747 | 0 | fclose(ole2->file); |
748 | | |
749 | 8.42k | for(i=0; i<ole2->files.count; ++i) { |
750 | 4.91k | free(ole2->files.file[i].name); |
751 | 4.91k | } |
752 | 3.50k | free(ole2->files.file); |
753 | 3.50k | free(ole2->SecID); |
754 | 3.50k | free(ole2->SSecID); |
755 | 3.50k | free(ole2->SSAT); |
756 | 3.50k | free(ole2); |
757 | 3.50k | } |
758 | | |
759 | | void ole2_fclose(OLE2Stream* ole2st) |
760 | 4.89k | { |
761 | 4.89k | free(ole2st->buf); |
762 | 4.89k | free(ole2st); |
763 | 4.89k | } |
764 | | |
765 | | // Return offset in bytes of a sector from its sid |
766 | | static size_t sector_pos(OLE2* ole2, DWORD sid) |
767 | 4.35M | { |
768 | 4.35M | return 512 + sid * ole2->lsector; |
769 | 4.35M | } |
770 | | // Read one sector from its sid |
771 | | static ssize_t sector_read(OLE2* ole2, void *buffer, size_t buffer_len, DWORD sid) |
772 | 4.35M | { |
773 | 4.35M | size_t num; |
774 | 4.35M | size_t seeked; |
775 | | |
776 | 4.35M | if ((seeked = ole2_fseek(ole2, sector_pos(ole2, sid))) != 0) { |
777 | 8.55k | if (xls_debug) fprintf(stderr, "Error: wanted to seek to sector %u (0x%x) loc=%u\n", sid, sid, |
778 | 0 | (unsigned int)sector_pos(ole2, sid)); |
779 | 8.55k | return -1; |
780 | 8.55k | } |
781 | | |
782 | 4.34M | if ((num = ole2_fread(ole2, buffer, buffer_len, ole2->lsector)) != 1) { |
783 | 472 | if (xls_debug) fprintf(stderr, "Error: fread wanted 1 got %lu loc=%u\n", (unsigned long)num, |
784 | 0 | (unsigned int)sector_pos(ole2, sid)); |
785 | 472 | return -1; |
786 | 472 | } |
787 | | |
788 | 4.34M | return ole2->lsector; |
789 | 4.34M | } |
790 | | |
791 | | // read first 109 sectors of MSAT from header |
792 | 3.24k | static ssize_t read_MSAT_header(OLE2* ole2, OLE2Header* oleh, DWORD sectorCount) { |
793 | 3.24k | BYTE *sector = (BYTE*)ole2->SecID; |
794 | 3.24k | ssize_t bytes_read = 0, total_bytes_read = 0; |
795 | 3.24k | size_t bytes_left = ole2->SecIDCount * sizeof(DWORD); |
796 | 3.24k | DWORD sectorNum; |
797 | | |
798 | 8.71k | for (sectorNum = 0; sectorNum < sectorCount && sectorNum < 109; sectorNum++) |
799 | 6.05k | { |
800 | 6.05k | DWORD s = oleh->MSAT[sectorNum]; |
801 | 6.05k | if (s == ENDOFCHAIN || s == FREESECT) |
802 | 455 | break; |
803 | 5.59k | if ((bytes_read = sector_read(ole2, sector, bytes_left, s)) == -1) { |
804 | 134 | if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", s); |
805 | 134 | return -1; |
806 | 134 | } |
807 | 5.46k | sector += ole2->lsector; |
808 | 5.46k | bytes_left -= ole2->lsector; |
809 | 5.46k | total_bytes_read += bytes_read; |
810 | 5.46k | } |
811 | 3.11k | return total_bytes_read; |
812 | 3.24k | } |
813 | | |
814 | | // Add additional sectors of the MSAT |
815 | 3.11k | static ssize_t read_MSAT_body(OLE2 *ole2, DWORD sectorOffset, DWORD sectorCount) { |
816 | 3.11k | DWORD sid = ole2->difstart; |
817 | 3.11k | ssize_t bytes_read = 0, total_bytes_read = 0; |
818 | 3.11k | DWORD sectorNum = sectorOffset; |
819 | | |
820 | 3.11k | DWORD *sector = ole_malloc(ole2->lsector); |
821 | 3.11k | if (sector == NULL) |
822 | 0 | return -1; |
823 | | //printf("sid=%u (0x%x) sector=%u\n", sid, sid, ole2->lsector); |
824 | 5.06k | while (sid != ENDOFCHAIN && sid != FREESECT) // FREESECT only here due to an actual file that requires it (old Apple Numbers bug) |
825 | 2.18k | { |
826 | 2.18k | int posInSector; |
827 | | // read MSAT sector |
828 | 2.18k | if ((bytes_read = sector_read(ole2, sector, ole2->lsector, sid)) == -1) { |
829 | 101 | total_bytes_read = -1; |
830 | 101 | if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", sid); |
831 | 101 | goto cleanup; |
832 | 101 | } |
833 | 2.08k | total_bytes_read += bytes_read; |
834 | | |
835 | | // read content |
836 | 254k | for (posInSector = 0; posInSector < (ole2->lsector-4)/4; posInSector++) |
837 | 252k | { |
838 | 252k | DWORD s = sector[posInSector]; |
839 | | //printf(" s[%d]=%d (0x%x)\n", posInSector, s, s); |
840 | | |
841 | 252k | if (s != ENDOFCHAIN && s != FREESECT) // see patch in Bug 31. For very large files |
842 | 190k | { |
843 | 190k | if (sectorNum == sectorCount) { |
844 | 37 | if (xls_debug) fprintf(stderr, "Error: Unable to seek to sector #%d\n", s); |
845 | 37 | total_bytes_read = -1; |
846 | 37 | goto cleanup; |
847 | 37 | } |
848 | 190k | if ((bytes_read = sector_read(ole2, (BYTE*)(ole2->SecID)+sectorNum*ole2->lsector, |
849 | 190k | (ole2->SecIDCount * sizeof(DWORD) - sectorNum*ole2->lsector), s)) == -1) { |
850 | 72 | if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", s); |
851 | 72 | total_bytes_read = -1; |
852 | 72 | goto cleanup; |
853 | 72 | } |
854 | 190k | total_bytes_read += bytes_read; |
855 | 190k | sectorNum++; |
856 | 190k | } |
857 | 252k | } |
858 | 1.97k | if (sid == sector[posInSector]) { |
859 | 30 | if (xls_debug) fprintf(stderr, "Error: Loop detected in sector #%d\n", sid); |
860 | 30 | total_bytes_read = -1; |
861 | 30 | goto cleanup; |
862 | 30 | } |
863 | 1.94k | sid = sector[posInSector]; |
864 | | //printf(" s[%d]=%d (0x%x)\n", posInSector, sid, sid); |
865 | 1.94k | } |
866 | | #ifdef OLE_DEBUG |
867 | | if(xls_debug) { |
868 | | //printf("==== READ IN SECTORS FOR MSAT TABLE====\n"); |
869 | | int i; |
870 | | for(i=0; i<512/4; ++i) { // just the first block |
871 | | if(ole2->SecID[i] != FREESECT) printf("SecID[%d]=%d\n", i, ole2->SecID[i]); |
872 | | } |
873 | | } |
874 | | //exit(0); |
875 | | #endif |
876 | | |
877 | 3.11k | cleanup: |
878 | 3.11k | free(sector); |
879 | 3.11k | return total_bytes_read; |
880 | 3.11k | } |
881 | | |
882 | | // read in short table |
883 | 2.87k | static ssize_t read_MSAT_trailer(OLE2 *ole2) { |
884 | 2.87k | ssize_t total_bytes_read = 0; |
885 | 2.87k | DWORD sector, k; |
886 | 2.87k | BYTE *wptr; |
887 | 2.87k | size_t bytes_left; |
888 | | |
889 | 2.87k | if(ole2->sfatstart == ENDOFCHAIN) |
890 | 137 | return 0; |
891 | | |
892 | 2.73k | if ((ole2->SSecID = ole_malloc(ole2->csfat*(size_t)ole2->lsector)) == NULL) { |
893 | 34 | return -1; |
894 | 34 | } |
895 | 2.70k | ole2->SSecIDCount = ole2->csfat*(size_t)ole2->lsector/4; |
896 | 2.70k | memset(ole2->SSecID, 0xFF, ole2->SSecIDCount * sizeof(DWORD)); |
897 | 2.70k | sector = ole2->sfatstart; |
898 | 2.70k | wptr=(BYTE*)ole2->SSecID; |
899 | 2.70k | bytes_left = ole2->SSecIDCount * sizeof(DWORD); |
900 | 2.06M | for(k=0; k<ole2->csfat; ++k) { |
901 | 2.06M | if (sector == ENDOFCHAIN || sector_read(ole2, wptr, bytes_left, sector) == -1) { |
902 | 77 | total_bytes_read = -1; |
903 | 77 | goto cleanup; |
904 | 77 | } |
905 | 2.06M | if (!ole2_validate_sector(sector, ole2)) { |
906 | 47 | total_bytes_read = -1; |
907 | 47 | goto cleanup; |
908 | 47 | } |
909 | 2.06M | wptr += ole2->lsector; |
910 | 2.06M | bytes_left -= ole2->lsector; |
911 | 2.06M | total_bytes_read += ole2->lsector; |
912 | 2.06M | sector = xlsIntVal(ole2->SecID[sector]); |
913 | 2.06M | } |
914 | | #ifdef OLE_DEBUG |
915 | | if(xls_debug) { |
916 | | int i; |
917 | | for(i=0; i<ole2->csfat; ++i) { |
918 | | if(ole2->SSecID[i] != FREESECT) fprintf(stderr, "SSecID[%d]=%d\n", i, ole2->SSecID[i]); |
919 | | } |
920 | | } |
921 | | #endif |
922 | | |
923 | 2.70k | cleanup: |
924 | 2.70k | return total_bytes_read; |
925 | 2.70k | } |
926 | | |
927 | | |
928 | | // Read MSAT |
929 | | static ssize_t read_MSAT(OLE2* ole2, OLE2Header* oleh) |
930 | 3.31k | { |
931 | | // reconstitution of the MSAT |
932 | 3.31k | DWORD count = ole2->cfat; |
933 | 3.31k | if(count == 0 || count > (1 << 24)) { |
934 | 35 | if (xls_debug) fprintf(stderr, "Error: MSAT count %u out-of-bounds\n", count); |
935 | 35 | return -1; |
936 | 35 | } |
937 | | |
938 | 3.27k | ssize_t total_bytes_read = 0; |
939 | 3.27k | ssize_t bytes_read = 0; |
940 | | |
941 | 3.27k | ole2->SecIDCount = count*ole2->lsector/4; |
942 | 3.27k | if ((ole2->SecID = ole_malloc(ole2->SecIDCount * sizeof(DWORD))) == NULL) { |
943 | 31 | total_bytes_read = -1; |
944 | 31 | goto cleanup; |
945 | 31 | } |
946 | 3.24k | memset(ole2->SecID, 0xFF, ole2->SecIDCount * sizeof(DWORD)); |
947 | | |
948 | 3.24k | if ((bytes_read = read_MSAT_header(ole2, oleh, count)) == -1) { |
949 | 134 | total_bytes_read = -1; |
950 | 134 | goto cleanup; |
951 | 134 | } |
952 | 3.11k | total_bytes_read += bytes_read; |
953 | | |
954 | 3.11k | if ((bytes_read = read_MSAT_body(ole2, total_bytes_read / ole2->lsector, count)) == -1) { |
955 | 240 | total_bytes_read = -1; |
956 | 240 | goto cleanup; |
957 | 240 | } |
958 | 2.87k | total_bytes_read += bytes_read; |
959 | | |
960 | 2.87k | if ((bytes_read = read_MSAT_trailer(ole2)) == -1) { |
961 | 158 | total_bytes_read = -1; |
962 | 158 | goto cleanup; |
963 | 158 | } |
964 | 2.71k | total_bytes_read += bytes_read; |
965 | | |
966 | 3.27k | cleanup: |
967 | 3.27k | if (total_bytes_read == -1) { |
968 | 563 | if (ole2->SecID) { |
969 | 532 | free(ole2->SecID); |
970 | 532 | ole2->SecID = NULL; |
971 | 532 | } |
972 | 563 | if (ole2->SSecID) { |
973 | 124 | free(ole2->SSecID); |
974 | 124 | ole2->SSecID = NULL; |
975 | 124 | } |
976 | 563 | } |
977 | | |
978 | 3.27k | return total_bytes_read; |
979 | 2.71k | } |