1 /*
2 / freexl.c
3 /
4 / FreeXL implementation
5 /
6 / version 1.0, 2011 July 26
7 /
8 / Author: Sandro Furieri a.furieri@lqt.it
9 /
10 / ------------------------------------------------------------------------------
11 /
12 / Version: MPL 1.1/GPL 2.0/LGPL 2.1
13 /
14 / The contents of this file are subject to the Mozilla Public License Version
15 / 1.1 (the "License"); you may not use this file except in compliance with
16 / the License. You may obtain a copy of the License at
17 / http://www.mozilla.org/MPL/
18 /
19 / Software distributed under the License is distributed on an "AS IS" basis,
20 / WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
21 / for the specific language governing rights and limitations under the
22 / License.
23 /
24 / The Original Code is the FreeXL library
25 /
26 / The Initial Developer of the Original Code is Alessandro Furieri
27 /
28 / Portions created by the Initial Developer are Copyright (C) 2011
29 / the Initial Developer. All Rights Reserved.
30 /
31 / Contributor(s):
32 / Brad Hards
33 /
34 / Alternatively, the contents of this file may be used under the terms of
35 / either the GNU General Public License Version 2 or later (the "GPL"), or
36 / the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
37 / in which case the provisions of the GPL or the LGPL are applicable instead
38 / of those above. If you wish to allow use of your version of this file only
39 / under the terms of either the GPL or the LGPL, and not to allow others to
40 / use your version of this file under the terms of the MPL, indicate your
41 / decision by deleting the provisions above and replace them with the notice
42 / and other provisions required by the GPL or the LGPL. If you do not delete
43 / the provisions above, a recipient may use your version of this file under
44 / the terms of any one of the MPL, the GPL or the LGPL.
45 /
46 */
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <math.h>
51
52 #if defined(__MINGW32__) || defined(_WIN32)
53 #define LIBICONV_STATIC
54 #include <iconv.h>
55 #define LIBCHARSET_STATIC
56 #ifdef _MSC_VER
57 /* <localcharset.h> isn't supported on OSGeo4W */
58 /* applying a tricky workaround to fix this issue */
59 extern const char *locale_charset (void);
60 #else /* sane Windows - not OSGeo4W */
61 #include <localcharset.h>
62 #endif /* end localcharset */
63 #else /* not WINDOWS */
64 #if defined(__APPLE__) || defined(__ANDROID__)
65 #include <iconv.h>
66 #include <localcharset.h>
67 #else /* neither Mac OsX nor Android */
68 #include <iconv.h>
69 #include <langinfo.h>
70 #endif
71 #endif
72
73 #if defined(_WIN32) && !defined(__MINGW32__)
74 #include "config-msvc.h"
75 #else
76 #include "config.h"
77 #endif
78
79 #include "freexl.h"
80 #include "freexl_internals.h"
81
82
83 const char *freexlversion = VERSION;
84
85 FREEXL_DECLARE const char *
freexl_version(void)86 freexl_version (void)
87 {
88 /* return the library version number */
89 return freexlversion;
90 }
91
92 #if defined(_WIN32) && !defined(__MINGW32__) && _MSC_VER < 1800
93 /* obsolete MSVC compiler doesn't support lround() at all */
94 static double
round(double num)95 round (double num)
96 {
97 double integer = ceil (num);
98 if (num > 0)
99 return integer - num > 0.5 ? integer - 1.0 : integer;
100 return integer - num >= 0.5 ? integer - 1.0 : integer;
101 }
102
103 static long
lround(double num)104 lround (double num)
105 {
106 long integer = (long) round (num);
107 return integer;
108 }
109 #endif
110
111 static void
swap16(biff_word16 * word)112 swap16 (biff_word16 * word)
113 {
114 /* Endianness: swapping a 16 bit word */
115 unsigned char save = word->bytes[0];
116 word->bytes[0] = word->bytes[1];
117 word->bytes[1] = save;
118 }
119
120 static void
swap32(biff_word32 * word)121 swap32 (biff_word32 * word)
122 {
123 /* Endianness: swapping a 32 bit word */
124 unsigned char save0 = word->bytes[0];
125 unsigned char save1 = word->bytes[1];
126 unsigned char save2 = word->bytes[2];
127 word->bytes[0] = word->bytes[3];
128 word->bytes[1] = save2;
129 word->bytes[2] = save1;
130 word->bytes[3] = save0;
131 }
132
133 static void
swap_float(biff_float * word)134 swap_float (biff_float * word)
135 {
136 /* Endianness: swapping a 64 bit float */
137 unsigned char save0 = word->bytes[0];
138 unsigned char save1 = word->bytes[1];
139 unsigned char save2 = word->bytes[2];
140 unsigned char save3 = word->bytes[3];
141 unsigned char save4 = word->bytes[4];
142 unsigned char save5 = word->bytes[5];
143 unsigned char save6 = word->bytes[6];
144 word->bytes[0] = word->bytes[7];
145 word->bytes[1] = save6;
146 word->bytes[2] = save5;
147 word->bytes[3] = save4;
148 word->bytes[4] = save3;
149 word->bytes[5] = save2;
150 word->bytes[6] = save1;
151 word->bytes[7] = save0;
152 }
153
154 static int
biff_set_utf8_converter(biff_workbook * workbook)155 biff_set_utf8_converter (biff_workbook * workbook)
156 {
157 /* attempting to set up a charset converter to UTF-8 */
158 iconv_t cvt = (iconv_t) (-1);
159 if (workbook->utf8_converter)
160 iconv_close (workbook->utf8_converter);
161 workbook->utf8_converter = NULL;
162 switch (workbook->biff_code_page)
163 {
164 case 0x016F:
165 cvt = iconv_open ("UTF-8", "ASCII");
166 break;
167 case 0x01B5:
168 cvt = iconv_open ("UTF-8", "CP437");
169 break;
170 case 0x02D0:
171 cvt = iconv_open ("UTF-8", "CP720");
172 break;
173 case 0x02E1:
174 cvt = iconv_open ("UTF-8", "CP737");
175 break;
176 case 0x0307:
177 cvt = iconv_open ("UTF-8", "CP775");
178 break;
179 case 0x0352:
180 cvt = iconv_open ("UTF-8", "CP850");
181 break;
182 case 0x0354:
183 cvt = iconv_open ("UTF-8", "CP852");
184 break;
185 case 0x0357:
186 cvt = iconv_open ("UTF-8", "CP855");
187 break;
188 case 0x0359:
189 cvt = iconv_open ("UTF-8", "CP857");
190 break;
191 case 0x035A:
192 cvt = iconv_open ("UTF-8", "CP858");
193 break;
194 case 0x035C:
195 cvt = iconv_open ("UTF-8", "CP860");
196 break;
197 case 0x035D:
198 cvt = iconv_open ("UTF-8", "CP861");
199 break;
200 case 0x035E:
201 cvt = iconv_open ("UTF-8", "CP862");
202 break;
203 case 0x035F:
204 cvt = iconv_open ("UTF-8", "CP863");
205 break;
206 case 0x0360:
207 cvt = iconv_open ("UTF-8", "CP864");
208 break;
209 case 0x0361:
210 cvt = iconv_open ("UTF-8", "CP865");
211 break;
212 case 0x0362:
213 cvt = iconv_open ("UTF-8", "CP866");
214 break;
215 case 0x0365:
216 cvt = iconv_open ("UTF-8", "CP869");
217 break;
218 case 0x036A:
219 cvt = iconv_open ("UTF-8", "CP874");
220 break;
221 case 0x03A4:
222 cvt = iconv_open ("UTF-8", "CP932");
223 break;
224 case 0x03A8:
225 cvt = iconv_open ("UTF-8", "CP936");
226 break;
227 case 0x03B5:
228 cvt = iconv_open ("UTF-8", "CP949");
229 break;
230 case 0x03B6:
231 cvt = iconv_open ("UTF-8", "CP950");
232 break;
233 case 0x04B0:
234 cvt = iconv_open ("UTF-8", "UTF-16LE");
235 break;
236 case 0x04E2:
237 cvt = iconv_open ("UTF-8", "CP1250");
238 break;
239 case 0x04E3:
240 cvt = iconv_open ("UTF-8", "CP1251");
241 break;
242 case 0x04E4:
243 case 0x8001:
244 cvt = iconv_open ("UTF-8", "CP1252");
245 break;
246 case 0x04E5:
247 cvt = iconv_open ("UTF-8", "CP1253");
248 break;
249 case 0x04E6:
250 cvt = iconv_open ("UTF-8", "CP1254");
251 break;
252 case 0x04E7:
253 cvt = iconv_open ("UTF-8", "CP1255");
254 break;
255 case 0x04E8:
256 cvt = iconv_open ("UTF-8", "CP1256");
257 break;
258 case 0x04E9:
259 cvt = iconv_open ("UTF-8", "CP1257");
260 break;
261 case 0x04EA:
262 cvt = iconv_open ("UTF-8", "CP1258");
263 break;
264 case 0x0551:
265 cvt = iconv_open ("UTF-8", "CP1361");
266 break;
267 case 0x2710:
268 case 0x8000:
269 cvt = iconv_open ("UTF-8", "MacRoman");
270 break;
271 };
272 if (cvt == (iconv_t) (-1))
273 return 0;
274 workbook->utf8_converter = cvt;
275 return 1;
276 }
277
278 static char *
convert_to_utf8(iconv_t converter,const char * buf,int buflen,int * err)279 convert_to_utf8 (iconv_t converter, const char *buf, int buflen, int *err)
280 {
281 /* converting a string to UTF8 */
282 char *utf8buf = 0;
283 #if !defined(__MINGW32__) && defined(_WIN32)
284 const char *pBuf;
285 #else
286 char *pBuf;
287 #endif
288 size_t len;
289 size_t utf8len;
290 int maxlen = (buflen * 4) + 1;
291 char *pUtf8buf;
292 *err = FREEXL_OK;
293 if (!converter)
294 {
295 *err = FREEXL_UNSUPPORTED_CHARSET;
296 return NULL;
297 }
298 utf8buf = malloc (maxlen);
299 len = buflen;
300 utf8len = maxlen;
301 pBuf = (char *) buf;
302 pUtf8buf = utf8buf;
303 if (iconv (converter, &pBuf, &len, &pUtf8buf, &utf8len) == (size_t) (-1))
304 {
305 free (utf8buf);
306 *err = FREEXL_INVALID_CHARACTER;
307 return NULL;
308 }
309 utf8buf[maxlen - utf8len] = '\0';
310 return utf8buf;
311 }
312
313 static void
get_unicode_params(unsigned char * addr,int swap,unsigned int * start_offset,int * real_utf16,unsigned int * extra_skip)314 get_unicode_params (unsigned char *addr, int swap, unsigned int *start_offset,
315 int *real_utf16, unsigned int *extra_skip)
316 {
317 /* retrieving Unicode string params */
318 biff_word16 word16;
319 biff_word32 word32;
320 int skip_1 = 0;
321 int skip_2 = 0;
322 unsigned char *p_string = addr;
323 unsigned char mask = *p_string;
324
325 /*
326 * a bitwise mask
327 * 0x01 - the string is 'real' UTF16LE
328 * otherwise any high-order ZEROes are suppressed
329 * ['stripped' UTF16]
330 *
331 * 0x04 - an extra 32-bit field is present
332 * 0x08 - another extra 16-bit field is present
333 * (such extra (optional) fields are intended by MS
334 * for text formatting purposes: we'll ignore them
335 * at all, simply adjusting any offset as required)
336 */
337 p_string++;
338 if ((mask & 0x01) == 0x01)
339 *real_utf16 = 1;
340 else
341 *real_utf16 = 0;
342
343 if ((mask & 0x08) == 0x08)
344 {
345 /* optional field 16-bits */
346 memcpy (word16.bytes, p_string, 2);
347 if (swap)
348 swap16 (&word16);
349 skip_2 = word16.value;
350 p_string += 2;
351 }
352 if ((mask & 0x04) == 0x04)
353 {
354 /* optional field: 32-bits */
355 memcpy (word32.bytes, p_string, 4);
356 if (swap)
357 swap32 (&word32);
358 skip_1 = word32.value;
359 p_string += 4;
360 }
361 *start_offset = p_string - addr;
362 *extra_skip = skip_1 + (skip_2 * 4);
363 }
364
365 static int
parse_unicode_string(iconv_t converter,unsigned short characters,int real_utf16,unsigned char * unicode_string,char ** utf8_string)366 parse_unicode_string (iconv_t converter, unsigned short characters,
367 int real_utf16, unsigned char *unicode_string,
368 char **utf8_string)
369 {
370 /* attemping to convert an Unicode string into UTF-8 */
371 unsigned int len = characters * 2;
372 char *string;
373 int err;
374 unsigned char *p_string = unicode_string;
375
376 string = malloc (len);
377 if (!real_utf16)
378 {
379 /* 'stripped' UTF-16: requires padding */
380 unsigned int i;
381 for (i = 0; i < characters; i++)
382 {
383 *(string + (i * 2)) = *p_string;
384 p_string++;
385 *(string + ((i * 2) + 1)) = 0x00;
386 }
387 }
388 else
389 {
390 /* already encoded as UTF-16 */
391 memcpy (string, p_string, len);
392 }
393 /* converting text to UTF-8 */
394 *utf8_string = convert_to_utf8 (converter, string, len, &err);
395 free (string);
396 if (err)
397 return 0;
398 return 1;
399 }
400
401 static int
decode_rk_integer(unsigned char * bytes,int * value,int swap)402 decode_rk_integer (unsigned char *bytes, int *value, int swap)
403 {
404 /* attempting to decode an RK value as an INT-32 */
405 biff_word32 word32;
406 unsigned char mask = bytes[0];
407 if ((mask & 0x02) == 0x02 && (mask & 0x01) == 0x00)
408 {
409 /* ok, this RK value is an INT-32 */
410 memcpy (word32.bytes, bytes, 4);
411 if (swap)
412 swap32 (&word32);
413 *value = word32.signed_value >> 2; /* right shift: 2 bits */
414 return 1;
415 }
416 return 0;
417 }
418
419 static int
decode_rk_float(unsigned char * bytes,double * value,int swap)420 decode_rk_float (unsigned char *bytes, double *value, int swap)
421 {
422 /* attempting to decode an RK value as a DOUBLE-FLOAT */
423 biff_word32 word32;
424 biff_float word_float;
425 int int_value;
426 double dbl_value;
427 int div_by_100 = 0;
428 unsigned char mask = bytes[0];
429 if ((mask & 0x02) == 0x02 && (mask & 0x01) == 0x01)
430 {
431 /* ok, this RK value is an INT-32 (divided by 100) */
432 memcpy (word32.bytes, bytes, 4);
433 if (swap)
434 swap32 (&word32);
435 int_value = word32.signed_value >> 2; /* right shift: 2 bits */
436 *value = (double) int_value / 100.0;
437 return 1;
438 }
439 if ((mask & 0x02) == 0x00)
440 {
441 /* ok, this RK value is a FLOAT */
442 if ((mask & 0x01) == 0x01)
443 div_by_100 = 1;
444 memcpy (word32.bytes, bytes, 4);
445 if (swap)
446 swap32 (&word32);
447 int_value = word32.value;
448 int_value &= 0xfffffffc;
449 word32.value = int_value;
450 memset (word_float.bytes, '\0', 8);
451 if (swap)
452 memcpy (word_float.bytes, word32.bytes, 4);
453 else
454 memcpy (word_float.bytes + 4, word32.bytes, 4);
455 dbl_value = word_float.value;
456 if (div_by_100)
457 dbl_value /= 100.0;
458 *value = dbl_value;
459 return 1;
460 }
461 return 0;
462 }
463
464 static int
check_xf_datetime(biff_workbook * workbook,unsigned short xf_index,int * is_date,int * is_datetime,int * is_time)465 check_xf_datetime (biff_workbook * workbook, unsigned short xf_index,
466 int *is_date, int *is_datetime, int *is_time)
467 {
468 /* testing for DATE/DATETIME/TIME formats */
469 unsigned short idx;
470 unsigned short format_index;
471 if (xf_index >= workbook->biff_xf_next_index)
472 return 0;
473 format_index = workbook->biff_xf_array[xf_index];
474 for (idx = 0; idx < workbook->max_format_index; idx++)
475 {
476 biff_format *format = workbook->format_array + idx;
477 if (format->format_index == format_index)
478 {
479 *is_date = format->is_date;
480 *is_datetime = format->is_datetime;
481 *is_time = format->is_time;
482 return 1;
483 }
484 }
485 *is_date = 0;
486 *is_datetime = 0;
487 *is_time = 0;
488 return 1;
489 }
490
491 static int
check_xf_datetime_58(biff_workbook * workbook,unsigned short xf_index,int * is_date,int * is_datetime,int * is_time)492 check_xf_datetime_58 (biff_workbook * workbook, unsigned short xf_index,
493 int *is_date, int *is_datetime, int *is_time)
494 {
495 /*
496 / testing for DATE/DATETIME/TIME formats
497 / BIFF5 and BIFF8 versions
498 */
499 unsigned short format_index;
500 if (xf_index >= workbook->biff_xf_next_index)
501 return 0;
502 format_index = workbook->biff_xf_array[xf_index];
503 switch (format_index)
504 {
505 case 14:
506 case 15:
507 case 16:
508 case 17:
509 /* BIFF5/BIFF8 built-in DATE formats */
510 *is_date = 1;
511 *is_datetime = 0;
512 *is_time = 0;
513 return 1;
514 case 18:
515 case 19:
516 case 20:
517 case 21:
518 case 45:
519 case 46:
520 case 47:
521 /* BIFF5/BIFF8 built-in TIME formats */
522 *is_date = 0;
523 *is_datetime = 0;
524 *is_time = 1;
525 return 1;
526 case 22:
527 /* BIFF5/BIFF8 built-in DATETIME formats */
528 *is_date = 0;
529 *is_datetime = 1;
530 *is_time = 0;
531 return 1;
532 default:
533 break;
534 };
535 return check_xf_datetime (workbook, xf_index, is_date, is_datetime,
536 is_time);
537 }
538
539 static void
compute_time(int * hh,int * mm,int * ss,double percent)540 compute_time (int *hh, int *mm, int *ss, double percent)
541 {
542 /* computing an Excel time */
543 int hours;
544 int mins;
545 int secs;
546 double day_seconds = 24 * 60 * 60;
547 day_seconds *= percent;
548 secs = lround (day_seconds);
549 hours = secs / 3600;
550 secs -= hours * 3600;
551 mins = secs / 60;
552 secs -= mins * 60;
553 *hh = hours;
554 *mm = mins;
555 *ss = secs;
556 }
557
558 static void
compute_date(int * year,int * month,int * day,int count)559 compute_date (int *year, int *month, int *day, int count)
560 {
561 /* coumputing an Excel date */
562 int i;
563 int yy = *year;
564 int mm = *month;
565 int dd = *day;
566 for (i = 1; i < count; i++)
567 {
568 int last_day_of_month;
569 switch (mm)
570 {
571 case 2:
572 if ((yy % 4) == 0)
573 {
574 /* February, leap year */
575 last_day_of_month = 29;
576 }
577 else
578 last_day_of_month = 28;
579 break;
580 case 4:
581 case 6:
582 case 9:
583 case 11:
584 last_day_of_month = 30;
585 break;
586 default:
587 last_day_of_month = 31;
588 break;
589 };
590 if (dd == last_day_of_month)
591 {
592 if (mm == 12)
593 {
594 mm = 1;
595 yy += 1;
596 }
597 else
598 mm += 1;
599 dd = 1;
600 }
601 else
602 dd += 1;
603 }
604 *year = yy;
605 *month = mm;
606 *day = dd;
607 }
608
609 static int
set_date_int_value(biff_workbook * workbook,unsigned int row,unsigned short col,unsigned short mode,int num)610 set_date_int_value (biff_workbook * workbook, unsigned int row,
611 unsigned short col, unsigned short mode, int num)
612 {
613 /* setting a DATE value to some cell */
614 biff_cell_value *p_cell;
615 char *string;
616 char buf[64];
617 unsigned int len;
618 int yy;
619 int mm;
620 int dd;
621 int count = num;
622
623 if (workbook->active_sheet == NULL)
624 return FREEXL_ILLEGAL_CELL_ROW_COL;
625 if (workbook->active_sheet->cell_values == NULL)
626 return FREEXL_ILLEGAL_CELL_ROW_COL;
627 if (row >= workbook->active_sheet->rows
628 || col >= workbook->active_sheet->columns)
629 return FREEXL_ILLEGAL_CELL_ROW_COL;
630
631 if (mode)
632 {
633 yy = 1904;
634 mm = 1;
635 dd = 2;
636 }
637 else
638 {
639 yy = 1900;
640 mm = 1;
641 dd = 1;
642 }
643 compute_date (&yy, &mm, &dd, count);
644 sprintf (buf, "%04d-%02d-%02d", yy, mm, dd);
645 len = strlen (buf);
646 string = malloc (len + 1);
647 if (!string)
648 return FREEXL_INSUFFICIENT_MEMORY;
649 strcpy (string, buf);
650
651 p_cell =
652 workbook->active_sheet->cell_values +
653 (row * workbook->active_sheet->columns) + col;
654 p_cell->type = FREEXL_CELL_DATE;
655 p_cell->value.text_value = string;
656 return FREEXL_OK;
657 }
658
659 static int
set_datetime_int_value(biff_workbook * workbook,unsigned int row,unsigned short col,unsigned short mode,int num)660 set_datetime_int_value (biff_workbook * workbook, unsigned int row,
661 unsigned short col, unsigned short mode, int num)
662 {
663 /* setting a DATETIME value to some cell */
664 biff_cell_value *p_cell;
665 char *string;
666 char buf[64];
667 unsigned int len;
668 int yy;
669 int mm;
670 int dd;
671 int count = num;
672
673 if (workbook->active_sheet == NULL)
674 return FREEXL_ILLEGAL_CELL_ROW_COL;
675 if (workbook->active_sheet->cell_values == NULL)
676 return FREEXL_ILLEGAL_CELL_ROW_COL;
677 if (row >= workbook->active_sheet->rows
678 || col >= workbook->active_sheet->columns)
679 return FREEXL_ILLEGAL_CELL_ROW_COL;
680
681 if (mode)
682 {
683 yy = 1904;
684 mm = 1;
685 dd = 2;
686 }
687 else
688 {
689 yy = 1900;
690 mm = 1;
691 dd = 1;
692 }
693 compute_date (&yy, &mm, &dd, count);
694 sprintf (buf, "%04d-%02d-%02d 00:00:00", yy, mm, dd);
695 len = strlen (buf);
696 string = malloc (len + 1);
697 if (!string)
698 return FREEXL_INSUFFICIENT_MEMORY;
699 strcpy (string, buf);
700
701 p_cell =
702 workbook->active_sheet->cell_values +
703 (row * workbook->active_sheet->columns) + col;
704 p_cell->type = FREEXL_CELL_DATETIME;
705 p_cell->value.text_value = string;
706 return FREEXL_OK;
707 }
708
709 static int
set_date_double_value(biff_workbook * workbook,unsigned int row,unsigned short col,unsigned short mode,double num)710 set_date_double_value (biff_workbook * workbook, unsigned int row,
711 unsigned short col, unsigned short mode, double num)
712 {
713 /* setting a DATE value to some cell */
714 biff_cell_value *p_cell;
715 char *string;
716 char buf[64];
717 unsigned int len;
718 int yy;
719 int mm;
720 int dd;
721 int count = (int) floor (num);
722
723 if (workbook->active_sheet == NULL)
724 return FREEXL_ILLEGAL_CELL_ROW_COL;
725 if (workbook->active_sheet->cell_values == NULL)
726 return FREEXL_ILLEGAL_CELL_ROW_COL;
727 if (row >= workbook->active_sheet->rows
728 || col >= workbook->active_sheet->columns)
729 return FREEXL_ILLEGAL_CELL_ROW_COL;
730
731 if (mode)
732 {
733 yy = 1904;
734 mm = 1;
735 dd = 2;
736 }
737 else
738 {
739 yy = 1900;
740 mm = 1;
741 dd = 1;
742 }
743 compute_date (&yy, &mm, &dd, count);
744 sprintf (buf, "%04d-%02d-%02d", yy, mm, dd);
745 len = strlen (buf);
746 string = malloc (len + 1);
747 if (!string)
748 return FREEXL_INSUFFICIENT_MEMORY;
749 strcpy (string, buf);
750
751 p_cell =
752 workbook->active_sheet->cell_values +
753 (row * workbook->active_sheet->columns) + col;
754 p_cell->type = FREEXL_CELL_DATE;
755 p_cell->value.text_value = string;
756 return FREEXL_OK;
757 }
758
759 static int
set_datetime_double_value(biff_workbook * workbook,unsigned int row,unsigned short col,unsigned short mode,double num)760 set_datetime_double_value (biff_workbook * workbook, unsigned int row,
761 unsigned short col, unsigned short mode, double num)
762 {
763 /* setting a DATETIME value to some cell */
764 biff_cell_value *p_cell;
765 char *string;
766 char buf[64];
767 unsigned int len;
768 int yy;
769 int mm;
770 int dd;
771 int h;
772 int m;
773 int s;
774 int count = (int) floor (num);
775 double percent = num - (double) count;
776
777 if (workbook->active_sheet == NULL)
778 return FREEXL_ILLEGAL_CELL_ROW_COL;
779 if (workbook->active_sheet->cell_values == NULL)
780 return FREEXL_ILLEGAL_CELL_ROW_COL;
781 if (row >= workbook->active_sheet->rows
782 || col >= workbook->active_sheet->columns)
783 return FREEXL_ILLEGAL_CELL_ROW_COL;
784
785 if (mode)
786 {
787 yy = 1904;
788 mm = 1;
789 dd = 2;
790 }
791 else
792 {
793 yy = 1900;
794 mm = 1;
795 dd = 1;
796 }
797 compute_date (&yy, &mm, &dd, count);
798 compute_time (&h, &m, &s, percent);
799 sprintf (buf, "%04d-%02d-%02d %02d:%02d:%02d", yy, mm, dd, h, m, s);
800 len = strlen (buf);
801 string = malloc (len + 1);
802 if (!string)
803 return FREEXL_INSUFFICIENT_MEMORY;
804 strcpy (string, buf);
805
806 p_cell =
807 workbook->active_sheet->cell_values +
808 (row * workbook->active_sheet->columns) + col;
809 p_cell->type = FREEXL_CELL_DATETIME;
810 p_cell->value.text_value = string;
811 return FREEXL_OK;
812 }
813
814 static int
set_time_double_value(biff_workbook * workbook,unsigned int row,unsigned short col,double num)815 set_time_double_value (biff_workbook * workbook, unsigned int row,
816 unsigned short col, double num)
817 {
818 /* setting a TIME value to some cell */
819 biff_cell_value *p_cell;
820 char *string;
821 char buf[64];
822 unsigned int len;
823 int h;
824 int m;
825 int s;
826 int count = (int) floor (num);
827 double percent = num - (double) count;
828
829 if (workbook->active_sheet == NULL)
830 return FREEXL_ILLEGAL_CELL_ROW_COL;
831 if (workbook->active_sheet->cell_values == NULL)
832 return FREEXL_ILLEGAL_CELL_ROW_COL;
833 if (row >= workbook->active_sheet->rows
834 || col >= workbook->active_sheet->columns)
835 return FREEXL_ILLEGAL_CELL_ROW_COL;
836
837 compute_time (&h, &m, &s, percent);
838 sprintf (buf, "%02d:%02d:%02d", h, m, s);
839 len = strlen (buf);
840 string = malloc (len + 1);
841 if (!string)
842 return FREEXL_INSUFFICIENT_MEMORY;
843 strcpy (string, buf);
844
845 p_cell =
846 workbook->active_sheet->cell_values +
847 (row * workbook->active_sheet->columns) + col;
848 p_cell->type = FREEXL_CELL_TIME;
849 p_cell->value.text_value = string;
850 return FREEXL_OK;
851 }
852
853 static int
set_int_value(biff_workbook * workbook,unsigned int row,unsigned short col,int num)854 set_int_value (biff_workbook * workbook, unsigned int row, unsigned short col,
855 int num)
856 {
857 /* setting an INTEGER value to some cell */
858 biff_cell_value *p_cell;
859
860 if (workbook->active_sheet == NULL)
861 return FREEXL_ILLEGAL_CELL_ROW_COL;
862 if (workbook->active_sheet->cell_values == NULL)
863 return FREEXL_ILLEGAL_CELL_ROW_COL;
864 if (row >= workbook->active_sheet->rows
865 || col >= workbook->active_sheet->columns)
866 return FREEXL_ILLEGAL_CELL_ROW_COL;
867
868 p_cell =
869 workbook->active_sheet->cell_values +
870 (row * workbook->active_sheet->columns) + col;
871 p_cell->type = FREEXL_CELL_INT;
872 p_cell->value.int_value = num;
873 return FREEXL_OK;
874 }
875
876 static int
set_double_value(biff_workbook * workbook,unsigned int row,unsigned short col,double num)877 set_double_value (biff_workbook * workbook, unsigned int row,
878 unsigned short col, double num)
879 {
880 /* setting a DOUBLE value to some cell */
881 biff_cell_value *p_cell;
882
883 if (workbook->active_sheet == NULL)
884 return FREEXL_ILLEGAL_CELL_ROW_COL;
885 if (workbook->active_sheet->cell_values == NULL)
886 return FREEXL_ILLEGAL_CELL_ROW_COL;
887 if (row >= workbook->active_sheet->rows
888 || col >= workbook->active_sheet->columns)
889 return FREEXL_ILLEGAL_CELL_ROW_COL;
890
891 p_cell =
892 workbook->active_sheet->cell_values +
893 (row * workbook->active_sheet->columns) + col;
894 p_cell->type = FREEXL_CELL_DOUBLE;
895 p_cell->value.dbl_value = num;
896 return FREEXL_OK;
897 }
898
899 static int
set_text_value(biff_workbook * workbook,unsigned int row,unsigned short col,char * text)900 set_text_value (biff_workbook * workbook, unsigned int row, unsigned short col,
901 char *text)
902 {
903 /* setting a TEXT value to some cell */
904 biff_cell_value *p_cell;
905
906 if (workbook->active_sheet == NULL)
907 return FREEXL_ILLEGAL_CELL_ROW_COL;
908 if (workbook->active_sheet->cell_values == NULL)
909 return FREEXL_ILLEGAL_CELL_ROW_COL;
910 if (row >= workbook->active_sheet->rows
911 || col >= workbook->active_sheet->columns)
912 return FREEXL_ILLEGAL_CELL_ROW_COL;
913
914 p_cell =
915 workbook->active_sheet->cell_values +
916 (row * workbook->active_sheet->columns) + col;
917 if (!text)
918 {
919 p_cell->type = FREEXL_CELL_NULL;
920 return FREEXL_OK;
921 }
922 p_cell->type = FREEXL_CELL_TEXT;
923 p_cell->value.text_value = text;
924 return FREEXL_OK;
925 }
926
927 static int
set_sst_value(biff_workbook * workbook,unsigned int row,unsigned short col,const char * text)928 set_sst_value (biff_workbook * workbook, unsigned int row, unsigned short col,
929 const char *text)
930 {
931 /* setting an SST-TEXT value to some cell */
932 biff_cell_value *p_cell;
933
934 if (workbook->active_sheet == NULL)
935 return FREEXL_ILLEGAL_CELL_ROW_COL;
936 if (workbook->active_sheet->cell_values == NULL)
937 return FREEXL_ILLEGAL_CELL_ROW_COL;
938 if (row >= workbook->active_sheet->rows
939 || col >= workbook->active_sheet->columns)
940 return FREEXL_ILLEGAL_CELL_ROW_COL;
941
942 p_cell =
943 workbook->active_sheet->cell_values +
944 (row * workbook->active_sheet->columns) + col;
945 if (!text)
946 {
947 p_cell->type = FREEXL_CELL_NULL;
948 return FREEXL_OK;
949 }
950 p_cell->type = FREEXL_CELL_SST_TEXT;
951 p_cell->value.sst_value = text;
952 return FREEXL_OK;
953 }
954
955 static size_t
xls_fread(size_t bufsz,void * buf,size_t size,size_t nmemb,FILE * fl)956 xls_fread (size_t bufsz, void *buf, size_t size, size_t nmemb, FILE * fl)
957 {
958 /*
959 / Sandro 2017-09-07
960 / secure version of "fread" checking against buffer overflows
961 /---------------------------
962 / expected to fix the issue reported by
963 / Cisco [TALOS-2017-431]
964 */
965 if ((size * nmemb) > bufsz)
966 return 0;
967 return fread (buf, size, nmemb, fl);
968 }
969
970 static fat_chain *
alloc_fat_chain(int swap,unsigned short sector_shift,unsigned int directory_start)971 alloc_fat_chain (int swap, unsigned short sector_shift,
972 unsigned int directory_start)
973 {
974 /* allocating the FAT chain */
975 fat_chain *chain = malloc (sizeof (fat_chain));
976 if (!chain)
977 return NULL;
978 chain->swap = swap;
979 if (sector_shift == 12)
980 chain->sector_size = 4096;
981 else
982 chain->sector_size = 512;
983 chain->next_sector = 0;
984 chain->directory_start = directory_start;
985 chain->first = NULL;
986 chain->last = NULL;
987 chain->fat_array = NULL;
988 chain->fat_array_count = 0;
989 chain->miniCutOff = 0;
990 chain->next_sectorMini = 0;
991 chain->firstMini = NULL;
992 chain->lastMini = NULL;
993 chain->miniFAT_array = NULL;
994 chain->miniFAT_array_count = 0;
995 chain->miniFAT_len = 0;
996 chain->miniStream = NULL;
997 return chain;
998 }
999
1000 static void
destroy_fat_chain(fat_chain * chain)1001 destroy_fat_chain (fat_chain * chain)
1002 {
1003 /* destroying a FAT chain */
1004 fat_entry *entry;
1005 fat_entry *entry_n;
1006 if (!chain)
1007 return;
1008 /* destroying the main FAT */
1009 entry = chain->first;
1010 while (entry)
1011 {
1012 entry_n = entry->next;
1013 free (entry);
1014 entry = entry_n;
1015 }
1016 if (chain->fat_array)
1017 free (chain->fat_array);
1018 /* destroying the miniFAT */
1019 entry = chain->firstMini;
1020 while (entry)
1021 {
1022 entry_n = entry->next;
1023 free (entry);
1024 entry = entry_n;
1025 }
1026 if (chain->miniFAT_array)
1027 free (chain->miniFAT_array);
1028 if (chain->miniStream)
1029 free (chain->miniStream);
1030 free (chain);
1031 }
1032
1033 static unsigned int
get_worksheet_count(biff_workbook * workbook)1034 get_worksheet_count (biff_workbook * workbook)
1035 {
1036 /* counting how many Worksheet are into the Workbook */
1037 unsigned int count = 0;
1038 biff_sheet *p_sheet = workbook->first_sheet;
1039 while (p_sheet)
1040 {
1041 count++;
1042 p_sheet = p_sheet->next;
1043 }
1044 return count;
1045 }
1046
1047 static void
destroy_cell(biff_cell_value * cell)1048 destroy_cell (biff_cell_value * cell)
1049 {
1050 /* destroying a cell */
1051 if (cell->type == FREEXL_CELL_TEXT || cell->type == FREEXL_CELL_DATE
1052 || cell->type == FREEXL_CELL_DATETIME || cell->type == FREEXL_CELL_TIME)
1053 {
1054 if (cell->value.text_value)
1055 free (cell->value.text_value);
1056 }
1057 }
1058
1059 static void
destroy_sheet(biff_sheet * sheet)1060 destroy_sheet (biff_sheet * sheet)
1061 {
1062 /* destroying a Sheet struct */
1063 unsigned int row;
1064 unsigned int col;
1065 biff_cell_value *p_cell;
1066
1067 if (!sheet)
1068 return;
1069 if (sheet->utf8_name)
1070 free (sheet->utf8_name);
1071 if (sheet->cell_values)
1072 {
1073 for (row = 0; row < sheet->rows; row++)
1074 {
1075 /* destroying rows */
1076 p_cell = sheet->cell_values + (row * sheet->columns);
1077 for (col = 0; col < sheet->columns; col++)
1078 {
1079 /* destroying cells */
1080 destroy_cell (p_cell);
1081 p_cell++;
1082 }
1083 }
1084 }
1085 free (sheet->cell_values);
1086 free (sheet);
1087 }
1088
1089 static int
allocate_cells(biff_workbook * workbook)1090 allocate_cells (biff_workbook * workbook)
1091 {
1092 /* allocating the rows and cells for the active Worksheet */
1093 unsigned int row;
1094 unsigned int col;
1095 double dsize;
1096 biff_cell_value *p_cell;
1097
1098 if (workbook == NULL)
1099 return FREEXL_NULL_ARGUMENT;
1100 if (workbook->active_sheet == NULL)
1101 return FREEXL_NULL_ARGUMENT;
1102
1103 /* testing for an unrealistically high memory size > 256MB */
1104 dsize =
1105 (double) sizeof (biff_cell_value) *
1106 (double) (workbook->active_sheet->rows) *
1107 (double) (workbook->active_sheet->columns);
1108 if (dsize > 256.0 * 1024.0 * 1024.0)
1109 return FREEXL_INSUFFICIENT_MEMORY;
1110
1111 /* allocating the cell values array */
1112 if (workbook->active_sheet->rows * workbook->active_sheet->columns <= 0)
1113 {
1114 workbook->active_sheet->cell_values = NULL;
1115 return FREEXL_OK;
1116 }
1117 workbook->active_sheet->cell_values =
1118 malloc (sizeof (biff_cell_value) *
1119 (workbook->active_sheet->rows *
1120 workbook->active_sheet->columns));
1121 if (workbook->active_sheet->cell_values == NULL)
1122 return FREEXL_INSUFFICIENT_MEMORY;
1123 for (row = 0; row < workbook->active_sheet->rows; row++)
1124 {
1125 /* initializing NULL cell values */
1126 p_cell =
1127 workbook->active_sheet->cell_values +
1128 (row * workbook->active_sheet->columns);
1129 for (col = 0; col < workbook->active_sheet->columns; col++)
1130 {
1131 p_cell->type = FREEXL_CELL_NULL;
1132 p_cell++;
1133 }
1134 }
1135
1136 return FREEXL_OK;
1137 }
1138
1139 static int
add_sheet_to_workbook(biff_workbook * workbook,unsigned int offset,unsigned char visible,unsigned char type,char * name)1140 add_sheet_to_workbook (biff_workbook * workbook, unsigned int offset,
1141 unsigned char visible, unsigned char type, char *name)
1142 {
1143 /* appending a further Sheet to the Workbook */
1144 biff_sheet *sheet = malloc (sizeof (biff_sheet));
1145 if (!sheet)
1146 return 0;
1147 sheet->start_offset = offset;
1148 sheet->visible = visible;
1149 sheet->type = type;
1150 sheet->utf8_name = name;
1151 sheet->rows = 0;
1152 sheet->columns = 0;
1153 sheet->cell_values = NULL;
1154 sheet->valid_dimension = 0;
1155 sheet->already_done = 0;
1156 sheet->next = NULL;
1157
1158 /* updating the linked list */
1159 if (workbook->first_sheet == NULL)
1160 workbook->first_sheet = sheet;
1161 if (workbook->last_sheet != NULL)
1162 workbook->last_sheet->next = sheet;
1163 workbook->last_sheet = sheet;
1164 return 1;
1165 }
1166
1167 static void
destroy_workbook(biff_workbook * workbook)1168 destroy_workbook (biff_workbook * workbook)
1169 {
1170 /* destroyng the Workbook struct */
1171 biff_sheet *p_sheet;
1172 biff_sheet *p_sheet_n;
1173 if (workbook)
1174 {
1175 if (workbook->xls)
1176 fclose (workbook->xls);
1177 if (workbook->utf8_converter)
1178 iconv_close (workbook->utf8_converter);
1179 if (workbook->utf16_converter)
1180 iconv_close (workbook->utf16_converter);
1181 if (workbook->shared_strings.utf8_strings != NULL)
1182 {
1183 /* destroying the Shared Strings Table [SST] */
1184 unsigned int i;
1185 for (i = 0; i < workbook->shared_strings.string_count; i++)
1186 {
1187 char *string =
1188 *(workbook->shared_strings.utf8_strings + i);
1189 if (string != NULL)
1190 free (string);
1191 }
1192 free (workbook->shared_strings.utf8_strings);
1193 }
1194 if (workbook->shared_strings.current_utf16_buf)
1195 free (workbook->shared_strings.current_utf16_buf);
1196 p_sheet = workbook->first_sheet;
1197 while (p_sheet)
1198 {
1199 p_sheet_n = p_sheet->next;
1200 destroy_sheet (p_sheet);
1201 p_sheet = p_sheet_n;
1202 }
1203 if (workbook->fat)
1204 destroy_fat_chain (workbook->fat);
1205 free (workbook);
1206 }
1207 }
1208
1209 static biff_workbook *
alloc_workbook(int magic)1210 alloc_workbook (int magic)
1211 {
1212 /* allocating and initializing the Workbook struct */
1213 biff_workbook *workbook = malloc (sizeof (biff_workbook));
1214 if (!workbook)
1215 return NULL;
1216 workbook->magic1 = magic;
1217 workbook->magic2 = FREEXL_MAGIC_END;
1218 workbook->xls = NULL;
1219 workbook->fat = NULL;
1220 workbook->cfbf_version = 0;
1221 workbook->cfbf_sector_size = 0;
1222 workbook->start_sector = 0;
1223 workbook->size = 0;
1224 workbook->current_sector = 0;
1225 workbook->bytes_read = 0;
1226 workbook->current_offset = 0;
1227 memset (workbook->sector_buf, 0, sizeof (workbook->sector_buf));
1228 workbook->p_in = workbook->sector_buf;
1229 workbook->sector_end = 0;
1230 workbook->sector_ready = 0;
1231 workbook->ok_bof = -1;
1232 workbook->biff_version = 0;
1233 workbook->biff_max_record_size = 0;
1234 workbook->biff_content_type = 0;
1235 workbook->biff_code_page = 0;
1236 workbook->biff_book_code_page = 0;
1237 workbook->biff_date_mode = 0;
1238 workbook->biff_obfuscated = 0;
1239 workbook->utf8_converter = NULL;
1240 workbook->utf16_converter = NULL;
1241 memset (workbook->record, 0, sizeof (workbook->record));
1242 workbook->record_type = 0;
1243 workbook->prev_record_type = 0;
1244 workbook->record_size = 0;
1245 workbook->shared_strings.string_count = 0;
1246 workbook->shared_strings.utf8_strings = NULL;
1247 workbook->shared_strings.current_index = 0;
1248 workbook->shared_strings.current_utf16_buf = NULL;
1249 workbook->shared_strings.current_utf16_len = 0;
1250 workbook->shared_strings.current_utf16_off = 0;
1251 workbook->shared_strings.current_utf16_skip = 0;
1252 workbook->shared_strings.next_utf16_skip = 0;
1253 workbook->first_sheet = NULL;
1254 workbook->last_sheet = NULL;
1255 workbook->active_sheet = NULL;
1256 workbook->second_pass = 0;
1257 workbook->max_format_index = 0;
1258 workbook->biff_xf_next_index = 0;
1259 return workbook;
1260 }
1261
1262 static int
insert_into_fat_chain(fat_chain * chain,unsigned int sector)1263 insert_into_fat_chain (fat_chain * chain, unsigned int sector)
1264 {
1265 /* inserting a sector into the FAT chain [linked list] */
1266 fat_entry *entry = malloc (sizeof (fat_entry));
1267 if (entry == NULL)
1268 return FREEXL_INSUFFICIENT_MEMORY;
1269 entry->current_sector = chain->next_sector;
1270 chain->next_sector += 1;
1271 entry->next_sector = sector;
1272 entry->next = NULL;
1273 if (chain->first == NULL)
1274 chain->first = entry;
1275 if (chain->last != NULL)
1276 chain->last->next = entry;
1277 chain->last = entry;
1278 return FREEXL_OK;
1279 }
1280
1281 static int
insert_into_miniFAT_chain(fat_chain * chain,unsigned int sector)1282 insert_into_miniFAT_chain (fat_chain * chain, unsigned int sector)
1283 {
1284 /* inserting a sector into the miniFAT chain [linked list] */
1285 fat_entry *entry = malloc (sizeof (fat_entry));
1286 if (entry == NULL)
1287 return FREEXL_INSUFFICIENT_MEMORY;
1288 entry->current_sector = chain->next_sectorMini;
1289 chain->next_sectorMini += 1;
1290 entry->next_sector = sector;
1291 entry->next = NULL;
1292 if (chain->firstMini == NULL)
1293 chain->firstMini = entry;
1294 if (chain->lastMini != NULL)
1295 chain->lastMini->next = entry;
1296 chain->lastMini = entry;
1297 return FREEXL_OK;
1298 }
1299
1300 static fat_entry *
get_fat_entry(fat_chain * chain,unsigned int i_sect)1301 get_fat_entry (fat_chain * chain, unsigned int i_sect)
1302 {
1303 /* attempting to retrieve a FAT item [sector] */
1304 if (!chain)
1305 return NULL;
1306 if (i_sect < chain->fat_array_count)
1307 return *(chain->fat_array + i_sect);
1308 return NULL;
1309 }
1310
1311 static int
build_fat_arrays(fat_chain * chain)1312 build_fat_arrays (fat_chain * chain)
1313 {
1314 /* building FAT sectors array */
1315 fat_entry *entry;
1316 int i;
1317
1318 if (!chain)
1319 return FREEXL_NULL_ARGUMENT;
1320 if (chain->fat_array)
1321 free (chain->fat_array);
1322 chain->fat_array = NULL;
1323 chain->fat_array_count = 0;
1324 if (chain->miniFAT_array)
1325 free (chain->miniFAT_array);
1326 chain->miniFAT_array = NULL;
1327 chain->miniFAT_array_count = 0;
1328
1329 entry = chain->first;
1330 while (entry)
1331 {
1332 /* counting how many sectors are into the FAT list */
1333 chain->fat_array_count += 1;
1334 entry = entry->next;
1335 }
1336 if (chain->fat_array_count == 0)
1337 return FREEXL_CFBF_EMPTY_FAT_CHAIN;
1338
1339 /* allocating the FAT sectors array */
1340 chain->fat_array = malloc (sizeof (fat_entry *) * chain->fat_array_count);
1341 if (chain->fat_array == NULL)
1342 return FREEXL_INSUFFICIENT_MEMORY;
1343
1344 i = 0;
1345 entry = chain->first;
1346 while (entry)
1347 {
1348 /* populating the pointer array */
1349 *(chain->fat_array + i) = entry;
1350 i++;
1351 entry = entry->next;
1352 }
1353
1354 entry = chain->firstMini;
1355 while (entry)
1356 {
1357 /* counting how many sectors are into the miniFAT list */
1358 chain->miniFAT_array_count += 1;
1359 entry = entry->next;
1360 }
1361 if (chain->miniFAT_array_count > 0)
1362 {
1363 /* allocating the miniFAT sectors array */
1364 chain->miniFAT_array =
1365 malloc (sizeof (fat_entry *) * chain->miniFAT_array_count);
1366 if (chain->miniFAT_array == NULL)
1367 return FREEXL_INSUFFICIENT_MEMORY;
1368
1369 i = 0;
1370 entry = chain->firstMini;
1371 while (entry)
1372 {
1373 /* populating the pointer array */
1374 *(chain->miniFAT_array + i) = entry;
1375 i++;
1376 entry = entry->next;
1377 }
1378 }
1379 return FREEXL_OK;
1380 }
1381
1382 static void
select_active_sheet(biff_workbook * workbook,unsigned int current_offset)1383 select_active_sheet (biff_workbook * workbook, unsigned int current_offset)
1384 {
1385 /* selecting the currently acrive Sheet (if any) */
1386 biff_sheet *p_sheet;
1387 p_sheet = workbook->first_sheet;
1388 while (p_sheet)
1389 {
1390 if (p_sheet->start_offset == current_offset)
1391 {
1392 /* ok, this one is the current Sheet */
1393 workbook->active_sheet = p_sheet;
1394 return;
1395 }
1396 p_sheet = p_sheet->next;
1397 }
1398 workbook->active_sheet = NULL;
1399 }
1400
1401 static int
read_fat_sector(FILE * xls,fat_chain * chain,unsigned int sector)1402 read_fat_sector (FILE * xls, fat_chain * chain, unsigned int sector)
1403 {
1404 /* reading a FAT chain sector */
1405 long where = (sector + 1) * chain->sector_size;
1406 unsigned char buf[4096];
1407 unsigned char *p_buf = buf;
1408 int i_fat;
1409 int max_fat;
1410 if (fseek (xls, where, SEEK_SET) != 0)
1411 return FREEXL_CFBF_SEEK_ERROR;
1412 if (chain->sector_size == 4096)
1413 max_fat = 1024;
1414 else
1415 max_fat = 128;
1416
1417 /* reading a FAT sector */
1418 if (xls_fread (sizeof (buf), buf, 1, chain->sector_size, xls) !=
1419 chain->sector_size)
1420 return FREEXL_CFBF_READ_ERROR;
1421
1422 for (i_fat = 0; i_fat < max_fat; i_fat++)
1423 {
1424 int ret;
1425 biff_word32 fat;
1426 memcpy (fat.bytes, p_buf, 4);
1427 p_buf += 4;
1428 if (chain->swap)
1429 swap32 (&fat);
1430 ret = insert_into_fat_chain (chain, fat.value);
1431 if (ret != FREEXL_OK)
1432 return ret;
1433 }
1434 return FREEXL_OK;
1435 }
1436
1437 static int
read_difat_sectors(FILE * xls,fat_chain * chain,unsigned int sector,unsigned int num_sectors)1438 read_difat_sectors (FILE * xls, fat_chain * chain, unsigned int sector,
1439 unsigned int num_sectors)
1440 {
1441 /* reading a DIFAT (DoubleIndirect) chain sector */
1442 unsigned int next_sector = sector;
1443 unsigned int blocks = 0;
1444 long where = (sector + 1) * chain->sector_size;
1445 biff_word32 difat[1024];
1446 int i_difat;
1447 int max_difat;
1448 int end_of_chain = 0;
1449
1450 if (chain->sector_size == 4096)
1451 max_difat = 1024;
1452 else
1453 max_difat = 128;
1454
1455 while (1)
1456 {
1457 where = (next_sector + 1) * chain->sector_size;
1458 if (fseek (xls, where, SEEK_SET) != 0)
1459 return FREEXL_CFBF_SEEK_ERROR;
1460 /* reading a DIFAT sector */
1461 if (xls_fread (sizeof (difat), &difat, 1, chain->sector_size, xls) !=
1462 chain->sector_size)
1463 return FREEXL_CFBF_READ_ERROR;
1464 blocks++;
1465 if (chain->swap)
1466 {
1467 for (i_difat = 0; i_difat < max_difat; i_difat++)
1468 swap32 (difat + i_difat);
1469 }
1470
1471 for (i_difat = 0; i_difat < max_difat; i_difat++)
1472 {
1473 if (difat[i_difat].value == 0xFFFFFFFE)
1474 {
1475 end_of_chain = 1; /* end of FAT chain */
1476 break;
1477 }
1478 if (i_difat == max_difat - 1)
1479 next_sector = difat[i_difat].value;
1480 else
1481 {
1482 int ret;
1483 if (difat[i_difat].value == 0xFFFFFFFF)
1484 continue; /* unused sector */
1485 ret = read_fat_sector (xls, chain, difat[i_difat].value);
1486 if (ret != FREEXL_OK)
1487 return ret;
1488 }
1489 }
1490 if (blocks == num_sectors)
1491 break;
1492 if (end_of_chain)
1493 break;
1494 }
1495 if (blocks != num_sectors)
1496 return 0;
1497 return 1;
1498 }
1499
1500 static int
read_miniFAT_sectors(FILE * xls,fat_chain * chain,unsigned int sector,unsigned int num_sectors)1501 read_miniFAT_sectors (FILE * xls, fat_chain * chain, unsigned int sector,
1502 unsigned int num_sectors)
1503 {
1504 /* reading miniFAT chain sectors */
1505 long where = (sector - 1) * chain->sector_size;
1506 unsigned char buf[4096];
1507 int i_fat;
1508 int max_fat;
1509 unsigned int block = 0;
1510
1511 if (chain->sector_size == 4096)
1512 max_fat = 1024;
1513 else
1514 max_fat = 128;
1515
1516 if (fseek (xls, where, SEEK_SET) != 0)
1517 return FREEXL_CFBF_SEEK_ERROR;
1518 while (block < num_sectors)
1519 {
1520 unsigned char *p_buf = buf;
1521 block++;
1522 /* reading a miniFAT sector */
1523 if (xls_fread (sizeof (buf), &buf, 1, chain->sector_size, xls) !=
1524 chain->sector_size)
1525 return FREEXL_CFBF_READ_ERROR;
1526 for (i_fat = 0; i_fat < max_fat; i_fat++)
1527 {
1528 int ret;
1529 biff_word32 fat;
1530 memcpy (fat.bytes, p_buf, 4);
1531 p_buf += 4;
1532 if (chain->swap)
1533 swap32 (&fat);
1534 ret = insert_into_miniFAT_chain (chain, fat.value);
1535 if (ret != FREEXL_OK)
1536 return ret;
1537 }
1538 }
1539 return 1;
1540 }
1541
1542 static fat_chain *
read_cfbf_header(biff_workbook * workbook,int swap,int * err_code)1543 read_cfbf_header (biff_workbook * workbook, int swap, int *err_code)
1544 {
1545 /* attempting to read and check FAT header */
1546 cfbf_header header;
1547 fat_chain *chain = NULL;
1548 int i_fat;
1549 int ret;
1550 unsigned char *p_fat = header.fat_sector_map;
1551
1552 if (xls_fread (sizeof (header), &header, 1, 512, workbook->xls) != 512)
1553 {
1554 *err_code = FREEXL_CFBF_READ_ERROR;
1555 return NULL;
1556 }
1557 if (swap)
1558 {
1559 /* BIG endian arch: swap required */
1560 swap16 (&(header.minor_version));
1561 swap16 (&(header.major_version));
1562 swap16 (&(header.byte_order));
1563 swap16 (&(header.sector_shift));
1564 swap16 (&(header.mini_sector_shift));
1565 swap16 (&(header.reserved1));
1566 swap32 (&(header.reserved2));
1567 swap32 (&(header.directory_sectors));
1568 swap32 (&(header.fat_sectors));
1569 swap32 (&(header.directory_start));
1570 swap32 (&(header.transaction_signature));
1571 swap32 (&(header.mini_cutoff));
1572 swap32 (&(header.mini_fat_start));
1573 swap32 (&(header.mini_fat_sectors));
1574 swap32 (&(header.difat_start));
1575 swap32 (&(header.difat_sectors));
1576 }
1577
1578 if (header.signature[0] == 0xd0 && header.signature[1] == 0xcf
1579 && header.signature[2] == 0x11 && header.signature[3] == 0xe0
1580 && header.signature[4] == 0xa1 && header.signature[5] == 0xb1
1581 && header.signature[6] == 0x1a && header.signature[7] == 0xe1)
1582 ; /* magic signature OK */
1583 else
1584 {
1585 *err_code = FREEXL_CFBF_INVALID_SIGNATURE;
1586 return NULL;
1587 }
1588 if (header.sector_shift.value == 9 || header.sector_shift.value == 12)
1589 ; /* ok, valid sector size */
1590 else
1591 {
1592 *err_code = FREEXL_CFBF_INVALID_SECTOR_SIZE;
1593 return NULL;
1594 }
1595
1596 workbook->cfbf_version = header.major_version.value;
1597 if (header.sector_shift.value == 9)
1598 workbook->cfbf_sector_size = 512;
1599 if (header.sector_shift.value == 12)
1600 workbook->cfbf_sector_size = 4096;
1601
1602 chain =
1603 alloc_fat_chain (swap, header.sector_shift.value,
1604 header.directory_start.value);
1605 if (!chain)
1606 {
1607 *err_code = FREEXL_INSUFFICIENT_MEMORY;
1608 return NULL;
1609 }
1610 for (i_fat = 0; i_fat < 109; i_fat++)
1611 {
1612 /* reading FAT sectors */
1613 biff_word32 fat;
1614 memcpy (fat.bytes, p_fat, 4);
1615 p_fat += 4;
1616 if (swap)
1617 swap32 (&fat);
1618 if (fat.value == 0xFFFFFFFF)
1619 continue; /* unused sector */
1620 ret = read_fat_sector (workbook->xls, chain, fat.value);
1621 if (ret != FREEXL_OK)
1622 {
1623 *err_code = ret;
1624 destroy_fat_chain (chain);
1625 return NULL;
1626 }
1627 }
1628
1629 if (header.difat_sectors.value > 0)
1630 {
1631 /* reading DoubleIndirect [DIFAT] sectors */
1632 if (!read_difat_sectors
1633 (workbook->xls, chain, header.difat_start.value,
1634 header.difat_sectors.value))
1635 {
1636 *err_code = FREEXL_CFBF_READ_ERROR;
1637 destroy_fat_chain (chain);
1638 return NULL;
1639 }
1640 }
1641
1642 if (header.mini_fat_sectors.value > 0)
1643 {
1644 /* there is a miniFAT requiring to be supported */
1645 chain->miniCutOff = header.mini_cutoff.value;
1646 if (!read_miniFAT_sectors
1647 (workbook->xls, chain, header.mini_fat_start.value,
1648 header.mini_fat_sectors.value))
1649 {
1650 *err_code = FREEXL_CFBF_READ_ERROR;
1651 destroy_fat_chain (chain);
1652 return NULL;
1653 }
1654 }
1655
1656 ret = build_fat_arrays (chain);
1657 if (ret != FREEXL_OK)
1658 {
1659 *err_code = ret;
1660 destroy_fat_chain (chain);
1661 return NULL;
1662 }
1663
1664 *err_code = FREEXL_OK;
1665 return chain;
1666 }
1667
1668 static int
read_mini_stream(biff_workbook * workbook,int * errcode)1669 read_mini_stream (biff_workbook * workbook, int *errcode)
1670 {
1671 /* loading in memory the whole ministream */
1672 unsigned int len = 0;
1673 unsigned int sector = workbook->fat->miniFAT_start;
1674 unsigned char buf[4096];
1675 unsigned char *miniStream;
1676 fat_entry *entry;
1677 int eof = 0;
1678
1679 if (workbook->fat->miniStream)
1680 free (workbook->fat->miniStream);
1681 workbook->fat->miniStream = NULL;
1682 miniStream = malloc (workbook->fat->miniFAT_len);
1683 if (miniStream == NULL)
1684 {
1685 *errcode = FREEXL_INSUFFICIENT_MEMORY;
1686 return 0;
1687 }
1688 while (len < workbook->fat->miniFAT_len)
1689 {
1690 /* reading one sector */
1691 unsigned int size;
1692 long where = (sector + 1) * workbook->fat->sector_size;
1693 if (fseek (workbook->xls, where, SEEK_SET) != 0)
1694 {
1695 *errcode = FREEXL_CFBF_SEEK_ERROR;
1696 return 0;
1697 }
1698 if (xls_fread
1699 (sizeof (buf), buf, 1, workbook->fat->sector_size,
1700 workbook->xls) != workbook->fat->sector_size)
1701 {
1702 *errcode = FREEXL_CFBF_READ_ERROR;
1703 return 0;
1704 }
1705 size = workbook->fat->sector_size;
1706 if ((len + size) > workbook->fat->miniFAT_len)
1707 size = workbook->fat->miniFAT_len - len;
1708 memcpy (miniStream + len, buf, size);
1709 len += size;
1710 entry = get_fat_entry (workbook->fat, sector);
1711 if (entry == NULL)
1712 {
1713 *errcode = FREEXL_CFBF_ILLEGAL_FAT_ENTRY;
1714 return 0;
1715 }
1716 if (entry->next_sector == 0xfffffffe)
1717 {
1718 /* EOF: end-of-chain marker found */
1719 eof = 1;
1720 break;
1721 }
1722 sector = entry->next_sector;
1723 }
1724 if (!eof || len != workbook->fat->miniFAT_len)
1725 {
1726 free (miniStream);
1727 *errcode = FREEXL_INVALID_MINI_STREAM;
1728 return 0;
1729 }
1730 workbook->fat->miniStream = miniStream;
1731 return 1;
1732 }
1733
1734 static const char *
find_in_SST(biff_workbook * workbook,unsigned int string_index)1735 find_in_SST (biff_workbook * workbook, unsigned int string_index)
1736 {
1737 /* retieving a string from the SST */
1738 if (!workbook)
1739 return NULL;
1740 if (workbook->shared_strings.utf8_strings == NULL)
1741 return NULL;
1742 if (string_index < workbook->shared_strings.string_count)
1743 return *(workbook->shared_strings.utf8_strings + string_index);
1744 return NULL;
1745 }
1746
1747 static int
parse_SST(biff_workbook * workbook,int swap)1748 parse_SST (biff_workbook * workbook, int swap)
1749 {
1750 /* attempting to parse a Shared String Table */
1751 unsigned int i_string;
1752 unsigned char *p_string;
1753 biff_word32 n_strings;
1754 unsigned int required;
1755 unsigned int available;
1756
1757 if (workbook->shared_strings.string_count == 0
1758 && workbook->shared_strings.utf8_strings == NULL)
1759 {
1760 /* main SST record [initializing] */
1761 memcpy (n_strings.bytes, workbook->record + 4, 4);
1762 if (swap)
1763 swap32 (&n_strings);
1764 p_string = workbook->record + 8;
1765 workbook->shared_strings.string_count = n_strings.value;
1766 if (workbook->shared_strings.string_count > 1024 * 1024)
1767 {
1768 /* unexpected huge count ... cowardly giving up ... */
1769 return FREEXL_INSUFFICIENT_MEMORY;
1770 }
1771 workbook->shared_strings.utf8_strings =
1772 malloc (sizeof (char **) * workbook->shared_strings.string_count);
1773 if (workbook->shared_strings.utf8_strings == NULL)
1774 return FREEXL_INSUFFICIENT_MEMORY;
1775 for (i_string = 0; i_string < workbook->shared_strings.string_count;
1776 i_string++)
1777 *(workbook->shared_strings.utf8_strings + i_string) = NULL;
1778 }
1779 else
1780 {
1781 /* SST-CONTINUE */
1782 char *utf8_string;
1783 unsigned char mask;
1784 unsigned int len;
1785 int utf16 = 0;
1786 int err;
1787 unsigned int next_skip;
1788 unsigned int utf16_len = workbook->shared_strings.current_utf16_len;
1789 unsigned int utf16_off = workbook->shared_strings.current_utf16_off;
1790 unsigned int utf16_skip = workbook->shared_strings.current_utf16_skip;
1791 char *utf16_buf = workbook->shared_strings.current_utf16_buf;
1792 p_string = workbook->record;
1793
1794 if (workbook->shared_strings.current_utf16_len > 0)
1795 {
1796 /* completing the last suspended string [split between records] */
1797 mask = *p_string;
1798 p_string++;
1799 len = utf16_len - utf16_off;
1800
1801 if ((mask & 0x01) == 0x01)
1802 utf16 = 1;
1803 if (!utf16)
1804 {
1805 /* 'stripped' UTF-16: requires padding */
1806 unsigned int i;
1807 for (i = 0; i < len; i++)
1808 {
1809 if (p_string - workbook->record >=
1810 (int)workbook->record_size)
1811 {
1812 /* buffer overflow: it's a preasumable crafted file intended to crash FreeXL */
1813 return FREEXL_CRAFTED_FILE;
1814 }
1815 *(utf16_buf + (utf16_off * 2) + (i * 2)) =
1816 *p_string;
1817 p_string++;
1818 *(utf16_buf + (utf16_off * 2) + ((i * 2) + 1)) =
1819 0x00;
1820 }
1821 }
1822 else
1823 {
1824 /* already encoded as UTF-16 */
1825 memcpy (utf16_buf + (utf16_off * 2), p_string, len * 2);
1826 p_string += len * 2;
1827 }
1828
1829 /* skipping extra data (if any) */
1830 p_string += utf16_skip;
1831 if (p_string - workbook->record >= (int)workbook->record_size)
1832 next_skip =
1833 (p_string - workbook->record) - workbook->record_size;
1834 else
1835 next_skip = 0;
1836
1837 /* converting text to UTF-8 */
1838 utf8_string =
1839 convert_to_utf8 (workbook->utf16_converter, utf16_buf,
1840 utf16_len * 2, &err);
1841 if (err)
1842 return FREEXL_INVALID_CHARACTER;
1843 *(workbook->shared_strings.utf8_strings +
1844 workbook->shared_strings.current_index) = utf8_string;
1845 free (workbook->shared_strings.current_utf16_buf);
1846 workbook->shared_strings.current_utf16_buf = NULL;
1847 workbook->shared_strings.current_utf16_len = 0;
1848 workbook->shared_strings.current_utf16_off = 0;
1849 workbook->shared_strings.current_utf16_skip = next_skip;
1850 workbook->shared_strings.next_utf16_skip = 0;
1851 workbook->shared_strings.current_index += 1;
1852 }
1853 }
1854
1855 for (i_string = workbook->shared_strings.current_index;
1856 i_string < workbook->shared_strings.string_count; i_string++)
1857 {
1858 /* parsing strings */
1859 char *utf8_string;
1860 unsigned int len;
1861 int utf16 = 0;
1862 biff_word16 word16;
1863 unsigned int start_offset;
1864 unsigned int extra_skip;
1865 unsigned int next_skip;
1866
1867 if ((unsigned int) (p_string - workbook->record) >=
1868 workbook->record_size)
1869 {
1870 /* end of record */
1871 return FREEXL_OK;
1872 }
1873
1874 /* skipping extra bytes belonging to the previous record */
1875 p_string += workbook->shared_strings.next_utf16_skip;
1876
1877 memcpy (word16.bytes, p_string, 2);
1878 if (swap)
1879 swap16 (&word16);
1880 len = word16.value;
1881 p_string += 2;
1882
1883 get_unicode_params (p_string, swap, &start_offset, &utf16,
1884 &extra_skip);
1885 p_string += start_offset;
1886
1887 /* initializing the current UTF-16 variables */
1888 workbook->shared_strings.current_utf16_skip = extra_skip;
1889 workbook->shared_strings.next_utf16_skip = 0;
1890 workbook->shared_strings.current_utf16_off = 0;
1891 workbook->shared_strings.current_utf16_len = len;
1892 workbook->shared_strings.current_utf16_buf =
1893 malloc (workbook->shared_strings.current_utf16_len * 2);
1894
1895 if (!utf16)
1896 required = len;
1897 else
1898 required = len * 2;
1899 available = workbook->record_size - (p_string - workbook->record);
1900 if (required > available)
1901 {
1902 /* not enough input bytes: data spanning on next CONTINUE record */
1903 char *utf16_buf = workbook->shared_strings.current_utf16_buf;
1904 if (!utf16)
1905 {
1906 /* 'stripped' UTF-16: requires padding */
1907 unsigned int i;
1908 for (i = 0; i < available; i++)
1909 {
1910 *(utf16_buf + (i * 2)) = *p_string;
1911 p_string++;
1912 *(utf16_buf + ((i * 2) + 1)) = 0x00;
1913 }
1914 workbook->shared_strings.current_utf16_off = available;
1915 }
1916 else
1917 {
1918 /* already encoded as UTF-16 */
1919 memcpy (utf16_buf, p_string, available);
1920 workbook->shared_strings.current_utf16_off =
1921 available / 2;
1922 }
1923 return FREEXL_OK;
1924 }
1925
1926 if (len <= 0)
1927 {
1928 /* zero length - it's a preasumable crafted file intended to crash FreeXL */
1929 return FREEXL_CRAFTED_FILE;
1930 }
1931 if (!parse_unicode_string
1932 (workbook->utf16_converter, len, utf16, p_string, &utf8_string))
1933 return FREEXL_INVALID_CHARACTER;
1934
1935 /* skipping string data */
1936 if (!utf16)
1937 p_string += len;
1938 else
1939 p_string += len * 2;
1940 /* skipping extra data (if any) */
1941 p_string += workbook->shared_strings.current_utf16_skip;
1942 if (p_string - workbook->record >= (int)workbook->record_size)
1943 next_skip = (p_string - workbook->record) - workbook->record_size;
1944 else
1945 next_skip = 0;
1946
1947 *(workbook->shared_strings.utf8_strings + i_string) = utf8_string;
1948 free (workbook->shared_strings.current_utf16_buf);
1949 workbook->shared_strings.current_utf16_buf = NULL;
1950 workbook->shared_strings.current_utf16_len = 0;
1951 workbook->shared_strings.current_utf16_off = 0;
1952 workbook->shared_strings.current_utf16_skip = 0;
1953 workbook->shared_strings.next_utf16_skip = next_skip;
1954 workbook->shared_strings.current_index = i_string + 1;
1955 }
1956
1957 return FREEXL_OK;
1958 }
1959
1960 static void
check_format(char * utf8_string,int * is_date,int * is_datetime,int * is_time)1961 check_format (char *utf8_string, int *is_date, int *is_datetime, int *is_time)
1962 {
1963 /* attempting to identify DATE, DATETIME or TIME formats */
1964 int y = 0;
1965 int m = 0;
1966 int d = 0;
1967 int h = 0;
1968 int s = 0;
1969 unsigned int i;
1970 for (i = 0; i < strlen (utf8_string); i++)
1971 {
1972 switch (utf8_string[i])
1973 {
1974 case 'Y':
1975 case 'y':
1976 y++;
1977 break;
1978 case 'M':
1979 case 'm':
1980 m++;
1981 break;
1982 case 'D':
1983 case 'd':
1984 d++;
1985 break;
1986 case 'H':
1987 case 'h':
1988 h++;
1989 break;
1990 case 'S':
1991 case 's':
1992 s++;
1993 break;
1994 }
1995 }
1996 *is_date = 0;
1997 *is_datetime = 0;
1998 *is_time = 0;
1999 if (y && m && d && h)
2000 {
2001 *is_datetime = 1;
2002 return;
2003 }
2004 if ((y && m) || (m && d))
2005 {
2006 *is_date = 1;
2007 return;
2008 }
2009 if ((h && m) || (m && s))
2010 *is_time = 1;
2011 }
2012
2013 static void
add_format_to_workbook(biff_workbook * workbook,unsigned short format_index,int is_date,int is_datetime,int is_time)2014 add_format_to_workbook (biff_workbook * workbook, unsigned short format_index,
2015 int is_date, int is_datetime, int is_time)
2016 {
2017 /* adding a new DATE/DATETIME/TIME format to the Workbook */
2018 if (workbook->max_format_index < BIFF_MAX_FORMAT)
2019 {
2020 biff_format *format =
2021 workbook->format_array + workbook->max_format_index;
2022 format->format_index = format_index;
2023 format->is_date = is_date;
2024 format->is_datetime = is_datetime;
2025 format->is_time = is_time;
2026 workbook->max_format_index += 1;
2027 }
2028 }
2029
2030 static void
add_xf_to_workbook(biff_workbook * workbook,unsigned short format_index)2031 add_xf_to_workbook (biff_workbook * workbook, unsigned short format_index)
2032 {
2033 /* adding a new XF to the Workbook */
2034 if (workbook->biff_xf_next_index < BIFF_MAX_XF)
2035 workbook->biff_xf_array[workbook->biff_xf_next_index] = format_index;
2036 workbook->biff_xf_next_index += 1;
2037 }
2038
2039 static int
legacy_emergency_dimension(biff_workbook * workbook,int swap,unsigned short type,unsigned short size,unsigned int * rows,unsigned short * columns)2040 legacy_emergency_dimension (biff_workbook * workbook, int swap,
2041 unsigned short type, unsigned short size,
2042 unsigned int *rows, unsigned short *columns)
2043 {
2044 /* performing a preliminary pass so to get DIMENSION */
2045 biff_word16 record_type;
2046 biff_word16 record_size;
2047 unsigned char buf[16];
2048 int first = 1;
2049 long where;
2050 long restart_off = ftell (workbook->xls);
2051
2052 record_type.value = type;
2053 record_size.value = size;
2054
2055 while (1)
2056 {
2057 /* looping on BIFF records */
2058 if (!first)
2059 {
2060 if (xls_fread (sizeof (buf), &buf, 1, 4, workbook->xls) != 4)
2061 return 0;
2062 memcpy (record_type.bytes, buf, 2);
2063 memcpy (record_size.bytes, buf + 2, 2);
2064 }
2065 else
2066 first = 0;
2067 if (swap)
2068 {
2069 /* BIG endian arch: swap required */
2070 swap16 (&record_type);
2071 swap16 (&record_size);
2072 }
2073
2074 if (record_type.value == BIFF_EOF)
2075 {
2076 /* EOF marker found: the current stream is terminated */
2077 break;
2078 }
2079
2080 if (record_type.value == BIFF_INTEGER_2
2081 && workbook->biff_version == FREEXL_BIFF_VER_2)
2082 {
2083 /* INTEGER marker found */
2084 biff_word16 word16;
2085
2086 if (xls_fread
2087 (sizeof (workbook->record), workbook->record, 1,
2088 record_size.value, workbook->xls) != record_size.value)
2089 return 0;
2090
2091 memcpy (word16.bytes, workbook->record, 2);
2092 if (swap)
2093 swap16 (&word16);
2094 if (word16.value > *rows)
2095 *rows = word16.value;
2096 memcpy (word16.bytes, workbook->record + 2, 2);
2097 if (swap)
2098 swap16 (&word16);
2099 if (word16.value > *columns)
2100 *columns = word16.value;
2101 continue;
2102 }
2103
2104 if ((record_type.value == BIFF_NUMBER_2
2105 && workbook->biff_version == FREEXL_BIFF_VER_2)
2106 || (record_type.value == BIFF_NUMBER
2107 && (workbook->biff_version == FREEXL_BIFF_VER_3
2108 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2109 {
2110 /* NUMBER marker found */
2111 biff_word16 word16;
2112
2113 if (xls_fread
2114 (sizeof (workbook->record), workbook->record, 1,
2115 record_size.value, workbook->xls) != record_size.value)
2116 return 0;
2117
2118 memcpy (word16.bytes, workbook->record, 2);
2119 if (swap)
2120 swap16 (&word16);
2121 if (word16.value > *rows)
2122 *rows = word16.value;
2123 memcpy (word16.bytes, workbook->record + 2, 2);
2124 if (swap)
2125 swap16 (&word16);
2126 if (word16.value > *columns)
2127 *columns = word16.value;
2128 continue;
2129 }
2130
2131 if ((record_type.value == BIFF_BOOLERR_2
2132 && workbook->biff_version == FREEXL_BIFF_VER_2)
2133 || (record_type.value == BIFF_BOOLERR
2134 && (workbook->biff_version == FREEXL_BIFF_VER_3
2135 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2136 {
2137 /* BOOLERR marker found */
2138 biff_word16 word16;
2139
2140 if (xls_fread
2141 (sizeof (workbook->record), workbook->record, 1,
2142 record_size.value, workbook->xls) != record_size.value)
2143 return 0;
2144
2145 memcpy (word16.bytes, workbook->record, 2);
2146 if (swap)
2147 swap16 (&word16);
2148 if (word16.value > *rows)
2149 *rows = word16.value;
2150 memcpy (word16.bytes, workbook->record + 2, 2);
2151 if (swap)
2152 swap16 (&word16);
2153 if (word16.value > *columns)
2154 *columns = word16.value;
2155 continue;
2156 }
2157
2158 if (record_type.value == BIFF_RK
2159 && (workbook->biff_version == FREEXL_BIFF_VER_3
2160 || workbook->biff_version == FREEXL_BIFF_VER_4))
2161 {
2162 /* RK marker found */
2163 biff_word16 word16;
2164
2165 if (xls_fread
2166 (sizeof (workbook->record), workbook->record, 1,
2167 record_size.value, workbook->xls) != record_size.value)
2168 return 0;
2169
2170 memcpy (word16.bytes, workbook->record, 2);
2171 if (swap)
2172 swap16 (&word16);
2173 if (word16.value > *rows)
2174 *rows = word16.value;
2175 memcpy (word16.bytes, workbook->record + 2, 2);
2176 if (swap)
2177 swap16 (&word16);
2178 if (word16.value > *columns)
2179 *columns = word16.value;
2180 continue;
2181 }
2182
2183 if ((record_type.value == BIFF_LABEL_2
2184 && workbook->biff_version == FREEXL_BIFF_VER_2)
2185 || (record_type.value == BIFF_LABEL
2186 && (workbook->biff_version == FREEXL_BIFF_VER_3
2187 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2188 {
2189 /* LABEL marker found */
2190 biff_word16 word16;
2191
2192 if (xls_fread
2193 (sizeof (workbook->record), workbook->record, 1,
2194 record_size.value, workbook->xls) != record_size.value)
2195 return 0;
2196
2197 memcpy (word16.bytes, workbook->record, 2);
2198 if (swap)
2199 swap16 (&word16);
2200 if (word16.value > *rows)
2201 *rows = word16.value;
2202 memcpy (word16.bytes, workbook->record + 2, 2);
2203 if (swap)
2204 swap16 (&word16);
2205 if (word16.value > *columns)
2206 *columns = word16.value;
2207 continue;
2208 }
2209
2210 /* skipping to next record */
2211 where = record_size.value;
2212 if (fseek (workbook->xls, where, SEEK_CUR) != 0)
2213 return 0;
2214 }
2215
2216 /* repositioning the stream offset */
2217 if (fseek (workbook->xls, restart_off, SEEK_SET) != 0)
2218 return 0;
2219 return 1;
2220 }
2221
2222 static int
check_legacy_undeclared_dimension(biff_workbook * workbook,int swap,unsigned short type,unsigned short size)2223 check_legacy_undeclared_dimension (biff_workbook * workbook, int swap,
2224 unsigned short type, unsigned short size)
2225 {
2226 /* checking (and eventually saning) missing DIMENSION */
2227 if (workbook->active_sheet == NULL)
2228 {
2229 char *utf8_name;
2230 unsigned int rows = 0;
2231 unsigned short columns = 0;
2232 if (!legacy_emergency_dimension
2233 (workbook, swap, type, size, &rows, &columns))
2234 return 0;
2235 /* initializing the worksheet */
2236 utf8_name = malloc (10);
2237 strcpy (utf8_name, "Worksheet");
2238 if (!add_sheet_to_workbook (workbook, 0, 0, 0, utf8_name))
2239 return 0;
2240 workbook->active_sheet = workbook->first_sheet;
2241 if (workbook->active_sheet != NULL)
2242 {
2243 /* setting Sheet dimensions */
2244 int ret;
2245 workbook->active_sheet->rows = rows + 1;
2246 workbook->active_sheet->columns = columns + 1;
2247 ret = allocate_cells (workbook);
2248 if (ret != FREEXL_OK)
2249 return 0;
2250 }
2251 }
2252 return 1;
2253 }
2254
2255 static int
read_legacy_biff(biff_workbook * workbook,int swap)2256 read_legacy_biff (biff_workbook * workbook, int swap)
2257 {
2258 /*
2259 * attempting to read legacy BIFF (versions 2,3,4)
2260 * no CFBF: simply a BIFF stream (one only Worksheet)
2261 */
2262 long where;
2263 biff_word16 word16;
2264 biff_word16 record_type;
2265 biff_word16 record_size;
2266 unsigned char buf[16];
2267 unsigned short format_index = 0;
2268
2269 /* attempting to get the main BOF */
2270 rewind (workbook->xls);
2271 if (xls_fread (sizeof (buf), &buf, 1, 4, workbook->xls) != 4)
2272 return 0;
2273 memcpy (record_type.bytes, buf, 2);
2274 memcpy (record_size.bytes, buf + 2, 2);
2275 if (swap)
2276 {
2277 /* BIG endian arch: swap required */
2278 swap16 (&record_type);
2279 swap16 (&record_size);
2280 }
2281 switch (record_type.value)
2282 {
2283 case BIFF_BOF_2: /* BIFF2 */
2284 workbook->biff_version = FREEXL_BIFF_VER_2;
2285 workbook->ok_bof = 1;
2286 break;
2287 case BIFF_BOF_3: /* BIFF3 */
2288 workbook->biff_version = FREEXL_BIFF_VER_3;
2289 workbook->ok_bof = 1;
2290 break;
2291 case BIFF_BOF_4: /* BIFF4 */
2292 workbook->biff_version = FREEXL_BIFF_VER_4;
2293 workbook->ok_bof = 1;
2294 break;
2295 };
2296 if (workbook->ok_bof != 1)
2297 return 0;
2298
2299 where = record_size.value;
2300 if (fseek (workbook->xls, where, SEEK_CUR) != 0)
2301 return 0;
2302
2303 while (1)
2304 {
2305 /* looping on BIFF records */
2306
2307 if (xls_fread (sizeof (buf), &buf, 1, 4, workbook->xls) != 4)
2308 return 0;
2309 memcpy (record_type.bytes, buf, 2);
2310 memcpy (record_size.bytes, buf + 2, 2);
2311 if (swap)
2312 {
2313 /* BIG endian arch: swap required */
2314 swap16 (&record_type);
2315 swap16 (&record_size);
2316 }
2317
2318 if (record_type.value == BIFF_SHEETSOFFSET)
2319 {
2320 /* unsupported BIFF4W format */
2321 return 0;
2322 }
2323
2324 if (record_type.value == BIFF_EOF)
2325 {
2326 /* EOF marker found: the current stream is terminated */
2327 return 1;
2328 }
2329
2330 if (record_type.value == BIFF_CODEPAGE)
2331 {
2332 /* CODEPAGE marker found */
2333 if (xls_fread
2334 (sizeof (workbook->record), workbook->record, 1,
2335 record_size.value, workbook->xls) != record_size.value)
2336 return 0;
2337 memcpy (word16.bytes, workbook->record, 2);
2338 if (swap)
2339 swap16 (&word16);
2340 workbook->biff_code_page = word16.value;
2341 if (workbook->ok_bof == 1)
2342 workbook->biff_book_code_page = word16.value;
2343 if (!biff_set_utf8_converter (workbook))
2344 return 0;
2345 continue;
2346 }
2347
2348 if (record_type.value == BIFF_DATEMODE)
2349 {
2350 /* DATEMODE marker found */
2351 if (xls_fread
2352 (sizeof (workbook->record), workbook->record, 1,
2353 record_size.value, workbook->xls) != record_size.value)
2354 return 0;
2355 memcpy (word16.bytes, workbook->record, 2);
2356 if (swap)
2357 swap16 (&word16);
2358 workbook->biff_date_mode = word16.value;
2359 continue;
2360 }
2361
2362 if (record_type.value == BIFF_FILEPASS)
2363 {
2364 /* PASSWORD marker found */
2365 workbook->biff_obfuscated = 1;
2366 goto skip_to_next;
2367 }
2368
2369 if ((record_type.value == BIFF_FORMAT_2
2370 && (workbook->biff_version == FREEXL_BIFF_VER_2
2371 || workbook->biff_version == FREEXL_BIFF_VER_3))
2372 || (record_type.value == BIFF_FORMAT
2373 && (workbook->biff_version == FREEXL_BIFF_VER_4)))
2374 {
2375 /* FORMAT marker found */
2376 biff_word16 word16;
2377 char *string;
2378 char *utf8_string;
2379 unsigned int len;
2380 int err;
2381 unsigned char *p_string;
2382 int is_date = 0;
2383 int is_datetime = 0;
2384 int is_time = 0;
2385 if (xls_fread
2386 (sizeof (workbook->record), workbook->record, 1,
2387 record_size.value, workbook->xls) != record_size.value)
2388 return 0;
2389
2390 if (workbook->biff_version == FREEXL_BIFF_VER_2
2391 || workbook->biff_version == FREEXL_BIFF_VER_3)
2392 {
2393 len = *workbook->record;
2394 p_string = workbook->record + 1;
2395 string = malloc (len);
2396 memcpy (string, p_string, len);
2397 /* converting text to UTF-8 */
2398 utf8_string =
2399 convert_to_utf8 (workbook->utf8_converter, string,
2400 len, &err);
2401 free (string);
2402 if (err)
2403 return 0;
2404 check_format (utf8_string, &is_date, &is_datetime,
2405 &is_time);
2406 free (utf8_string);
2407 if (is_date || is_datetime || is_time)
2408 add_format_to_workbook (workbook, format_index,
2409 is_date, is_datetime,
2410 is_time);
2411 }
2412 else
2413 {
2414 memcpy (word16.bytes, workbook->record + 2, 2);
2415 if (swap)
2416 swap16 (&word16);
2417 len = word16.value;
2418 p_string = workbook->record + 4;
2419
2420 len = *(workbook->record + 2);
2421 p_string = workbook->record + 3;
2422 string = malloc (len);
2423 memcpy (string, p_string, len);
2424 /* converting text to UTF-8 */
2425 utf8_string =
2426 convert_to_utf8 (workbook->utf8_converter, string,
2427 len, &err);
2428 free (string);
2429 if (err)
2430 return 0;
2431 check_format (utf8_string, &is_date, &is_datetime,
2432 &is_time);
2433 free (utf8_string);
2434 if (is_date || is_datetime || is_time)
2435 add_format_to_workbook (workbook, format_index,
2436 is_date, is_datetime,
2437 is_time);
2438 }
2439 format_index++;
2440 continue;
2441 }
2442
2443 if ((record_type.value == BIFF_XF_2
2444 && workbook->biff_version == FREEXL_BIFF_VER_2)
2445 || (record_type.value == BIFF_XF_3
2446 && workbook->biff_version == FREEXL_BIFF_VER_3)
2447 || (record_type.value == BIFF_XF_4
2448 && workbook->biff_version == FREEXL_BIFF_VER_4))
2449 {
2450 /* XF [Extended Format] marker found */
2451 unsigned char format;
2452 unsigned short s_format = 0;
2453 if (xls_fread
2454 (sizeof (workbook->record), workbook->record, 1,
2455 record_size.value, workbook->xls) != record_size.value)
2456 return 0;
2457 switch (workbook->biff_version)
2458 {
2459 case FREEXL_BIFF_VER_2:
2460 format = *(workbook->record + 2);
2461 format &= 0x3F;
2462 s_format = format;
2463 break;
2464 case FREEXL_BIFF_VER_3:
2465 case FREEXL_BIFF_VER_4:
2466 format = *(workbook->record + 1);
2467 s_format = format;
2468 break;
2469 };
2470 add_xf_to_workbook (workbook, s_format);
2471 continue;
2472 }
2473
2474 if ((record_type.value == 0x0000
2475 && workbook->biff_version == FREEXL_BIFF_VER_2)
2476 || (record_type.value == BIFF_DIMENSION
2477 && (workbook->biff_version == FREEXL_BIFF_VER_3
2478 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2479 {
2480 /* DIMENSION marker found */
2481 biff_word16 word16;
2482 unsigned int rows;
2483 unsigned short columns;
2484 char *utf8_name;
2485 if (xls_fread
2486 (sizeof (workbook->record), workbook->record, 1,
2487 record_size.value, workbook->xls) != record_size.value)
2488 return 0;
2489
2490 memcpy (word16.bytes, workbook->record + 2, 2);
2491 if (swap)
2492 swap16 (&word16);
2493 rows = word16.value;
2494 memcpy (word16.bytes, workbook->record + 6, 2);
2495 if (swap)
2496 swap16 (&word16);
2497 columns = word16.value;
2498 utf8_name = malloc (10);
2499 strcpy (utf8_name, "Worksheet");
2500 if (!add_sheet_to_workbook (workbook, 0, 0, 0, utf8_name))
2501 return 0;
2502 workbook->active_sheet = workbook->first_sheet;
2503 if (workbook->active_sheet != NULL)
2504 {
2505 /* setting Sheet dimensions */
2506 int ret;
2507 workbook->active_sheet->rows = rows;
2508 workbook->active_sheet->columns = columns;
2509 ret = allocate_cells (workbook);
2510 if (ret != FREEXL_OK)
2511 return 0;
2512 }
2513 continue;
2514 }
2515
2516 if (record_type.value == BIFF_INTEGER_2
2517 && workbook->biff_version == FREEXL_BIFF_VER_2)
2518 {
2519 /* INTEGER marker found */
2520 biff_word16 word16;
2521 unsigned short row;
2522 unsigned short col;
2523 unsigned short xf_index = 0;
2524 unsigned short num;
2525 int is_date;
2526 int is_datetime;
2527 int is_time;
2528 int ret;
2529 unsigned char format;
2530
2531 if (!check_legacy_undeclared_dimension
2532 (workbook, swap, record_type.value, record_size.value))
2533 return 0;
2534
2535 if (xls_fread
2536 (sizeof (workbook->record), workbook->record, 1,
2537 record_size.value, workbook->xls) != record_size.value)
2538 return 0;
2539
2540 memcpy (word16.bytes, workbook->record, 2);
2541 if (swap)
2542 swap16 (&word16);
2543 row = word16.value;
2544 memcpy (word16.bytes, workbook->record + 2, 2);
2545 if (swap)
2546 swap16 (&word16);
2547 col = word16.value;
2548
2549 format = *(workbook->record + 4);
2550 format &= 0x3F;
2551 xf_index = format;
2552 memcpy (word16.bytes, workbook->record + 7, 2);
2553 if (swap)
2554 swap16 (&word16);
2555 num = word16.value;
2556
2557 if (!check_xf_datetime
2558 (workbook, xf_index, &is_date, &is_datetime, &is_time))
2559 {
2560 is_date = 0;
2561 is_datetime = 0;
2562 is_time = 0;
2563 }
2564 if (is_date)
2565 ret =
2566 set_date_int_value (workbook, row, col,
2567 workbook->biff_date_mode, num);
2568 else if (is_datetime)
2569 ret =
2570 set_datetime_int_value (workbook, row, col,
2571 workbook->biff_date_mode, num);
2572 else if (is_time)
2573 ret = set_time_double_value (workbook, row, col, 0.0);
2574 else
2575 ret = set_int_value (workbook, row, col, num);
2576 if (ret != FREEXL_OK)
2577 return 0;
2578 continue;
2579 }
2580
2581 if ((record_type.value == BIFF_NUMBER_2
2582 && workbook->biff_version == FREEXL_BIFF_VER_2)
2583 || (record_type.value == BIFF_NUMBER
2584 && (workbook->biff_version == FREEXL_BIFF_VER_3
2585 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2586 {
2587 /* NUMBER marker found */
2588 biff_word16 word16;
2589 biff_float word_float;
2590 unsigned short row;
2591 unsigned short col;
2592 unsigned short xf_index = 0;
2593 double num;
2594 int is_date;
2595 int is_datetime;
2596 int is_time;
2597 int ret;
2598
2599 if (!check_legacy_undeclared_dimension
2600 (workbook, swap, record_type.value, record_size.value))
2601 return 0;
2602
2603 if (xls_fread
2604 (sizeof (workbook->record), workbook->record, 1,
2605 record_size.value, workbook->xls) != record_size.value)
2606 return 0;
2607
2608 memcpy (word16.bytes, workbook->record, 2);
2609 if (swap)
2610 swap16 (&word16);
2611 row = word16.value;
2612 memcpy (word16.bytes, workbook->record + 2, 2);
2613 if (swap)
2614 swap16 (&word16);
2615 col = word16.value;
2616
2617 if (workbook->biff_version == FREEXL_BIFF_VER_2)
2618 {
2619 /* BIFF2 */
2620 unsigned char format = *(workbook->record + 4);
2621 format &= 0x3F;
2622 xf_index = format;
2623 memcpy (word_float.bytes, workbook->record + 7, 8);
2624 if (swap)
2625 swap_float (&word_float);
2626 num = word_float.value;
2627 }
2628 else
2629 {
2630 /* any other sebsequent version */
2631 memcpy (word16.bytes, workbook->record + 4, 2);
2632 if (swap)
2633 swap16 (&word16);
2634 xf_index = word16.value;
2635 memcpy (word_float.bytes, workbook->record + 6, 8);
2636 if (swap)
2637 swap_float (&word_float);
2638 num = word_float.value;
2639 }
2640 if (!check_xf_datetime
2641 (workbook, xf_index, &is_date, &is_datetime, &is_time))
2642 {
2643 is_date = 0;
2644 is_datetime = 0;
2645 is_time = 0;
2646 }
2647 if (is_date)
2648 ret =
2649 set_date_double_value (workbook, row, col,
2650 workbook->biff_date_mode, num);
2651 else if (is_datetime)
2652 ret =
2653 set_datetime_double_value (workbook, row, col,
2654 workbook->biff_date_mode,
2655 num);
2656 else if (is_time)
2657 ret = set_time_double_value (workbook, row, col, num);
2658 else
2659 ret = set_double_value (workbook, row, col, num);
2660 if (ret != FREEXL_OK)
2661 return 0;
2662 continue;
2663 }
2664
2665 if ((record_type.value == BIFF_BOOLERR_2
2666 && workbook->biff_version == FREEXL_BIFF_VER_2)
2667 || (record_type.value == BIFF_BOOLERR
2668 && (workbook->biff_version == FREEXL_BIFF_VER_3
2669 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2670 {
2671 /* BOOLERR marker found */
2672 biff_word16 word16;
2673 unsigned short row;
2674 unsigned short col;
2675 unsigned char value;
2676 int ret;
2677
2678 if (!check_legacy_undeclared_dimension
2679 (workbook, swap, record_type.value, record_size.value))
2680 return 0;
2681
2682 if (xls_fread
2683 (sizeof (workbook->record), workbook->record, 1,
2684 record_size.value, workbook->xls) != record_size.value)
2685 return 0;
2686
2687 memcpy (word16.bytes, workbook->record, 2);
2688 if (swap)
2689 swap16 (&word16);
2690 row = word16.value;
2691 memcpy (word16.bytes, workbook->record + 2, 2);
2692 if (swap)
2693 swap16 (&word16);
2694 col = word16.value;
2695
2696 if (workbook->biff_version == FREEXL_BIFF_VER_2)
2697 {
2698 /* BIFF2 */
2699 value = *(workbook->record + 7);
2700 }
2701 else
2702 {
2703 /* any other sebsequent version */
2704 value = *(workbook->record + 6);
2705 }
2706 if (value != 0)
2707 value = 1;
2708 ret = set_int_value (workbook, row, col, value);
2709 if (ret != FREEXL_OK)
2710 return 0;
2711 continue;
2712 }
2713
2714 if (record_type.value == BIFF_RK
2715 && (workbook->biff_version == FREEXL_BIFF_VER_3
2716 || workbook->biff_version == FREEXL_BIFF_VER_4))
2717 {
2718 /* RK marker found */
2719 biff_word16 word16;
2720 biff_word32 word32;
2721 unsigned short row;
2722 unsigned short col;
2723 unsigned short xf_index;
2724 int int_value;
2725 double dbl_value;
2726 int is_date;
2727 int is_datetime;
2728 int is_time;
2729 int ret;
2730
2731 if (!check_legacy_undeclared_dimension
2732 (workbook, swap, record_type.value, record_size.value))
2733 return 0;
2734
2735 if (xls_fread
2736 (sizeof (workbook->record), workbook->record, 1,
2737 record_size.value, workbook->xls) != record_size.value)
2738 return 0;
2739
2740 memcpy (word16.bytes, workbook->record, 2);
2741 if (swap)
2742 swap16 (&word16);
2743 row = word16.value;
2744 memcpy (word16.bytes, workbook->record + 2, 2);
2745 if (swap)
2746 swap16 (&word16);
2747 col = word16.value;
2748 memcpy (word16.bytes, workbook->record + 4, 2);
2749 if (swap)
2750 swap16 (&word16);
2751 xf_index = word16.value;
2752 memcpy (word32.bytes, workbook->record + 6, 4);
2753 if (decode_rk_integer (word32.bytes, &int_value, swap))
2754 {
2755 if (!check_xf_datetime
2756 (workbook, xf_index, &is_date, &is_datetime,
2757 &is_time))
2758 {
2759 is_date = 0;
2760 is_datetime = 0;
2761 is_time = 0;
2762 }
2763 if (is_date)
2764 ret =
2765 set_date_int_value (workbook, row, col,
2766 workbook->biff_date_mode,
2767 int_value);
2768 else if (is_datetime)
2769 ret =
2770 set_datetime_int_value (workbook, row, col,
2771 workbook->biff_date_mode,
2772 int_value);
2773 else if (is_time)
2774 ret = set_time_double_value (workbook, row, col, 0.0);
2775 else
2776 ret = set_int_value (workbook, row, col, int_value);
2777 if (ret != FREEXL_OK)
2778 return 0;
2779 }
2780 else if (decode_rk_float (word32.bytes, &dbl_value, swap))
2781 {
2782 if (!check_xf_datetime
2783 (workbook, xf_index, &is_date, &is_datetime,
2784 &is_time))
2785 {
2786 is_date = 0;
2787 is_datetime = 0;
2788 is_time = 0;
2789 }
2790 if (is_date)
2791 ret =
2792 set_date_double_value (workbook, row, col,
2793 workbook->biff_date_mode,
2794 dbl_value);
2795 else if (is_datetime)
2796 ret =
2797 set_datetime_double_value (workbook, row, col,
2798 workbook->biff_date_mode,
2799 dbl_value);
2800 else if (is_time)
2801 ret =
2802 set_time_double_value (workbook, row, col,
2803 dbl_value);
2804 else
2805 ret =
2806 set_double_value (workbook, row, col, dbl_value);
2807 if (ret != FREEXL_OK)
2808 return 0;
2809 }
2810 else
2811 return 0;
2812 continue;
2813 }
2814
2815 if ((record_type.value == BIFF_LABEL_2
2816 && workbook->biff_version == FREEXL_BIFF_VER_2)
2817 || (record_type.value == BIFF_LABEL
2818 && (workbook->biff_version == FREEXL_BIFF_VER_3
2819 || workbook->biff_version == FREEXL_BIFF_VER_4)))
2820 {
2821 /* LABEL marker found */
2822 biff_word16 word16;
2823 char *string;
2824 char *utf8_string;
2825 unsigned int len;
2826 int err;
2827 unsigned short row;
2828 unsigned short col;
2829 unsigned char *p_string;
2830 int ret;
2831
2832 if (!check_legacy_undeclared_dimension
2833 (workbook, swap, record_type.value, record_size.value))
2834 return 0;
2835
2836 if (xls_fread
2837 (sizeof (workbook->record), workbook->record, 1,
2838 record_size.value, workbook->xls) != record_size.value)
2839 return 0;
2840
2841 memcpy (word16.bytes, workbook->record, 2);
2842 if (swap)
2843 swap16 (&word16);
2844 row = word16.value;
2845 memcpy (word16.bytes, workbook->record + 2, 2);
2846 if (swap)
2847 swap16 (&word16);
2848 col = word16.value;
2849
2850 if (workbook->biff_version == FREEXL_BIFF_VER_2)
2851 {
2852 len = *(workbook->record + 7);
2853 p_string = workbook->record + 8;
2854 }
2855 else
2856 {
2857 memcpy (word16.bytes, workbook->record + 6, 2);
2858 if (swap)
2859 swap16 (&word16);
2860 len = word16.value;
2861 p_string = workbook->record + 8;
2862 }
2863
2864 string = malloc (len);
2865 memcpy (string, p_string, len);
2866
2867 /* converting text to UTF-8 */
2868 utf8_string =
2869 convert_to_utf8 (workbook->utf8_converter, string, len,
2870 &err);
2871 free (string);
2872 if (err)
2873 return 0;
2874 ret = set_text_value (workbook, row, col, utf8_string);
2875 if (ret != FREEXL_OK)
2876 return 0;
2877 continue;
2878 }
2879
2880 /* skipping to next record */
2881 skip_to_next:
2882 where = record_size.value;
2883 if (fseek (workbook->xls, where, SEEK_CUR) != 0)
2884 return 0;
2885 }
2886
2887 /* saving the current record */
2888 workbook->record_type = record_type.value;
2889 workbook->record_size = record_size.value;
2890
2891 return 0;
2892 }
2893
2894 static int
check_already_done(biff_workbook * workbook)2895 check_already_done (biff_workbook * workbook)
2896 {
2897 /* checking if the currently active sheet has been already loaded */
2898 if (workbook->active_sheet != NULL)
2899 {
2900 if (workbook->active_sheet->already_done)
2901 {
2902 /* already loaded */
2903 return 1;
2904 }
2905 }
2906 return 0;
2907 }
2908
2909 static int
check_undeclared_dimension(biff_workbook * workbook,unsigned int row,unsigned short col)2910 check_undeclared_dimension (biff_workbook * workbook, unsigned int row,
2911 unsigned short col)
2912 {
2913 /* checking if DIMENSION isn't yet set */
2914 if (workbook->active_sheet != NULL)
2915 {
2916 if (workbook->active_sheet->valid_dimension == 0)
2917 {
2918 /* not yet set */
2919 if (row > workbook->active_sheet->rows)
2920 workbook->active_sheet->rows = row;
2921 if (col > workbook->active_sheet->columns)
2922 workbook->active_sheet->columns = col;
2923 return 1;
2924 }
2925 }
2926 return 0;
2927 }
2928
2929 static int
parse_biff_record(biff_workbook * workbook,int swap)2930 parse_biff_record (biff_workbook * workbook, int swap)
2931 {
2932 /*
2933 * attempting to parse a BIFF record
2934 * please note well: BIFF5 and BIFF8 versions only
2935 *
2936 * oldest BIFF2, BIFF3 and BIFF4 are processed separatedly
2937 * by read_legacy_biff() function
2938 *
2939 */
2940 biff_word16 word16;
2941 unsigned int base_offset = workbook->current_offset;
2942
2943 workbook->current_offset += workbook->record_size + 4;
2944
2945 if (workbook->record_type == BIFF_CONTINUE)
2946 {
2947 /* CONTINUE marker found: restoring the previous record type */
2948 if (workbook->prev_record_type == BIFF_SST)
2949 {
2950 /* continuing: SST [Shared String Table] */
2951 if (workbook->second_pass)
2952 return FREEXL_OK;
2953 return parse_SST (workbook, swap);
2954 }
2955 return FREEXL_OK;
2956 }
2957
2958 workbook->prev_record_type = workbook->record_type;
2959 if (workbook->ok_bof == -1)
2960 {
2961 /*
2962 * the first record is expected to be of BOF type
2963 * and contains Version related information
2964 */
2965 switch (workbook->record_type)
2966 {
2967 case BIFF_BOF: /* BIFF5 or BIFF8 */
2968 memcpy (word16.bytes, workbook->record, 2);
2969 if (swap)
2970 swap16 (&word16);
2971 if (word16.value == 0x0500)
2972 workbook->biff_version = FREEXL_BIFF_VER_5;
2973 else if (word16.value == 0x0600)
2974 workbook->biff_version = FREEXL_BIFF_VER_8;
2975 else
2976 {
2977 /* unknown, probably wrong or corrupted */
2978 workbook->ok_bof = 0;
2979 return FREEXL_BIFF_INVALID_BOF;
2980 }
2981 workbook->ok_bof = 1;
2982 break;
2983 default:
2984 workbook->ok_bof = 0;
2985 return FREEXL_BIFF_INVALID_BOF;
2986 };
2987 if (workbook->biff_version == FREEXL_BIFF_VER_8)
2988 workbook->biff_max_record_size = 8224;
2989 else
2990 workbook->biff_max_record_size = 2080;
2991 memcpy (word16.bytes, workbook->record + 2, 2);
2992 if (swap)
2993 swap16 (&word16);
2994 workbook->biff_content_type = word16.value;
2995 workbook->biff_code_page = 0;
2996 return FREEXL_OK;
2997 }
2998 if (workbook->ok_bof == 0)
2999 {
3000 /* we are expecting to find some BOF record here (not the main one) */
3001 switch (workbook->record_type)
3002 {
3003 case BIFF_BOF: /* BIFF5 or BIFF8 */
3004 workbook->ok_bof = 1;
3005 memcpy (word16.bytes, workbook->record + 2, 2);
3006 if (swap)
3007 swap16 (&word16);
3008 workbook->biff_content_type = word16.value;
3009 workbook->biff_code_page = 0;
3010 break;
3011 default:
3012 workbook->ok_bof = 0;
3013 return FREEXL_BIFF_INVALID_BOF;
3014 };
3015 select_active_sheet (workbook, base_offset);
3016 return FREEXL_OK;
3017 }
3018
3019 if (workbook->record_type == BIFF_EOF)
3020 {
3021 /* EOF marker found: the current stream is terminated */
3022 workbook->ok_bof = 0;
3023 workbook->biff_content_type = 0;
3024 workbook->biff_code_page = 0;
3025 return FREEXL_OK;
3026 }
3027
3028 if (workbook->record_type == BIFF_SST)
3029 {
3030 /* SST [Shared String Table] marker found */
3031 if (workbook->second_pass)
3032 return FREEXL_OK;
3033 return parse_SST (workbook, swap);
3034 }
3035
3036 if (workbook->record_type == BIFF_CODEPAGE)
3037 {
3038 /* CODEPAGE marker found */
3039 memcpy (word16.bytes, workbook->record, 2);
3040 if (swap)
3041 swap16 (&word16);
3042 workbook->biff_code_page = word16.value;
3043 if (workbook->ok_bof == 1)
3044 workbook->biff_book_code_page = word16.value;
3045 if (!biff_set_utf8_converter (workbook))
3046 return FREEXL_UNSUPPORTED_CHARSET;
3047 return FREEXL_OK;
3048 }
3049
3050 if (workbook->record_type == BIFF_DATEMODE)
3051 {
3052 /* DATEMODE marker found */
3053 memcpy (word16.bytes, workbook->record, 2);
3054 if (swap)
3055 swap16 (&word16);
3056 workbook->biff_date_mode = word16.value;
3057 return FREEXL_OK;
3058 }
3059
3060 if (workbook->record_type == BIFF_FILEPASS)
3061 {
3062 /* PASSWORD marker found */
3063 workbook->biff_obfuscated = 1;
3064 return FREEXL_OK;
3065 }
3066
3067 if (workbook->record_type == BIFF_SHEET)
3068 {
3069 /* SHEET marker found */
3070 char *utf8_name;
3071 char name[4096];
3072 int err;
3073 int len;
3074 biff_word32 offset;
3075
3076 if (workbook->second_pass)
3077 {
3078 if (workbook->active_sheet == NULL)
3079 workbook->active_sheet = workbook->first_sheet;
3080 else
3081 workbook->active_sheet = workbook->active_sheet->next;
3082 return FREEXL_OK;
3083 }
3084
3085 memcpy (offset.bytes, workbook->record, 4);
3086 if (swap)
3087 swap32 (&offset);
3088 len = workbook->record[6];
3089 if (len <= 0)
3090 {
3091 /* zero length - it's a preasumable crafted file intended to crash FreeXL */
3092 return FREEXL_CRAFTED_FILE;
3093 }
3094 if (workbook->biff_version == FREEXL_BIFF_VER_5)
3095 {
3096 /* BIFF5: codepage text */
3097 memcpy (name, workbook->record + 7, len);
3098 utf8_name =
3099 convert_to_utf8 (workbook->utf8_converter, name, len, &err);
3100 if (err)
3101 return FREEXL_INVALID_CHARACTER;
3102 }
3103 else
3104 {
3105 /* BIFF8: Unicode text */
3106 if (workbook->record[7] == 0x00)
3107 {
3108 /* 'stripped' UTF-16: requires padding */
3109 int i;
3110 for (i = 0; i < len; i++)
3111 {
3112 name[i * 2] = workbook->record[8 + i];
3113 name[(i * 2) + 1] = 0x00;
3114 }
3115 len *= 2;
3116 }
3117 else
3118 {
3119 /* already encoded as UTF-16 */
3120 len *= 2;
3121 memcpy (name, workbook->record + 8, len);
3122 }
3123 utf8_name =
3124 convert_to_utf8 (workbook->utf16_converter, name, len,
3125 &err);
3126 if (err)
3127 return FREEXL_INVALID_CHARACTER;
3128 }
3129 if (!add_sheet_to_workbook
3130 (workbook, offset.value, workbook->record[4], workbook->record[5],
3131 utf8_name))
3132 return FREEXL_INSUFFICIENT_MEMORY;
3133 return FREEXL_OK;
3134 }
3135
3136 if (workbook->record_type == BIFF_DIMENSION
3137 && (workbook->biff_version == FREEXL_BIFF_VER_5
3138 || workbook->biff_version == FREEXL_BIFF_VER_8))
3139 {
3140 /* DIMENSION marker found */
3141 biff_word16 word16;
3142 biff_word32 word32;
3143 unsigned int rows;
3144 unsigned short columns;
3145
3146 if (workbook->second_pass)
3147 return FREEXL_OK;
3148 if (workbook->biff_version == FREEXL_BIFF_VER_8)
3149 {
3150 /* BIFF8: 32-bit row index */
3151 memcpy (word32.bytes, workbook->record + 4, 4);
3152 if (swap)
3153 swap32 (&word32);
3154 rows = word32.value;
3155 memcpy (word16.bytes, workbook->record + 10, 2);
3156 if (swap)
3157 swap16 (&word16);
3158 columns = word16.value;
3159 }
3160 else
3161 {
3162 /* any previous version: 16-bit row index */
3163 memcpy (word16.bytes, workbook->record + 2, 2);
3164 if (swap)
3165 swap16 (&word16);
3166 rows = word16.value;
3167 memcpy (word16.bytes, workbook->record + 6, 2);
3168 if (swap)
3169 swap16 (&word16);
3170 columns = word16.value;
3171 }
3172 if (workbook->active_sheet != NULL)
3173 {
3174 /* setting Sheet dimensions */
3175 int ret;
3176 workbook->active_sheet->rows = rows;
3177 workbook->active_sheet->columns = columns;
3178 ret = allocate_cells (workbook);
3179 if (ret != FREEXL_OK)
3180 return ret;
3181 workbook->active_sheet->valid_dimension = 1;
3182 }
3183 return FREEXL_OK;
3184 }
3185
3186 if (workbook->magic1 == FREEXL_MAGIC_INFO)
3187 {
3188 /* when open in INFO mode we can safely ignore any other */
3189 return FREEXL_OK;
3190 }
3191
3192 if (workbook->record_type == BIFF_FORMAT
3193 && (workbook->biff_version == FREEXL_BIFF_VER_5
3194 || workbook->biff_version == FREEXL_BIFF_VER_8))
3195 {
3196 /* FORMAT marker found */
3197 biff_word16 word16;
3198 char *string;
3199 char *utf8_string;
3200 unsigned int len;
3201 int err;
3202 unsigned short format_index;
3203 unsigned char *p_string;
3204 int is_date = 0;
3205 int is_datetime = 0;
3206 int is_time = 0;
3207
3208 if (workbook->second_pass)
3209 return FREEXL_OK;
3210 if (workbook->biff_version == FREEXL_BIFF_VER_5)
3211 {
3212 /* CODEPAGE string */
3213 memcpy (word16.bytes, workbook->record, 2);
3214 if (swap)
3215 swap16 (&word16);
3216 format_index = word16.value;
3217 len = *(workbook->record + 3);
3218 p_string = workbook->record + 3;
3219 string = malloc (len);
3220 memcpy (string, p_string, len);
3221
3222 /* converting text to UTF-8 */
3223 utf8_string =
3224 convert_to_utf8 (workbook->utf8_converter, string, len,
3225 &err);
3226 free (string);
3227 if (err)
3228 return FREEXL_INVALID_CHARACTER;
3229 check_format (utf8_string, &is_date, &is_datetime, &is_time);
3230 free (utf8_string);
3231 if (is_date || is_datetime || is_time)
3232 add_format_to_workbook (workbook, format_index, is_date,
3233 is_datetime, is_time);
3234 }
3235 if (workbook->biff_version == FREEXL_BIFF_VER_8)
3236 {
3237 /* please note: this always is UTF-16 */
3238 int utf16 = 0;
3239 unsigned int start_offset;
3240 unsigned int extra_skip;
3241 memcpy (word16.bytes, workbook->record, 2);
3242 if (swap)
3243 swap16 (&word16);
3244 format_index = word16.value;
3245 memcpy (word16.bytes, workbook->record + 2, 2);
3246 if (swap)
3247 swap16 (&word16);
3248 len = word16.value;
3249 p_string = workbook->record + 4;
3250 get_unicode_params (p_string, swap, &start_offset, &utf16,
3251 &extra_skip);
3252 p_string += start_offset;
3253 if (len <= 0)
3254 {
3255 /* zero length - it's a preasumable crafted file intended to crash FreeXL */
3256 return FREEXL_CRAFTED_FILE;
3257 }
3258 if (!parse_unicode_string
3259 (workbook->utf16_converter, len, utf16, p_string,
3260 &utf8_string))
3261 return FREEXL_INVALID_CHARACTER;
3262 check_format (utf8_string, &is_date, &is_datetime, &is_time);
3263 free (utf8_string);
3264 if (is_date || is_datetime || is_time)
3265 add_format_to_workbook (workbook, format_index, is_date,
3266 is_datetime, is_time);
3267 }
3268 return FREEXL_OK;
3269 }
3270
3271 if (workbook->record_type == BIFF_XF
3272 && (workbook->biff_version == FREEXL_BIFF_VER_5
3273 || workbook->biff_version == FREEXL_BIFF_VER_8))
3274 {
3275 /* XF [Extended Format] marker found */
3276 unsigned short s_format = 0;
3277 biff_word16 word16;
3278 if (workbook->second_pass)
3279 return FREEXL_OK;
3280 switch (workbook->biff_version)
3281 {
3282 case FREEXL_BIFF_VER_5:
3283 case FREEXL_BIFF_VER_8:
3284 memcpy (word16.bytes, workbook->record + 2, 2);
3285 if (swap)
3286 swap16 (&word16);
3287 s_format = word16.value;
3288 break;
3289 };
3290 add_xf_to_workbook (workbook, s_format);
3291 return FREEXL_OK;
3292 }
3293
3294 if ((workbook->record_type == BIFF_NUMBER
3295 && (workbook->biff_version == FREEXL_BIFF_VER_5
3296 || workbook->biff_version == FREEXL_BIFF_VER_8)))
3297 {
3298 /* NUMBER marker found */
3299 biff_word16 word16;
3300 biff_float word_float;
3301 unsigned short row;
3302 unsigned short col;
3303 unsigned short xf_index = 0;
3304 double num;
3305 int is_date;
3306 int is_datetime;
3307 int is_time;
3308 int ret;
3309
3310 if (check_already_done (workbook))
3311 return FREEXL_OK;
3312
3313 memcpy (word16.bytes, workbook->record, 2);
3314 if (swap)
3315 swap16 (&word16);
3316 row = word16.value;
3317 memcpy (word16.bytes, workbook->record + 2, 2);
3318 if (swap)
3319 swap16 (&word16);
3320 col = word16.value;
3321
3322 if (check_undeclared_dimension (workbook, row, col))
3323 return FREEXL_OK;
3324
3325 memcpy (word16.bytes, workbook->record + 4, 2);
3326 if (swap)
3327 swap16 (&word16);
3328 xf_index = word16.value;
3329 memcpy (word_float.bytes, workbook->record + 6, 8);
3330 if (swap)
3331 swap_float (&word_float);
3332 num = word_float.value;
3333
3334 if (!check_xf_datetime_58
3335 (workbook, xf_index, &is_date, &is_datetime, &is_time))
3336 {
3337 is_date = 0;
3338 is_datetime = 0;
3339 is_time = 0;
3340 }
3341 if (is_date)
3342 ret =
3343 set_date_double_value (workbook, row, col,
3344 workbook->biff_date_mode, num);
3345 else if (is_datetime)
3346 ret =
3347 set_datetime_double_value (workbook, row, col,
3348 workbook->biff_date_mode, num);
3349 else if (is_time)
3350 ret = set_time_double_value (workbook, row, col, num);
3351 else
3352 ret = set_double_value (workbook, row, col, num);
3353 if (ret != FREEXL_OK)
3354 return ret;
3355 return FREEXL_OK;
3356 }
3357
3358 if ((workbook->record_type == BIFF_BOOLERR
3359 && (workbook->biff_version == FREEXL_BIFF_VER_5
3360 || workbook->biff_version == FREEXL_BIFF_VER_8)))
3361 {
3362 /* BOOLERR marker found */
3363 biff_word16 word16;
3364 unsigned short row;
3365 unsigned short col;
3366 unsigned char value;
3367 int ret;
3368
3369 if (check_already_done (workbook))
3370 return FREEXL_OK;
3371
3372 memcpy (word16.bytes, workbook->record, 2);
3373 if (swap)
3374 swap16 (&word16);
3375 row = word16.value;
3376 memcpy (word16.bytes, workbook->record + 2, 2);
3377 if (swap)
3378 swap16 (&word16);
3379 col = word16.value;
3380
3381 if (check_undeclared_dimension (workbook, row, col))
3382 return FREEXL_OK;
3383
3384 value = *(workbook->record + 6);
3385 if (value != 0)
3386 value = 1;
3387 ret = set_int_value (workbook, row, col, value);
3388 if (ret != FREEXL_OK)
3389 return ret;
3390 return FREEXL_OK;
3391 }
3392
3393 if (workbook->record_type == BIFF_RK
3394 && (workbook->biff_version == FREEXL_BIFF_VER_5
3395 || workbook->biff_version == FREEXL_BIFF_VER_8))
3396 {
3397 /* RK marker found */
3398 biff_word16 word16;
3399 biff_word32 word32;
3400 unsigned short row;
3401 unsigned short col;
3402 unsigned short xf_index;
3403 int int_value;
3404 double dbl_value;
3405 int is_date;
3406 int is_datetime;
3407 int is_time;
3408 int ret;
3409
3410 if (check_already_done (workbook))
3411 return FREEXL_OK;
3412
3413 memcpy (word16.bytes, workbook->record, 2);
3414 if (swap)
3415 swap16 (&word16);
3416 row = word16.value;
3417 memcpy (word16.bytes, workbook->record + 2, 2);
3418 if (swap)
3419 swap16 (&word16);
3420 col = word16.value;
3421
3422 if (check_undeclared_dimension (workbook, row, col))
3423 return FREEXL_OK;
3424
3425 memcpy (word16.bytes, workbook->record + 4, 2);
3426 if (swap)
3427 swap16 (&word16);
3428 xf_index = word16.value;
3429 memcpy (word32.bytes, workbook->record + 6, 4);
3430 if (decode_rk_integer (word32.bytes, &int_value, swap))
3431 {
3432 if (!check_xf_datetime_58
3433 (workbook, xf_index, &is_date, &is_datetime, &is_time))
3434 {
3435 is_date = 0;
3436 is_datetime = 0;
3437 is_time = 0;
3438 }
3439 if (is_date)
3440 ret =
3441 set_date_int_value (workbook, row, col,
3442 workbook->biff_date_mode,
3443 int_value);
3444 else if (is_datetime)
3445 ret =
3446 set_datetime_int_value (workbook, row, col,
3447 workbook->biff_date_mode,
3448 int_value);
3449 else if (is_time)
3450 ret = set_time_double_value (workbook, row, col, 0.0);
3451 else
3452 ret = set_int_value (workbook, row, col, int_value);
3453 if (ret != FREEXL_OK)
3454 return ret;
3455 }
3456 else if (decode_rk_float (word32.bytes, &dbl_value, swap))
3457 {
3458 if (!check_xf_datetime_58
3459 (workbook, xf_index, &is_date, &is_datetime, &is_time))
3460 {
3461 is_date = 0;
3462 is_datetime = 0;
3463 is_time = 0;
3464 }
3465 if (is_date)
3466 ret =
3467 set_date_double_value (workbook, row, col,
3468 workbook->biff_date_mode,
3469 dbl_value);
3470 else if (is_datetime)
3471 ret =
3472 set_datetime_double_value (workbook, row, col,
3473 workbook->biff_date_mode,
3474 dbl_value);
3475 else if (is_time)
3476 ret = set_time_double_value (workbook, row, col, dbl_value);
3477 else
3478 ret = set_double_value (workbook, row, col, dbl_value);
3479 if (ret != FREEXL_OK)
3480 return ret;
3481 }
3482 else
3483 return FREEXL_ILLEGAL_RK_VALUE;
3484 return FREEXL_OK;
3485 }
3486
3487 if (workbook->record_type == BIFF_MULRK
3488 && (workbook->biff_version == FREEXL_BIFF_VER_5
3489 || workbook->biff_version == FREEXL_BIFF_VER_8))
3490 {
3491 /* MULRK marker found */
3492 biff_word16 word16;
3493 biff_word32 word32;
3494 unsigned short row;
3495 unsigned short col;
3496 unsigned short xf_index;
3497 unsigned int off = 4;
3498 int int_value;
3499 double dbl_value;
3500 int is_date;
3501 int is_datetime;
3502 int is_time;
3503 int ret;
3504
3505 if (check_already_done (workbook))
3506 return FREEXL_OK;
3507
3508 memcpy (word16.bytes, workbook->record, 2);
3509 if (swap)
3510 swap16 (&word16);
3511 row = word16.value;
3512 memcpy (word16.bytes, workbook->record + 2, 2);
3513 if (swap)
3514 swap16 (&word16);
3515 col = word16.value;
3516
3517 if (check_undeclared_dimension (workbook, row, col))
3518 return FREEXL_OK;
3519
3520 while ((off + 6) < workbook->record_size)
3521 {
3522 /* fetching one cell value */
3523 memcpy (word16.bytes, workbook->record + off, 2);
3524 if (swap)
3525 swap16 (&word16);
3526 xf_index = word16.value;
3527 memcpy (word32.bytes, workbook->record + off + 2, 4);
3528 if (decode_rk_integer (word32.bytes, &int_value, swap))
3529 {
3530 if (!check_xf_datetime_58
3531 (workbook, xf_index, &is_date, &is_datetime,
3532 &is_time))
3533 {
3534 is_date = 0;
3535 is_datetime = 0;
3536 is_time = 0;
3537 }
3538 if (is_date)
3539 ret =
3540 set_date_int_value (workbook, row, col,
3541 workbook->biff_date_mode,
3542 int_value);
3543 else if (is_datetime)
3544 ret =
3545 set_datetime_int_value (workbook, row, col,
3546 workbook->biff_date_mode,
3547 int_value);
3548 else if (is_time)
3549 ret = set_time_double_value (workbook, row, col, 0.0);
3550 else
3551 ret = set_int_value (workbook, row, col, int_value);
3552 if (ret != FREEXL_OK)
3553 return ret;
3554 }
3555 else if (decode_rk_float (word32.bytes, &dbl_value, swap))
3556 {
3557 if (!check_xf_datetime_58
3558 (workbook, xf_index, &is_date, &is_datetime,
3559 &is_time))
3560 {
3561 is_date = 0;
3562 is_datetime = 0;
3563 is_time = 0;
3564 }
3565 if (is_date)
3566 ret =
3567 set_date_double_value (workbook, row, col,
3568 workbook->biff_date_mode,
3569 dbl_value);
3570 else if (is_datetime)
3571 ret =
3572 set_datetime_double_value (workbook, row, col,
3573 workbook->biff_date_mode,
3574 dbl_value);
3575 else if (is_time)
3576 ret =
3577 set_time_double_value (workbook, row, col,
3578 dbl_value);
3579 else
3580 ret =
3581 set_double_value (workbook, row, col, dbl_value);
3582 if (ret != FREEXL_OK)
3583 return ret;
3584 }
3585 else
3586 return FREEXL_ILLEGAL_MULRK_VALUE;
3587 off += 6;
3588 col++;
3589 }
3590 return FREEXL_OK;
3591 }
3592
3593 if (workbook->record_type == BIFF_LABEL
3594 && (workbook->biff_version == FREEXL_BIFF_VER_5
3595 || workbook->biff_version == FREEXL_BIFF_VER_8))
3596 {
3597 /* LABEL marker found */
3598 biff_word16 word16;
3599 char *string;
3600 char *utf8_string;
3601 unsigned int len;
3602 int err;
3603 unsigned short row;
3604 unsigned short col;
3605 unsigned char *p_string;
3606 int ret;
3607
3608 if (check_already_done (workbook))
3609 return FREEXL_OK;
3610
3611 memcpy (word16.bytes, workbook->record, 2);
3612 if (swap)
3613 swap16 (&word16);
3614 row = word16.value;
3615 memcpy (word16.bytes, workbook->record + 2, 2);
3616 if (swap)
3617 swap16 (&word16);
3618 col = word16.value;
3619
3620 if (check_undeclared_dimension (workbook, row, col))
3621 return FREEXL_OK;
3622
3623 memcpy (word16.bytes, workbook->record + 6, 2);
3624 if (swap)
3625 swap16 (&word16);
3626 len = word16.value;
3627 p_string = workbook->record + 8;
3628
3629 if (workbook->biff_version == FREEXL_BIFF_VER_5)
3630 {
3631 /* CODEPAGE string */
3632 string = malloc (len);
3633 memcpy (string, p_string, len);
3634
3635 /* converting text to UTF-8 */
3636 utf8_string =
3637 convert_to_utf8 (workbook->utf8_converter, string, len,
3638 &err);
3639 free (string);
3640 if (err)
3641 return FREEXL_INVALID_CHARACTER;
3642 }
3643 else
3644 {
3645 /* please note: this always is UTF-16 [BIFF8] */
3646 int utf16 = 0;
3647 unsigned int start_offset;
3648 unsigned int extra_skip;
3649 get_unicode_params (p_string, swap, &start_offset, &utf16,
3650 &extra_skip);
3651 p_string += start_offset;
3652 if (len <= 0)
3653 {
3654 /* zero length - it's a preasumable crafted file intended to crash FreeXL */
3655 return FREEXL_CRAFTED_FILE;
3656 }
3657 if (!parse_unicode_string
3658 (workbook->utf16_converter, len, utf16, p_string,
3659 &utf8_string))
3660 return FREEXL_INVALID_CHARACTER;
3661 }
3662 ret = set_text_value (workbook, row, col, utf8_string);
3663 if (ret != FREEXL_OK)
3664 return ret;
3665 return FREEXL_OK;
3666 }
3667
3668 if (workbook->record_type == BIFF_LABEL_SST
3669 && workbook->biff_version == FREEXL_BIFF_VER_8)
3670 {
3671 /* LABELSST marker found */
3672 biff_word16 word16;
3673 biff_word32 word32;
3674 unsigned short row;
3675 unsigned short col;
3676 unsigned int string_index;
3677 const char *utf8_string;
3678 int ret;
3679
3680 if (check_already_done (workbook))
3681 return FREEXL_OK;
3682
3683 memcpy (word16.bytes, workbook->record, 2);
3684 if (swap)
3685 swap16 (&word16);
3686 row = word16.value;
3687 memcpy (word16.bytes, workbook->record + 2, 2);
3688 if (swap)
3689 swap16 (&word16);
3690 col = word16.value;
3691
3692 if (check_undeclared_dimension (workbook, row, col))
3693 return FREEXL_OK;
3694
3695 memcpy (word32.bytes, workbook->record + 6, 4);
3696 if (swap)
3697 swap32 (&word32);
3698 string_index = word32.value;
3699 utf8_string = find_in_SST (workbook, string_index);
3700 if (!utf8_string)
3701 return FREEXL_BIFF_ILLEGAL_SST_INDEX;
3702 ret = set_sst_value (workbook, row, col, utf8_string);
3703 if (ret != FREEXL_OK)
3704 return ret;
3705 return FREEXL_OK;
3706 }
3707
3708 return FREEXL_OK;
3709 }
3710
3711 static int
read_cfbf_sector(biff_workbook * workbook,unsigned char * buf)3712 read_cfbf_sector (biff_workbook * workbook, unsigned char *buf)
3713 {
3714 /* attempting to read a physical sector from the CFBF stream */
3715 long where = (workbook->current_sector + 1) * workbook->fat->sector_size;
3716 if (fseek (workbook->xls, where, SEEK_SET) != 0)
3717 return FREEXL_CFBF_SEEK_ERROR;
3718 if (xls_fread
3719 (sizeof (biff_workbook), buf, 1, workbook->fat->sector_size,
3720 workbook->xls) != workbook->fat->sector_size)
3721 return FREEXL_CFBF_READ_ERROR;
3722 return FREEXL_OK;
3723 }
3724
3725 static int
read_cfbf_next_sector(biff_workbook * workbook,int * errcode)3726 read_cfbf_next_sector (biff_workbook * workbook, int *errcode)
3727 {
3728 /* attempting to read the next sector from the CFBF stream */
3729 int ret;
3730 fat_entry *entry = get_fat_entry (workbook->fat, workbook->current_sector);
3731 if (entry == NULL)
3732 {
3733 *errcode = FREEXL_CFBF_ILLEGAL_FAT_ENTRY;
3734 return 0;
3735 }
3736 if (entry->next_sector == 0xfffffffe)
3737 {
3738 /* EOF: end-of-chain marker found */
3739 *errcode = FREEXL_OK;
3740 return -1;
3741 }
3742 workbook->current_sector = entry->next_sector;
3743 if (workbook->sector_end > workbook->fat->sector_size)
3744 {
3745 /* shifting back the current sector buffer */
3746 memcpy (workbook->sector_buf,
3747 workbook->sector_buf + workbook->fat->sector_size,
3748 workbook->fat->sector_size);
3749 workbook->p_in -= workbook->fat->sector_size;
3750 }
3751 /* reading into the second half of the sector buffer */
3752 ret =
3753 read_cfbf_sector (workbook,
3754 workbook->sector_buf + workbook->fat->sector_size);
3755 if (ret != FREEXL_OK)
3756 {
3757 *errcode = ret;
3758 return 0;
3759 }
3760 workbook->bytes_read += workbook->fat->sector_size;
3761 if (workbook->bytes_read > workbook->size)
3762 {
3763 /* incomplete last sector */
3764 workbook->sector_end =
3765 (workbook->fat->sector_size * 2) - (workbook->bytes_read -
3766 workbook->size);
3767 }
3768 else
3769 workbook->sector_end = (workbook->fat->sector_size * 2);
3770 *errcode = FREEXL_OK;
3771 return 1;
3772 }
3773
3774 static int
read_biff_next_record(biff_workbook * workbook,int swap,int * errcode)3775 read_biff_next_record (biff_workbook * workbook, int swap, int *errcode)
3776 {
3777 /*
3778 * attempting to read the next BIFF record
3779 * from the Workbook stream
3780 */
3781 biff_word16 record_type;
3782 biff_word16 record_size;
3783 int ret;
3784
3785 if (workbook->sector_ready == 0)
3786 {
3787 /* first access: loading the first stream sector */
3788 ret = read_cfbf_sector (workbook, workbook->sector_buf);
3789 if (ret != FREEXL_OK)
3790 {
3791 *errcode = ret;
3792 return 0;
3793 }
3794 workbook->current_sector = workbook->start_sector;
3795 workbook->bytes_read += workbook->fat->sector_size;
3796 if (workbook->bytes_read > workbook->size)
3797 {
3798 /* incomplete last sector */
3799 workbook->sector_end =
3800 workbook->fat->sector_size - (workbook->bytes_read -
3801 workbook->size);
3802 }
3803 else
3804 workbook->sector_end = workbook->fat->sector_size;
3805 workbook->p_in = workbook->sector_buf;
3806 workbook->sector_ready = 1;
3807 }
3808
3809 /*
3810 * four bytes are now expected:
3811 * USHORT record-type
3812 * USHORT record-size
3813 */
3814 if ((workbook->p_in - workbook->sector_buf) + 4 > workbook->sector_end)
3815 {
3816 /* reading next sector */
3817 ret = read_cfbf_next_sector (workbook, errcode);
3818 if (ret == -1)
3819 return -1; /* EOF found */
3820 if (ret == 0)
3821 return 0;
3822 }
3823 /* fetching record-type and record-size */
3824 memcpy (record_type.bytes, workbook->p_in, 2);
3825 workbook->p_in += 2;
3826 memcpy (record_size.bytes, workbook->p_in, 2);
3827 workbook->p_in += 2;
3828 if (swap)
3829 {
3830 /* BIG endian arch: swap required */
3831 swap16 (&record_type);
3832 swap16 (&record_size);
3833 }
3834 /*
3835 / Sandro 2011-09-04
3836 / apparently a record-type 0x0000 and a record-size 0
3837 / seems to be an alternative way to mark EOF
3838 */
3839 if (record_type.value == 0x0000 && record_size.value == 0)
3840 return -1;
3841
3842 /*
3843 / Sandro 2017-09-07
3844 / fixing a security issue reported by
3845 / Cisco [TALOS-2017-430]
3846 */
3847 if (record_size.value > sizeof (workbook->record))
3848 return -1;
3849
3850 /* saving the current record */
3851 workbook->record_type = record_type.value;
3852 workbook->record_size = record_size.value;
3853
3854 if (((workbook->p_in + workbook->record_size) - workbook->sector_buf) >
3855 workbook->sector_end)
3856 {
3857 /* the current record spans on the following sector(s) */
3858 unsigned int already_done;
3859 unsigned int chunk =
3860 workbook->sector_end - (workbook->p_in - workbook->sector_buf);
3861 if (workbook->sector_end < (workbook->p_in - workbook->sector_buf))
3862 return -1;
3863 memcpy (workbook->record, workbook->p_in, chunk);
3864 workbook->p_in += chunk;
3865 already_done = chunk;
3866
3867 while (already_done < workbook->record_size)
3868 {
3869 /* reading a further sector */
3870 ret = read_cfbf_next_sector (workbook, errcode);
3871 if (ret == -1)
3872 return -1; /* EOF found */
3873 if (ret == 0)
3874 return 0;
3875 chunk = workbook->record_size - already_done;
3876 if (chunk <= workbook->fat->sector_size)
3877 {
3878 /* ok, finished: whole record reassembled */
3879 memcpy (workbook->record + already_done, workbook->p_in,
3880 chunk);
3881 workbook->p_in += chunk;
3882 goto record_done;
3883 }
3884 /* record still spanning on the following sector */
3885 memcpy (workbook->record + already_done, workbook->p_in,
3886 workbook->fat->sector_size);
3887 workbook->p_in += workbook->fat->sector_size;
3888 already_done += workbook->fat->sector_size;
3889 }
3890 }
3891 else
3892 {
3893 /* the record is fully contained into the current sector */
3894 memcpy (workbook->record, workbook->p_in, workbook->record_size);
3895 workbook->p_in += record_size.value;
3896 }
3897 record_done:
3898 ret = parse_biff_record (workbook, swap);
3899 if (ret != FREEXL_OK)
3900 return 0;
3901 *errcode = FREEXL_OK;
3902 return 1;
3903 }
3904
3905 static int
read_mini_biff_next_record(biff_workbook * workbook,int swap,int * errcode)3906 read_mini_biff_next_record (biff_workbook * workbook, int swap, int *errcode)
3907 {
3908 /*
3909 * attempting to read the next BIFF record
3910 * from the Workbook MINI-stream
3911 */
3912 biff_word16 record_type;
3913 biff_word16 record_size;
3914 int ret;
3915
3916 /*
3917 * four bytes are now expected:
3918 * USHORT record-type
3919 * USHORT record-size
3920 */
3921 if ((workbook->p_in - workbook->fat->miniStream) + 4 > (int) workbook->size)
3922 return -1; /* EOF found */
3923
3924 /* fetching record-type and record-size */
3925 memcpy (record_type.bytes, workbook->p_in, 2);
3926 workbook->p_in += 2;
3927 memcpy (record_size.bytes, workbook->p_in, 2);
3928 workbook->p_in += 2;
3929 if (swap)
3930 {
3931 /* BIG endian arch: swap required */
3932 swap16 (&record_type);
3933 swap16 (&record_size);
3934 }
3935 /* saving the current record */
3936 workbook->record_type = record_type.value;
3937 workbook->record_size = record_size.value;
3938
3939 if (workbook->record_size >= 8192)
3940 return 0; /* malformed or crafted file */
3941
3942 if ((workbook->p_in - workbook->fat->miniStream) + workbook->record_size >
3943 (int) workbook->size)
3944 return 0; /* unexpected EOF */
3945
3946 memcpy (workbook->record, workbook->p_in, workbook->record_size);
3947 workbook->p_in += record_size.value;
3948
3949 ret = parse_biff_record (workbook, swap);
3950 if (ret != FREEXL_OK)
3951 return 0;
3952 *errcode = FREEXL_OK;
3953 return 1;
3954 }
3955
3956 static int
parse_dir_entry(void * block,int swap,iconv_t utf16_utf8_converter,unsigned int * workbook,unsigned int * workbook_len,unsigned int * miniFAT_start,unsigned int * miniFAT_len,int * rootEntry)3957 parse_dir_entry (void *block, int swap, iconv_t utf16_utf8_converter,
3958 unsigned int *workbook, unsigned int *workbook_len,
3959 unsigned int *miniFAT_start, unsigned int *miniFAT_len,
3960 int *rootEntry)
3961 {
3962 /* parsing a Directory entry */
3963 char *name;
3964 int err;
3965 cfbf_dir_entry *entry = (cfbf_dir_entry *) block;
3966 if (swap)
3967 {
3968 /* BIG endian arch: swap required */
3969 swap16 (&(entry->name_size));
3970 swap32 (&(entry->previous));
3971 swap32 (&(entry->next));
3972 swap32 (&(entry->child));
3973 swap32 (&(entry->timestamp_1));
3974 swap32 (&(entry->timestamp_2));
3975 swap32 (&(entry->timestamp_3));
3976 swap32 (&(entry->timestamp_4));
3977 swap32 (&(entry->start_sector));
3978 swap32 (&(entry->extra_size));
3979 swap32 (&(entry->size));
3980 }
3981
3982 name =
3983 convert_to_utf8 (utf16_utf8_converter, entry->name,
3984 entry->name_size.value, &err);
3985 if (err)
3986 return FREEXL_INVALID_CHARACTER;
3987
3988 if (strcmp (name, "Root Entry") == 0)
3989 {
3990 *miniFAT_start = entry->start_sector.value;
3991 *miniFAT_len = entry->size.value;
3992 *rootEntry = 1;
3993 }
3994 else
3995 *rootEntry = 0;
3996
3997 if (strcmp (name, "Workbook") == 0 || strcmp (name, "Book") == 0)
3998 {
3999 *workbook = entry->start_sector.value;
4000 *workbook_len = entry->size.value;
4001 }
4002 free (name);
4003 return FREEXL_OK;
4004 }
4005
4006 static int
get_workbook_stream(biff_workbook * workbook)4007 get_workbook_stream (biff_workbook * workbook)
4008 {
4009 /* attempting to locate the Workbook into the main FAT directory */
4010 long where;
4011 unsigned int sector = workbook->fat->directory_start;
4012 unsigned char dir_block[4096];
4013 int max_entries;
4014 int i_entry;
4015 unsigned char *p_entry;
4016 unsigned int workbook_start;
4017 unsigned int workbook_len;
4018 unsigned int miniFAT_start;
4019 unsigned int miniFAT_len;
4020 int rootEntry;
4021 int ret;
4022
4023 if (workbook->fat->sector_size == 4096)
4024 max_entries = 32;
4025 else
4026 max_entries = 4;
4027
4028 where = (sector + 1) * workbook->fat->sector_size;
4029 if (fseek (workbook->xls, where, SEEK_SET) != 0)
4030 return FREEXL_CFBF_SEEK_ERROR;
4031 /* reading a FAT Directory block [sector] */
4032 if (xls_fread
4033 (sizeof (dir_block), dir_block, 1, workbook->fat->sector_size,
4034 workbook->xls) != workbook->fat->sector_size)
4035 return FREEXL_CFBF_READ_ERROR;
4036 workbook_start = 0xFFFFFFFF;
4037 for (i_entry = 0; i_entry < max_entries; i_entry++)
4038 {
4039 /* scanning dir entries until Workbook found */
4040 p_entry = dir_block + (i_entry * 128);
4041 ret =
4042 parse_dir_entry (p_entry, workbook->fat->swap,
4043 workbook->utf16_converter, &workbook_start,
4044 &workbook_len, &miniFAT_start, &miniFAT_len,
4045 &rootEntry);
4046 if (ret != FREEXL_OK)
4047 return ret;
4048 if (rootEntry)
4049 {
4050 /* ok, Root Entry found */
4051 workbook->fat->miniFAT_start = miniFAT_start;
4052 workbook->fat->miniFAT_len = miniFAT_len;
4053 }
4054 if (workbook_start != 0xFFFFFFFF)
4055 {
4056 /* ok, Workbook found */
4057 workbook->start_sector = workbook_start;
4058 workbook->size = workbook_len;
4059 workbook->current_sector = workbook_start;
4060 return FREEXL_OK;
4061 }
4062 }
4063 return FREEXL_BIFF_WORKBOOK_NOT_FOUND;
4064 }
4065
4066 static void *
create_utf16_utf8_converter(void)4067 create_utf16_utf8_converter (void)
4068 {
4069 /* creating the UTF16/UTF8 converter and returning on opaque reference to it */
4070 iconv_t cvt = iconv_open ("UTF-8", "UTF-16LE");
4071 if (cvt == (iconv_t) (-1))
4072 return NULL;
4073 return cvt;
4074 }
4075
4076 static int
check_little_endian_arch()4077 check_little_endian_arch ()
4078 {
4079 /* checking if target CPU is a little-endian one */
4080 biff_word32 word32;
4081 word32.value = 1;
4082 if (word32.bytes[0] == 0)
4083 return 1;
4084 return 0;
4085 }
4086
4087 static int
common_open(const char * path,const void ** xls_handle,int magic)4088 common_open (const char *path, const void **xls_handle, int magic)
4089 {
4090 /* opening and initializing the Workbook */
4091 biff_workbook *workbook;
4092 biff_sheet *p_sheet;
4093 fat_chain *chain = NULL;
4094 int errcode;
4095 int ret;
4096 int swap = check_little_endian_arch ();
4097
4098 *xls_handle = NULL;
4099 /* allocating the Workbook struct */
4100 workbook = alloc_workbook (magic);
4101 if (!workbook)
4102 return FREEXL_INSUFFICIENT_MEMORY;
4103 *xls_handle = workbook;
4104
4105 workbook->xls = fopen (path, "rb");
4106 if (workbook->xls == NULL)
4107 return FREEXL_FILE_NOT_FOUND;
4108
4109 /*
4110 * the XLS file is internally structured as a FAT-like
4111 * file-system (Compound File Binary Format, CFBF)
4112 * so we'll start by parsing the FAT
4113 */
4114 chain = read_cfbf_header (workbook, swap, &errcode);
4115 if (!chain)
4116 {
4117 /* it's not a CFBF file: testing older BIFF-(2,3,4) formats */
4118 if (read_legacy_biff (workbook, swap))
4119 return FREEXL_OK;
4120 goto stop;
4121 }
4122
4123 /* transferring FAT chain ownership */
4124 workbook->fat = chain;
4125 chain = NULL;
4126
4127 /* creating the UTF16/UTF8 converter */
4128 workbook->utf16_converter = create_utf16_utf8_converter ();
4129 if (workbook->utf16_converter == NULL)
4130 {
4131 errcode = FREEXL_UNSUPPORTED_CHARSET;
4132 goto stop;
4133 }
4134
4135 /* we'll now retrieve the FAT main Directory */
4136 ret = get_workbook_stream (workbook);
4137 if (ret != FREEXL_OK)
4138 {
4139 errcode = ret;
4140 goto stop;
4141 }
4142
4143 /* we'll now parse the Workbook */
4144 if (workbook->size <= workbook->fat->miniCutOff)
4145 {
4146 /* mini-stream stored in miniFAT */
4147 int ret = read_mini_stream (workbook, &errcode);
4148 if (!ret)
4149 goto stop;
4150 workbook->p_in = workbook->fat->miniStream;
4151 while (1)
4152 {
4153 ret = read_mini_biff_next_record (workbook, swap, &errcode);
4154 if (ret == -1)
4155 break; /* EOF */
4156 if (ret == 0)
4157 goto stop;
4158 }
4159 }
4160 else
4161 {
4162 /* normal stream */
4163 while (1)
4164 {
4165 int ret = read_biff_next_record (workbook, swap, &errcode);
4166 if (ret == -1)
4167 break; /* EOF */
4168 if (ret == 0)
4169 goto stop;
4170 }
4171 }
4172
4173 p_sheet = workbook->first_sheet;
4174 while (p_sheet)
4175 {
4176 if (p_sheet->valid_dimension == 0)
4177 {
4178 /* setting Sheet dimensions */
4179 int ret;
4180 p_sheet->rows += 1;
4181 p_sheet->columns += 1;
4182 ret = allocate_cells (workbook);
4183 if (ret != FREEXL_OK)
4184 {
4185 errcode = ret;
4186 goto stop;
4187 }
4188 p_sheet->valid_dimension = 1;
4189 workbook->second_pass = 1;
4190 }
4191 else
4192 p_sheet->already_done = 1;
4193 p_sheet = p_sheet->next;
4194 }
4195
4196 if (workbook->second_pass)
4197 {
4198 /* attempting to fetch cell values performing a second pass */
4199 workbook->active_sheet = NULL;
4200 workbook->start_sector = 0;
4201 workbook->size = 0;
4202 workbook->current_sector = 0;
4203 workbook->bytes_read = 0;
4204 workbook->current_offset = 0;
4205 workbook->p_in = workbook->sector_buf;
4206 workbook->sector_end = 0;
4207 workbook->sector_ready = 0;
4208 workbook->ok_bof = -1;
4209
4210 ret = get_workbook_stream (workbook);
4211 if (ret != FREEXL_OK)
4212 {
4213 errcode = ret;
4214 goto stop;
4215 }
4216
4217 /* we'll now parse the Workbook */
4218 if (workbook->size <= workbook->fat->miniCutOff)
4219 {
4220 /* mini-stream stored in miniFAT */
4221 int ret = read_mini_stream (workbook, &errcode);
4222 if (!ret)
4223 goto stop;
4224 workbook->p_in = workbook->fat->miniStream;
4225 while (1)
4226 {
4227 ret =
4228 read_mini_biff_next_record (workbook, swap, &errcode);
4229 if (ret == -1)
4230 break; /* EOF */
4231 if (ret == 0)
4232 goto stop;
4233 }
4234 }
4235 else
4236 {
4237 /* normal stream */
4238 while (1)
4239 {
4240 int ret =
4241 read_biff_next_record (workbook, swap, &errcode);
4242 if (ret == -1)
4243 break; /* EOF */
4244 if (ret == 0)
4245 goto stop;
4246 }
4247 }
4248 }
4249
4250 return FREEXL_OK;
4251
4252 stop:
4253 if (chain)
4254 destroy_fat_chain (chain);
4255 if (workbook)
4256 destroy_workbook (workbook);
4257 *xls_handle = NULL;
4258 return errcode;
4259 }
4260
4261 FREEXL_DECLARE int
freexl_open(const char * path,const void ** xls_handle)4262 freexl_open (const char *path, const void **xls_handle)
4263 {
4264 /* opening and initializing the Workbook */
4265 return common_open (path, xls_handle, FREEXL_MAGIC_START);
4266 }
4267
4268 FREEXL_DECLARE int
freexl_open_info(const char * path,const void ** xls_handle)4269 freexl_open_info (const char *path, const void **xls_handle)
4270 {
4271 /* opening and initializing the Workbook (only for Info) */
4272 return common_open (path, xls_handle, FREEXL_MAGIC_INFO);
4273 }
4274
4275 FREEXL_DECLARE int
freexl_close(const void * xls_handle)4276 freexl_close (const void *xls_handle)
4277 {
4278 /* attempting to destroy the Workbook */
4279 biff_workbook *workbook = (biff_workbook *) xls_handle;
4280 if (!workbook)
4281 return FREEXL_NULL_HANDLE;
4282 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4283 || workbook->magic1 == FREEXL_MAGIC_START)
4284 && workbook->magic2 == FREEXL_MAGIC_END)
4285 ;
4286 else
4287 return FREEXL_INVALID_HANDLE;
4288
4289 /* destroying the workbook */
4290 destroy_workbook (workbook);
4291
4292 return FREEXL_OK;
4293 }
4294
4295 FREEXL_DECLARE int
freexl_get_info(const void * xls_handle,unsigned short what,unsigned int * info)4296 freexl_get_info (const void *xls_handle, unsigned short what,
4297 unsigned int *info)
4298 {
4299 /* attempting to retrieve some info */
4300 biff_workbook *workbook = (biff_workbook *) xls_handle;
4301 if (!workbook)
4302 return FREEXL_NULL_HANDLE;
4303 if (!info)
4304 return FREEXL_NULL_ARGUMENT;
4305 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4306 || workbook->magic1 == FREEXL_MAGIC_START)
4307 && workbook->magic2 == FREEXL_MAGIC_END)
4308 ;
4309 else
4310 return FREEXL_INVALID_HANDLE;
4311
4312 switch (what)
4313 {
4314 case FREEXL_CFBF_VERSION:
4315 *info = FREEXL_UNKNOWN;
4316 if (workbook->cfbf_version == 3)
4317 *info = FREEXL_CFBF_VER_3;
4318 if (workbook->cfbf_version == 4)
4319 *info = FREEXL_CFBF_VER_4;
4320 return FREEXL_OK;
4321 case FREEXL_CFBF_SECTOR_SIZE:
4322 *info = FREEXL_UNKNOWN;
4323 if (workbook->cfbf_sector_size == 512)
4324 *info = FREEXL_CFBF_SECTOR_512;
4325 if (workbook->cfbf_sector_size == 4096)
4326 *info = FREEXL_CFBF_SECTOR_4096;
4327 return FREEXL_OK;
4328 case FREEXL_CFBF_FAT_COUNT:
4329 if (workbook->fat != NULL)
4330 *info = workbook->fat->fat_array_count;
4331 else
4332 *info = 0;
4333 return FREEXL_OK;
4334 case FREEXL_BIFF_MAX_RECSIZE:
4335 *info = FREEXL_UNKNOWN;
4336 if (workbook->biff_max_record_size == 2080)
4337 *info = FREEXL_BIFF_MAX_RECSZ_2080;
4338 if (workbook->biff_max_record_size == 8224)
4339 *info = FREEXL_BIFF_MAX_RECSZ_8224;
4340 return FREEXL_OK;
4341 case FREEXL_BIFF_DATEMODE:
4342 *info = FREEXL_UNKNOWN;
4343 if (workbook->biff_date_mode == 0)
4344 *info = FREEXL_BIFF_DATEMODE_1900;
4345 if (workbook->biff_date_mode == 1)
4346 *info = FREEXL_BIFF_DATEMODE_1904;
4347 return FREEXL_OK;
4348 case FREEXL_BIFF_CODEPAGE:
4349 switch (workbook->biff_book_code_page)
4350 {
4351 case 0x016F:
4352 *info = FREEXL_BIFF_ASCII;
4353 break;
4354 case 0x01B5:
4355 *info = FREEXL_BIFF_CP437;
4356 break;
4357 case 0x02D0:
4358 *info = FREEXL_BIFF_CP720;
4359 break;
4360 case 0x02E1:
4361 *info = FREEXL_BIFF_CP737;
4362 break;
4363 case 0x0307:
4364 *info = FREEXL_BIFF_CP775;
4365 break;
4366 case 0x0352:
4367 *info = FREEXL_BIFF_CP850;
4368 break;
4369 case 0x0354:
4370 *info = FREEXL_BIFF_CP852;
4371 break;
4372 case 0x0357:
4373 *info = FREEXL_BIFF_CP855;
4374 break;
4375 case 0x0359:
4376 *info = FREEXL_BIFF_CP857;
4377 break;
4378 case 0x035A:
4379 *info = FREEXL_BIFF_CP858;
4380 break;
4381 case 0x035C:
4382 *info = FREEXL_BIFF_CP860;
4383 break;
4384 case 0x035D:
4385 *info = FREEXL_BIFF_CP861;
4386 break;
4387 case 0x035E:
4388 *info = FREEXL_BIFF_CP862;
4389 break;
4390 case 0x035F:
4391 *info = FREEXL_BIFF_CP863;
4392 break;
4393 case 0x0360:
4394 *info = FREEXL_BIFF_CP864;
4395 break;
4396 case 0x0361:
4397 *info = FREEXL_BIFF_CP865;
4398 break;
4399 case 0x0362:
4400 *info = FREEXL_BIFF_CP866;
4401 break;
4402 case 0x0365:
4403 *info = FREEXL_BIFF_CP869;
4404 break;
4405 case 0x036A:
4406 *info = FREEXL_BIFF_CP874;
4407 break;
4408 case 0x03A4:
4409 *info = FREEXL_BIFF_CP932;
4410 break;
4411 case 0x03A8:
4412 *info = FREEXL_BIFF_CP936;
4413 break;
4414 case 0x03B5:
4415 *info = FREEXL_BIFF_CP949;
4416 break;
4417 case 0x03B6:
4418 *info = FREEXL_BIFF_CP950;
4419 break;
4420 case 0x04B0:
4421 *info = FREEXL_BIFF_UTF16LE;
4422 break;
4423 case 0x04E2:
4424 *info = FREEXL_BIFF_CP1250;
4425 break;
4426 case 0x04E3:
4427 *info = FREEXL_BIFF_CP1251;
4428 break;
4429 case 0x04E4:
4430 case 0x8001:
4431 *info = FREEXL_BIFF_CP1252;
4432 break;
4433 case 0x04E5:
4434 *info = FREEXL_BIFF_CP1253;
4435 break;
4436 case 0x04E6:
4437 *info = FREEXL_BIFF_CP1254;
4438 break;
4439 case 0x04E7:
4440 *info = FREEXL_BIFF_CP1255;
4441 break;
4442 case 0x04E8:
4443 *info = FREEXL_BIFF_CP1256;
4444 break;
4445 case 0x04E9:
4446 *info = FREEXL_BIFF_CP1257;
4447 break;
4448 case 0x04EA:
4449 *info = FREEXL_BIFF_CP1258;
4450 break;
4451 case 0x0551:
4452 *info = FREEXL_BIFF_CP1361;
4453 break;
4454 case 0x2710:
4455 case 0x8000:
4456 *info = FREEXL_BIFF_MACROMAN;
4457 break;
4458 default:
4459 *info = FREEXL_UNKNOWN;
4460 break;
4461 };
4462 return FREEXL_OK;
4463 case FREEXL_BIFF_VERSION:
4464 *info = FREEXL_UNKNOWN;
4465 if (workbook->biff_version == 2)
4466 *info = FREEXL_BIFF_VER_2;
4467 if (workbook->biff_version == 3)
4468 *info = FREEXL_BIFF_VER_3;
4469 if (workbook->biff_version == 4)
4470 *info = FREEXL_BIFF_VER_4;
4471 if (workbook->biff_version == 5)
4472 *info = FREEXL_BIFF_VER_5;
4473 if (workbook->biff_version == 8)
4474 *info = FREEXL_BIFF_VER_8;
4475 return FREEXL_OK;
4476 case FREEXL_BIFF_STRING_COUNT:
4477 *info = workbook->shared_strings.string_count;
4478 return FREEXL_OK;
4479 case FREEXL_BIFF_SHEET_COUNT:
4480 *info = get_worksheet_count (workbook);
4481 return FREEXL_OK;
4482 case FREEXL_BIFF_FORMAT_COUNT:
4483 *info = workbook->max_format_index;
4484 return FREEXL_OK;
4485 case FREEXL_BIFF_XF_COUNT:
4486 *info = workbook->biff_xf_next_index;
4487 return FREEXL_OK;
4488 case FREEXL_BIFF_PASSWORD:
4489 *info = FREEXL_UNKNOWN;
4490 if (workbook->biff_obfuscated == 0)
4491 *info = FREEXL_BIFF_PLAIN;
4492 /* 2019-01-30
4493 * issue reported by David Binderman
4494 *
4495 if (workbook->biff_obfuscated == 0)
4496 */
4497 else if (workbook->biff_obfuscated == 1)
4498 *info = FREEXL_BIFF_OBFUSCATED;
4499 else
4500 *info = workbook->biff_xf_next_index;
4501 return FREEXL_OK;
4502 };
4503
4504 return FREEXL_INVALID_INFO_ARG;
4505 }
4506
4507 FREEXL_DECLARE int
freexl_get_FAT_entry(const void * xls_handle,unsigned int sector_index,unsigned int * next_sector_index)4508 freexl_get_FAT_entry (const void *xls_handle, unsigned int sector_index,
4509 unsigned int *next_sector_index)
4510 {
4511 /* attempting to retrieve some FAT entry [by index] */
4512 fat_entry *entry;
4513 biff_workbook *workbook = (biff_workbook *) xls_handle;
4514 if (!workbook)
4515 return FREEXL_NULL_HANDLE;
4516 if (!next_sector_index)
4517 return FREEXL_NULL_ARGUMENT;
4518 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4519 || workbook->magic1 == FREEXL_MAGIC_START)
4520 && workbook->magic2 == FREEXL_MAGIC_END)
4521 ;
4522 else
4523 return FREEXL_INVALID_HANDLE;
4524
4525 if (workbook->fat == NULL)
4526 return FREEXL_CFBF_EMPTY_FAT_CHAIN;
4527
4528 entry = get_fat_entry (workbook->fat, sector_index);
4529 if (entry == NULL)
4530 return FREEXL_CFBF_ILLEGAL_FAT_ENTRY;
4531 *next_sector_index = entry->next_sector;
4532
4533 return FREEXL_OK;
4534
4535 }
4536
4537 FREEXL_DECLARE int
freexl_get_worksheet_name(const void * xls_handle,unsigned short worksheet_index,const char ** string)4538 freexl_get_worksheet_name (const void *xls_handle,
4539 unsigned short worksheet_index, const char **string)
4540 {
4541 /* attempting to retrieve some Worksheet name [by index] */
4542 unsigned int count = 0;
4543 biff_sheet *worksheet;
4544 biff_workbook *workbook = (biff_workbook *) xls_handle;
4545 if (!workbook)
4546 return FREEXL_NULL_HANDLE;
4547 if (!string)
4548 return FREEXL_NULL_ARGUMENT;
4549 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4550 || workbook->magic1 == FREEXL_MAGIC_START)
4551 && workbook->magic2 == FREEXL_MAGIC_END)
4552 ;
4553 else
4554 return FREEXL_INVALID_HANDLE;
4555
4556 worksheet = workbook->first_sheet;
4557 while (worksheet)
4558 {
4559 if (count == worksheet_index)
4560 {
4561 *string = worksheet->utf8_name;
4562 return FREEXL_OK;
4563 }
4564 count++;
4565 worksheet = worksheet->next;
4566 }
4567 return FREEXL_BIFF_ILLEGAL_SHEET_INDEX;
4568 }
4569
4570 FREEXL_DECLARE int
freexl_select_active_worksheet(const void * xls_handle,unsigned short worksheet_index)4571 freexl_select_active_worksheet (const void *xls_handle,
4572 unsigned short worksheet_index)
4573 {
4574 /* selecting the currently active worksheet [by index] */
4575 unsigned int count = 0;
4576 biff_sheet *worksheet;
4577 biff_workbook *workbook = (biff_workbook *) xls_handle;
4578 if (!workbook)
4579 return FREEXL_NULL_HANDLE;
4580 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4581 || workbook->magic1 == FREEXL_MAGIC_START)
4582 && workbook->magic2 == FREEXL_MAGIC_END)
4583 ;
4584 else
4585 return FREEXL_INVALID_HANDLE;
4586
4587 worksheet = workbook->first_sheet;
4588 while (worksheet)
4589 {
4590 if (count == worksheet_index)
4591 {
4592 workbook->active_sheet = worksheet;
4593 return FREEXL_OK;
4594 }
4595 count++;
4596 worksheet = worksheet->next;
4597 }
4598 return FREEXL_BIFF_ILLEGAL_SHEET_INDEX;
4599 }
4600
4601 FREEXL_DECLARE int
freexl_get_active_worksheet(const void * xls_handle,unsigned short * worksheet_index)4602 freexl_get_active_worksheet (const void *xls_handle,
4603 unsigned short *worksheet_index)
4604 {
4605 /* retrieving the currently active worksheet index */
4606 unsigned int count = 0;
4607 biff_sheet *worksheet;
4608 biff_workbook *workbook = (biff_workbook *) xls_handle;
4609 if (!workbook)
4610 return FREEXL_NULL_HANDLE;
4611 if (!worksheet_index)
4612 return FREEXL_NULL_ARGUMENT;
4613 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4614 || workbook->magic1 == FREEXL_MAGIC_START)
4615 && workbook->magic2 == FREEXL_MAGIC_END)
4616 ;
4617 else
4618 return FREEXL_INVALID_HANDLE;
4619
4620 worksheet = workbook->first_sheet;
4621 while (worksheet)
4622 {
4623 if (workbook->active_sheet == worksheet)
4624 {
4625 *worksheet_index = count;
4626 return FREEXL_OK;
4627 }
4628 count++;
4629 worksheet = worksheet->next;
4630 }
4631 return FREEXL_BIFF_UNSELECTED_SHEET;
4632 }
4633
4634 FREEXL_DECLARE int
freexl_worksheet_dimensions(const void * xls_handle,unsigned int * rows,unsigned short * columns)4635 freexl_worksheet_dimensions (const void *xls_handle, unsigned int *rows,
4636 unsigned short *columns)
4637 {
4638 /* dimensions: currently selected Worksheet */
4639 biff_workbook *workbook = (biff_workbook *) xls_handle;
4640 if (!workbook)
4641 return FREEXL_NULL_HANDLE;
4642 if (!rows)
4643 return FREEXL_NULL_ARGUMENT;
4644 if (!columns)
4645 return FREEXL_NULL_ARGUMENT;
4646 if ((workbook->magic1 == FREEXL_MAGIC_INFO
4647 || workbook->magic1 == FREEXL_MAGIC_START)
4648 && workbook->magic2 == FREEXL_MAGIC_END)
4649 ;
4650 else
4651 return FREEXL_INVALID_HANDLE;
4652
4653 if (workbook->active_sheet == NULL)
4654 return FREEXL_BIFF_UNSELECTED_SHEET;
4655
4656 *rows = workbook->active_sheet->rows;
4657 *columns = workbook->active_sheet->columns;
4658 return FREEXL_OK;
4659 }
4660
4661 FREEXL_DECLARE int
freexl_get_SST_string(const void * xls_handle,unsigned short string_index,const char ** string)4662 freexl_get_SST_string (const void *xls_handle, unsigned short string_index,
4663 const char **string)
4664 {
4665 /* attempting to retrieve some SST entry [by index] */
4666 biff_workbook *workbook = (biff_workbook *) xls_handle;
4667 if (!workbook)
4668 return FREEXL_NULL_HANDLE;
4669 if (!string)
4670 return FREEXL_NULL_ARGUMENT;
4671 if (workbook->magic1 == FREEXL_MAGIC_START
4672 && workbook->magic2 == FREEXL_MAGIC_END)
4673 ;
4674 else
4675 return FREEXL_INVALID_HANDLE;
4676
4677 *string = NULL;
4678 if (workbook->shared_strings.utf8_strings == NULL)
4679 return FREEXL_BIFF_INVALID_SST;
4680 if (string_index < workbook->shared_strings.string_count)
4681 {
4682 *string = *(workbook->shared_strings.utf8_strings + string_index);
4683 return FREEXL_OK;
4684 }
4685 return FREEXL_BIFF_ILLEGAL_SST_INDEX;
4686 }
4687
4688 FREEXL_DECLARE int
freexl_get_cell_value(const void * xls_handle,unsigned int row,unsigned short column,FreeXL_CellValue * val)4689 freexl_get_cell_value (const void *xls_handle, unsigned int row,
4690 unsigned short column, FreeXL_CellValue * val)
4691 {
4692 /* attempting to fetch a cell value */
4693 biff_cell_value *p_cell;
4694 biff_workbook *workbook = (biff_workbook *) xls_handle;
4695 if (!workbook)
4696 return FREEXL_NULL_HANDLE;
4697 if (!val)
4698 return FREEXL_NULL_ARGUMENT;
4699 if (workbook->magic1 == FREEXL_MAGIC_START
4700 && workbook->magic2 == FREEXL_MAGIC_END)
4701 ;
4702 else
4703 return FREEXL_INVALID_HANDLE;
4704
4705 if (row >= workbook->active_sheet->rows
4706 || column >= workbook->active_sheet->columns)
4707 return FREEXL_ILLEGAL_CELL_ROW_COL;
4708 if (workbook->active_sheet->cell_values == NULL)
4709 return FREEXL_ILLEGAL_CELL_ROW_COL;
4710
4711 p_cell =
4712 workbook->active_sheet->cell_values +
4713 (row * workbook->active_sheet->columns) + column;
4714 /*
4715 / kindly contributed by Brad Hards: 2011-09-03
4716 / this function now return the Cell Value using the
4717 / FreeXL_CellValue multi-type container
4718 */
4719 val->type = p_cell->type;
4720 switch (p_cell->type)
4721 {
4722 case FREEXL_CELL_INT:
4723 val->value.int_value = p_cell->value.int_value;
4724 break;
4725 case FREEXL_CELL_DOUBLE:
4726 val->value.double_value = p_cell->value.dbl_value;
4727 break;
4728 case FREEXL_CELL_DATE:
4729 case FREEXL_CELL_DATETIME:
4730 case FREEXL_CELL_TIME:
4731 case FREEXL_CELL_TEXT:
4732 val->value.text_value = p_cell->value.text_value;
4733 break;
4734 case FREEXL_CELL_SST_TEXT:
4735 val->value.text_value = p_cell->value.sst_value;
4736 break;
4737 };
4738
4739 return FREEXL_OK;
4740 }
4741