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