1 /*! \file xlhtml.c
2 \brief converts excel files to Html
3
4 xlhtml generates HTML, XML, csv and tab-delimitted versions of Excel
5 spreadsheets.
6 */
7
8 /*
9 Copyright 2002 Charles N Wyble <jackshck@yahoo.com>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25 */
26
27 #include "tuneable.h"
28 #include "xlhtml.h"
29
30
31
32 static char SectionName[2][12] = /* The section of the Excel Stream where the workbooks are kept */
33 {
34 "/Workbook", /*!< Excel 97 & 2000 */
35 "/Book" /*!< Everything else ? */
36 };
37
38
39 int numCustomColors = 0;
40 U8 **customColors = 0;
41 char colorTab[MAX_COLORS][8] =
42 {
43 "000000", /* FIXME: Need to find these first 8 colors! */
44 "FFFFFF",
45 "FFFFFF",
46 "FFFFFF",
47 "FFFFFF",
48 "FFFFFF",
49 "FFFFFF",
50 "FFFFFF",
51 "FFFFFF", /*0x08 - This one's Black, too ??? */
52 "FFFFFF", /* This one's normal */
53 "red", /* "FF0000", */
54 "lime", /* "00FF00", */
55 "blue", /* "0000FF", */
56 "FFFF00",
57 "FF00FF",
58 "aqua", /* "00FFFF", */
59 "800000", /* 0x10 */
60 "green", /* "008000", */
61 "navy", /* "000080", */
62 "808000",
63 "800080",
64 "teal", /* "008080", */
65 "C0C0C0",
66 "gray", /* "808080", */
67 "9999FF", /* 0x18 */
68 "993366",
69 "FFFFCC",
70 "CCFFFF",
71 "660066",
72 "FF8080",
73 "0066CC",
74 "CCCCFF",
75 "000080",
76 "FF00FF", /* 0x20 */
77 "FFFF00",
78 "00FFFF",
79 "800080",
80 "800000",
81 "008080",
82 "0000FF",
83 "00CCFF", /* 0x28 */
84 "CCFFFF",
85 "CCFFCC",
86 "FFFF99",
87 "99CCFF",
88 "FF99CC",
89 "CC99FF",
90 "FFCC99",
91 "3366FF", /* 0x30 */
92 "33CCCC",
93 "99CC00",
94 "FFCC00",
95 "FF9900",
96 "FF6600",
97 "666699",
98 "969696",
99 "003366", /* 0x38 */
100 "339966",
101 "003300",
102 "333300",
103 "993300",
104 "993366",
105 "333399",
106 "333333",
107 "FFFFFF" /* 0x40 */
108 };
109
110 int DatesR1904 = 0; /*!< Flag that the dates are based on McIntosh Dates system */
111
112 /* FIXME: Support major languages here...not just English */
113 const char month_abbr[12][5] = { "Jan", "Feb", "Mar", "Apr", "May", "June",
114 "July", "Aug", "Sep", "Oct", "Nov", "Dec" };
115
116
117 /* Function Prototypes */
118
119 /* These functions are in support.c */
120 extern void print_version(void);
121 extern void display_usage(void);
122 extern void do_cr(void);
123 extern void OutputTableHTML(void);
124 extern S32 getLong(U8 *);
125 extern U16 getShort(U8 *);
126 extern void getDouble(U8 *, F64 *);
127 extern int null_string(U8 *);
128 extern void FracToTime(U8 *, int *, int *, int *, int *);
129 extern void NumToDate(long, int *, int *, int *);
130 extern void RKtoDouble(S32, F64 *);
131
132 /* This function is in xml.c */
133 extern void OutputTableXML(void);
134
135 /* This function is in ascii.c */
136 void OutputPartialTableAscii(void);
137
138 /* These functions are in html.c */
139 extern void output_start_html_attr(html_attr *h, unsigned int, int);
140 extern void output_end_html_attr(html_attr *h);
141 extern void output_footer(void);
142 extern void output_header(void);
143
144 COLE_LOCATE_ACTION_FUNC scan_file;
145 void main_line_processor(U16, U16, U32, U16, U8);
146 void SetupExtraction(void);
147 void decodeBoolErr(U16, U16, char *);
148 int IsCellNumeric(cell *);
149 int IsCellSafe(cell *);
150 int IsCellFormula(cell *);
151 void output_cell(cell *, int);
152 void output_formatted_data(uni_string *, U16, int, int);
153 void PrintFloatComma(char *, int, F64);
154 void print_as_fraction(F64, int);
155 void trim_sheet_edges(unsigned int);
156 void update_default_font(unsigned int);
157 void incr_f_cnt(uni_string *);
158 int get_default_font(void);
159 void update_default_alignment(unsigned int, int);
160 void OutputString(uni_string *);
161 void OutputCharCorrected(U8);
162 void update_crun_info(U16 *loc, U16 *fnt_idx, U16 crun_cnt, U8 *fmt_run);
163 void put_utf8(U16);
164 void print_utf8(U16);
165 void uni_string_clear(uni_string *);
166 int uni_string_comp(uni_string *, uni_string *);
167 void html_flag_init(html_attr *h);
168 void output_start_font_attribute(html_attr *h, U16 fnt_idx);
169
170 /* The array update functions */
171 int ws_init(int);
172 int add_more_worksheet_ptrs(void);
173 int resize_c_array(work_sheet *, U32, U16);
174 void add_wb_array(U16, U16, U16, U16, U8, U8 *, U16, U16, U8 *);
175 void update_cell_xf(U16, U16, U16);
176 void update_cell_hyperlink(U16 r, U16 c, U8 *hyperlink, int len, U16 type);
177 void add_str_array(U8, U8 *, U16, U8 *, U8);
178 void add_font(U16, U16, U16, U16, U16, U8, U16, U8 *, U16);
179 void add_ws_title(U16, U8 *, U16);
180 void add_xf_array(U16 fnt_idx, U16 fmt_idx, U16 gen, U16 align,
181 U16 indent, U16 b_style, U16 b_l_color, U32 b_t_color, U16 cell_color);
182
183
184 /* Global data */
185 char filename[256];
186 int file_version = 0;
187 U32 next_string=0;
188 unsigned int next_font=0, next_ws_title=0, next_xf=0;
189 U8 working_buffer[WBUFF_SIZE];
190 unsigned int bufidx, buflast; /*!< Needed for working buffer */
191 U8 grbit=0; /*!< Needed by the SST Opcode FC */
192 U16 crun=0, cch=0; /*!< Needed by the SST Opcode FC */
193 U32 extrst=0; /*!< Needed by the SST Opcode FC */
194 U16 nonascii = 0; /*!< Needed by the SST Opcode FC */
195 int sheet_count=-2; /*!< Number of worksheets found */
196 U16 last_opcode = -1; /*!< Used for the continue command */
197 unsigned int cont_grbit=0, cont_str_array=0;
198 uni_string default_font; /*!< Font for table */
199 int default_fontsize = 3; /*!< Default font size for table */
200 char *default_alignment = 0; /*!< Alignment for table */
201 int first_sheet = 0; /*!< First worksheet to display */
202 int last_sheet = WORKSHEETS_INCR-1; /*!< The last worksheet to display */
203 S16 xp=0, xr1=-1, xr2=-1, xc1=-1, xc2=-1; /*!< Extraction info... */
204 int currency_symbol = '$'; /*!< What to use for currency */
205 U16 str_formula_row = 0; /*!< Data holders for string formulas */
206 U16 str_formula_col = 0; /*!< Data holders for string formulas */
207 U16 str_formula_format = 0; /*!< Data holders for string formulas */
208
209 /* Limits */
210 unsigned int max_fonts = FONTS_INCR;
211 unsigned int max_xformats = XFORMATS_INCR;
212 unsigned long max_strings = STRINGS_INCR;
213 unsigned int max_worksheets = WORKSHEETS_INCR;
214
215
216 /* Global arrays */
217 xf_attr **xf_array;
218 work_sheet **ws_array;
219 uni_string **str_array;
220 font_attr **font_array;
221 fnt_cnt *f_cnt;
222 int fnt_size_cnt[7]; /*!< Html has only 7 sizes... */
223 uni_string author;
224 char *title = 0;
225 char *lastUpdated = 0;
226
227 /* Command Line flags */
228 int use_colors = 1; /*!< Whether or not to use colors in output */
229 int aggressive = 0; /*!< Aggressive html optimization */
230 int formula_warnings = 1; /*!< Whether or not to suppress formula warnings */
231 int center_tables = 0; /*!< Whether or not to center justify tables or leave it left */
232 int trim_edges = 0; /*!< Whether or not to trim the edges of columns or rows */
233 char *default_text_color = "000000";
234 char *default_background_color="FFFFFF";
235 char *default_image=NULL; /*!< Point to background image */
236 int Ascii = 0; /*!< Whether or not to out ascii instaed of html */
237 int Csv = 0; /*!< Whether or not to out csv instaed of html */
238 int OutputXML = 0; /*!< Output as xml */
239 int DumpPage = 0; /*!< Dump page count & max cols & rows */
240 int Xtract = 0; /*!< Extract a range on a page. */
241 int MultiByte = 0; /*!< Output as multibyte */
242 int NoHeaders = 0; /*!< Dont output html header */
243
244
245 /* Some Global Flags */
246 int notAccurate = 0; /*!< Flag used to indicate that stale data was used */
247 int NoFormat = 0; /*!< Flag used to indicated unimplemented format */
248 int NotImplemented = 0; /*!< Flag to print unimplemented cell type message */
249 int Unsupported = 0; /*!< Flag to print unsupported cell type message */
250 int MaxPalExceeded = 0;
251 int MaxXFExceeded = 0;
252 int MaxFormatsExceeded = 0;
253 int MaxColExceeded = 0;
254 int MaxRowExceeded = 0;
255 int MaxWorksheetsExceeded = 0;
256 int MaxStringsExceeded = 0;
257 int MaxFontsExceeded = 0;
258 int UnicodeStrings = 0; /*!< 0==ASCII, 1==windows-1252, 2==uft-8 */
259 int CodePage = 0; /*!< Micosoft CodePage as specified in the Excel file. */
260
261
262
263
main(int argc,char ** argv)264 int main (int argc, char **argv)
265 {
266 int i, f_ptr = 0;
267 U16 k;
268 U32 j;
269 COLEFS * cfs;
270 COLERRNO colerrno;
271
272 if (argc < 2)
273 {
274 printf("Incorrect usage. Try xlhtml --help for more information\n");
275 exit(0);
276 }
277 else
278 {
279 strncpy(filename, argv[argc-1], 252);
280 filename[252] = 0;
281 for (i=1; i<(argc-1); i++)
282 {
283 if (strcmp(argv[i], "-nc") == 0)
284 use_colors = 0;
285 else if(strcmp(argv[i], "-xml") == 0 )
286 OutputXML = 1;
287 else if (strcmp(argv[i], "-asc") == 0)
288 Ascii = 1;
289 else if (strcmp(argv[i], "--ascii") == 0)
290 Ascii = 1;
291 else if (strcmp(argv[i], "-csv") == 0)
292 {
293 Ascii = 1;
294 Csv = 1;
295
296 }
297 else if (strcmp(argv[i], "-a") == 0)
298 aggressive = 1;
299 else if (strcmp(argv[i], "-fw") == 0)
300 formula_warnings = 0;
301 else if (strcmp(argv[i], "-c") == 0)
302 center_tables = 1;
303 else if (strcmp(argv[i], "-dp") == 0)
304 DumpPage = 1;
305 else if (strcmp(argv[i], "-m") == 0)
306 MultiByte = 1;
307 else if (strncmp(argv[i], "-tc", 3) == 0)
308 {
309 default_text_color = &argv[i][3];
310 if (strlen(default_text_color) != 6)
311 display_usage();
312 }
313 else if (strncmp(argv[i], "-bc", 3) == 0)
314 {
315 default_background_color = &argv[i][3];
316 if (strlen(default_background_color) != 6)
317 display_usage();
318 }
319 else if (strncmp(argv[i], "-bi", 3) == 0)
320 {
321 default_image = &argv[i][3];
322 use_colors = 0;
323 }
324 else if (strncmp(argv[i], "-te", 3) == 0)
325 trim_edges = 1;
326 else if (strcmp(argv[i], "-v") == 0)
327 print_version();
328 else if(strcmp(argv[i], "-nh") == 0 )
329 NoHeaders = 1;
330 else if (strncmp(argv[i], "-xc:", 4) == 0)
331 {
332 int d1, d2;
333 if (sscanf(argv[i] + 4, "%d-%d", &d1, &d2) != 2)
334 {
335 fprintf(stderr, "column range %s not valid, expected -xc:FIRST-LAST\n", argv[i] + 4);
336 display_usage();
337 }
338 xc1 = (S16)d1;
339 xc2 = (S16)d2;
340 Xtract = 1;
341 if (xc1 > xc2)
342 {
343 fprintf(stderr, "last column must be >= the first\n");
344 exit(1);
345 }
346 }
347 else if (strncmp(argv[i], "-xp:", 4) == 0)
348 {
349 Xtract = 1;
350 xp = (S16)atoi(&(argv[i][4]));
351 if (xp < 0)
352 {
353 fprintf(stderr, "Negative numbers are illegal.\n");
354 exit(1);
355 }
356 }
357 else if (strncmp(argv[i], "-xr:", 4) == 0)
358 {
359 char *ptr, *buf;
360 Xtract = 1;
361 buf = strdup(argv[i]);
362 ptr = strrchr(buf, '-');
363 xr2 = (S16)atoi(ptr+1);
364 *ptr = 0;
365 ptr = strchr(buf, ':');
366 xr1 = (S16)atoi(ptr+1);
367 free(buf);
368 if (xr1 > xr2)
369 {
370 fprintf(stderr, "row's 2nd digit must be >= the first\n");
371 exit(1);
372 }
373 }
374 else
375 display_usage();
376 }
377 if (strcmp(filename, "-v") == 0)
378 {
379 print_version();
380 }
381 if (strcmp(filename, "--version") == 0)
382 {
383 print_version();
384 }
385
386 if (strcmp(filename, "--help") == 0)
387 display_usage();
388 if (strcmp(filename, "-?") == 0)
389 display_usage();
390 }
391 if (Ascii)
392 { /* Disable it if DumpPage or Xtract isn't used... */
393 if (!(DumpPage||Xtract))
394 Ascii = 0;
395 }
396 if (Xtract)
397 trim_edges = 0; /* No trimming when extracting... */
398 if (OutputXML)
399 aggressive = 0;
400
401 /* Init arrays... */
402 ws_array = (work_sheet **)malloc(max_worksheets * sizeof(work_sheet *));
403 for (i=0; i<(int)max_worksheets; i++)
404 ws_array[i] = 0;
405
406 str_array = (uni_string **)malloc(max_strings*sizeof(uni_string *));
407 for (i=0; i<(int)max_strings; i++)
408 str_array[i] = 0;
409
410 font_array = (font_attr **)malloc(max_fonts * sizeof(font_attr *));
411 f_cnt = (fnt_cnt *)malloc(max_fonts * sizeof(fnt_cnt));
412 for (i=0; i<(int)max_fonts; i++)
413 { /* I assume these won't fail since we are just starting up... */
414 font_array[i] = 0;
415 f_cnt[i].name = 0;
416 }
417 xf_array = (xf_attr **)malloc(max_xformats * sizeof(xf_attr *));
418 for (i=0; i<(int)max_xformats; i++)
419 xf_array[i] = 0;
420
421 uni_string_clear(&author);
422 uni_string_clear(&default_font);
423 umask(GLOBAL_UMASK);
424
425 #if defined( __WIN32__ ) || defined( __BORLANDC__ )
426 {
427 char *ptr = strchr(filename, ':');
428 if (ptr)
429 {
430 int len;
431 char new_drive[MAXPATH];
432 fnsplit(filename, new_drive, 0, 0, 0);
433 if (new_drive[0] >= 'a')
434 setdisk(new_drive[0] - 'a');
435 else
436 setdisk(new_drive[0] - 'A');
437 ptr++; /* Get past the colon */
438 len = strlen(ptr);
439 memmove(filename, ptr, len);
440 filename[len] = 0;
441 }
442 }
443 #endif
444 /* If successful, this calls scan_file to extract the work book... */
445 cfs = cole_mount(filename, &colerrno);
446 if (cfs == NULL)
447 {
448 cole_perror (NULL, colerrno);
449 exit(1);
450 }
451 while (cole_locate_filename (cfs, SectionName[f_ptr], NULL, scan_file, &colerrno))
452 {
453 if (f_ptr)
454 { /* Two strikes...we're out! */
455 cole_perror (PRGNAME, colerrno);
456 if (colerrno == COLE_EFILENOTFOUND)
457 fprintf(stderr, "Section: Workbook\n");
458 break;
459 }
460 else
461 f_ptr++;
462 }
463
464 if (cole_umount (cfs, &colerrno))
465 {
466 cole_perror (PRGNAME, colerrno);
467 exit(1);
468 }
469
470 for (i=0; i<max_strings; i++)
471 {
472 if (str_array[i])
473 {
474 if (str_array[i]->str)
475 free(str_array[i]->str);
476 free(str_array[i]);
477 }
478 }
479
480 for (i=0; i<(int)max_fonts; i++)
481 {
482 if (font_array[i])
483 {
484 if (font_array[i]->name.str)
485 free(font_array[i]->name.str);
486 free(font_array[i]);
487 if (f_cnt[i].name)
488 {
489 if (f_cnt[i].name->str)
490 free(f_cnt[i].name->str);
491 free(f_cnt[i].name);
492 }
493 }
494 }
495
496
497 for (i=0; i<(int)max_worksheets; i++)
498 {
499 if (ws_array[i])
500 {
501 if (ws_array[i]->ws_title.str)
502 free(ws_array[i]->ws_title.str);
503 if (ws_array[i]->c_array)
504 {
505 for (j=0; j<ws_array[i]->max_rows; j++)
506 {
507 for (k=0; k<ws_array[i]->max_cols; k++)
508 {
509 if (ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k])
510 {
511 if (ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]->ustr.str)
512 free(ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]->ustr.str);
513 if (ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]->ustr.fmt_run)
514 free(ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]->ustr.fmt_run);
515 if (ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]->h_link.str)
516 free(ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]->h_link.str);
517 free(ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k]);
518 }
519 }
520 }
521 free(ws_array[i]->c_array);
522 }
523 free(ws_array[i]);
524 }
525 }
526
527
528 for (i=0; i<(int)max_xformats; i++)
529 {
530 if (xf_array[i])
531 free(xf_array[i]);
532 }
533
534 if (numCustomColors)
535 {
536 for (i=0; i<numCustomColors; i++)
537 free(customColors[i]);
538 free(customColors);
539 }
540
541 if (default_font.str)
542 free(default_font.str);
543 if (author.str)
544 free(author.str);
545 if (title)
546 free(title);
547 if (lastUpdated)
548 free(lastUpdated);
549
550 return 0;
551 }
552
553
554
555
556
557
558
559
scan_file(COLEDIRENT * cde,void * _info)560 void scan_file(COLEDIRENT *cde, void *_info)
561 {
562 U32 count = 0;
563 U16 length=0, target=0, opcode=0, version=0;
564 U8 buf[16];
565 COLEFILE *cf;
566 COLERRNO err;
567
568 cf = cole_fopen_direntry(cde, &err);
569 if (cf == 0)
570 { /* error abort processing */
571 cole_perror (PRGNAME, err);
572 return;
573 }
574
575 /* Read & process the file... */
576 while (cole_fread(cf, buf, 1, &err))
577 {
578 if (count > 3)
579 main_line_processor(opcode, version, count-4, target, buf[0]);
580 else if (count == 0)
581 { /* Init everything */
582 length = 0;
583 opcode = (U16)buf[0];
584 target = 80; /* ficticious number */
585 }
586 else if (count == 1)
587 version = (U16)buf[0];
588 else if (count == 2)
589 length = (U16)buf[0];
590 else if (count == 3)
591 {
592 length |= (U16)(buf[0]<<8);
593 target = length;
594 }
595
596 if (count == (U32)(target+3))
597 count = 0;
598 else
599 count++;
600 if (MaxColExceeded || MaxRowExceeded || MaxWorksheetsExceeded)
601 break; /* We're outta memory and therefore...done */
602
603 }
604 cole_fclose(cf, &err);
605
606 if (Ascii)
607 {
608 if (DumpPage)
609 { /* Output the XLS Parameters */
610 int i;
611 printf("There are %d pages total.\n", sheet_count+1);
612 for (i=0; i<=sheet_count; i++)
613 {
614 printf("Page:%d Name:%s MaxRow:%ld MaxCol:%d\n", i,
615 ws_array[i]->ws_title.str ? (char *)ws_array[i]->ws_title.str : "(Unknown Page)",
616 ws_array[i]->biggest_row, ws_array[i]->biggest_col);
617 }
618 }
619 else if (Xtract) {
620 if (xr2 == HARD_MAX_ROWS)
621 xr2 = ws_array[xp]->biggest_row;
622 if (xc2 == HARD_MAX_COLS)
623 xc2 = ws_array[xp]->biggest_col;
624 OutputPartialTableAscii();
625 }
626 }
627 else
628 {
629 if (DumpPage)
630 { /* Output the XLS Parameters */
631 int i;
632 output_header();
633 printf("<p>There are %d pages total.</p>\n", sheet_count+1);
634 for (i=0; i<=sheet_count; i++)
635 {
636 printf("<p>Page:%d Name:%s MaxRow:%ld MaxCol:%d</p>\n", i,
637 ws_array[i]->ws_title.str ? (char *)ws_array[i]->ws_title.str : "(Unknown Page)",
638 ws_array[i]->biggest_row, ws_array[i]->biggest_col);
639 }
640
641 output_footer();
642 }
643 else
644 {
645 if( OutputXML )
646 OutputTableXML();
647 else
648 OutputTableHTML();
649 }
650 }
651 }
652
653
654
655
656
657
658
SetupExtraction(void)659 void SetupExtraction(void)
660 {
661 if (Xtract)
662 { /* Revise the page settings... */
663 /* printf("-%d %d %d %d %d<br>\n", xp, xr1, xr2, xc1, xc2); */
664 if ((xp >= first_sheet)&&(xp <= last_sheet)&&(xp <= sheet_count))
665 {
666 first_sheet = xp;
667 last_sheet = xp;
668 if (xr1 < 0)
669 {
670 xr1 = (S16)ws_array[xp]->first_row;
671 xr2 = (S16)ws_array[xp]->biggest_row;
672 }
673 else if ((xr1 >= ws_array[xp]->first_row)&&(xr1 <= ws_array[xp]->biggest_row)
674 &&(xr2 >= ws_array[xp]->first_row)&&(xr2 <= ws_array[xp]->biggest_row))
675 {
676 ws_array[xp]->first_row = xr1;
677 ws_array[xp]->biggest_row = xr2;
678
679 if (xc1 < 0)
680 {
681 xc1 = ws_array[xp]->first_col;
682 xc2 = ws_array[xp]->biggest_col;
683 }
684 else if((xc1 >= ws_array[xp]->first_col)&&(xc1 <= ws_array[xp]->biggest_col)
685 &&(xc2 >= ws_array[xp]->first_col)&&(xc2 <= ws_array[xp]->biggest_col))
686 {
687 ws_array[xp]->first_col = xc1;
688 ws_array[xp]->biggest_col = xc2;
689 }
690 else
691 {
692 if (Ascii)
693 fprintf(stderr, "Error - Col not in range during extraction"
694 " (%d or %d not in [%d..%d])\n", xc1, xc2, ws_array[xp]->first_col, ws_array[xp]->biggest_col);
695 else
696 {
697 printf("Error - Col not in range during extraction.\n");
698
699 output_footer();
700 }
701 return;
702 }
703 }
704 else
705 {
706 if (Ascii)
707 fprintf(stderr, "Error - Row not in range during extraction"
708 " (%d or %d not in [%ld..%ld])\n", xr1, xr2, ws_array[xp]->first_row, ws_array[xp]->biggest_row);
709 else
710 {
711 printf("Error - Row not in range during extraction.");
712 output_footer();
713 }
714 return;
715 }
716 }
717 else
718 {
719 if (Ascii)
720 fprintf(stderr, "Error - Page not in range during extraction.");
721 else
722 {
723 printf("Error - Page not in range during extraction.");
724 output_footer();
725 }
726 return;
727 }
728 }
729 }
730
731
732 /*!******************************************************************
733 * \param count the absolute count in the record
734 * \param last the size of the record
735 * \param bufidx the index into the working buffer
736 * \param buflast the expected length of the working buffer
737 ********************************************************************/
main_line_processor(U16 opcode,U16 version,U32 count,U16 last,U8 data)738 void main_line_processor(U16 opcode, U16 version, U32 count, U16 last, U8 data)
739 {
740 U16 cont_opcode = 0;
741
742 /* If first pass, reset stuff. */
743 if (count == 0)
744 {
745 if (opcode != 0x3C) /* continue command */
746 /* {
747 printf("\n* * * * * * CONTINUE * * * * * * * * *\n\n");
748 }
749 else */
750 { /* Normal path... */
751 last_opcode = opcode;
752 bufidx = 0;
753 buflast = 0;
754 cont_str_array = 0;
755 memset(working_buffer, 0, WBUFF_SIZE);
756 }
757 }
758 if (opcode == 0x3C)
759 {
760 opcode = last_opcode;
761 cont_opcode = 1;
762 }
763
764 /* Abort processing if too big. Next opcode will reset everything. */
765 if (bufidx >= WBUFF_SIZE)
766 {
767 /*printf("OC:%02X C:%04X I:%04X BL:%04X cch:%04X gr:%04X\n", opcode, count, bufidx, buflast, cch, grbit); */
768 /*abort(); */
769 return;
770 }
771
772 /* no chart processing for now. */
773 if (version == 0x0010)
774 return;
775
776 switch (opcode)
777 {
778 case 0x09: /* BOF */
779 working_buffer[bufidx++] = data;
780 if (bufidx == last)
781 {
782 if (file_version == 0)
783 { /* File version info can be gathered here...
784 * 4 = Excel version 4
785 * 1280 = Excel version 5
786 * 0500 = Excel 95
787 * 1536 = Excel 97 */
788 if (version == 8)
789 file_version = getShort(&working_buffer[0]);
790 else
791 file_version = version;
792 if (file_version == EXCEL95)
793 {
794 use_colors = 0;
795 HARD_MAX_ROWS = HARD_MAX_ROWS_95;
796 }
797 /* printf("Biff:%X\n", file_version); */
798 }
799 sheet_count++;
800 if (sheet_count >= (int)max_worksheets)
801 add_more_worksheet_ptrs();
802 }
803 break;
804 case 0x01: /* Blank */
805 working_buffer[bufidx++] = data;
806 if (bufidx == last)
807 {
808 U16 r, c, f;
809
810 r = getShort(&working_buffer[0]);
811 c = getShort(&working_buffer[2]);
812 if (version == 2)
813 f = getShort(&working_buffer[4]);
814 else
815 f = 0;
816 add_wb_array(r, c, f, opcode, (U16)0, (U8 *)0, 0, (U16)0, 0);
817 }
818 break;
819 case 0x02: /* Integer */
820 working_buffer[bufidx++] = data;
821 if (bufidx == last)
822 {
823 U16 r, c, i, f;
824 char temp[32];
825
826 r = getShort(&working_buffer[0]);
827 c = getShort(&working_buffer[2]);
828 if (version == 2)
829 {
830 f = getShort(&working_buffer[4]);
831 i = getShort(&working_buffer[7]);
832 sprintf(temp, "%d", i);
833 }
834 else
835 {
836 f = 0;
837 Unsupported++;
838 strcpy(temp, OutputXML ? "<Unsupported/>INT" : "****INT");
839 }
840 add_wb_array(r, c, f, opcode, (U16)0, (U8 *)temp, (U16)strlen(temp), 0, NULL);
841 }
842 break;
843 case 0x03: /* Number - Float */
844 working_buffer[bufidx++] = data;
845 if (bufidx == last)
846 {
847 U16 r, c, f;
848 F64 d;
849 char temp[64];
850
851 r = getShort(&working_buffer[0]);
852 c = getShort(&working_buffer[2]);
853 if (version == 2)
854 {
855 f = getShort(&working_buffer[4]);
856 getDouble(&working_buffer[6], &d);
857 sprintf(temp, "%.15g", d);
858 }
859 else
860 { /* Who knows what the future looks like */
861 f = 0;
862 Unsupported = 1;
863 sprintf(temp, "****FPv:%d", version);
864 }
865 add_wb_array(r, c, f, opcode, (U16)0, (U8 *)temp, (U16)strlen(temp), 0, 0);
866 }
867 break;
868 case 0xD6: /* RString */
869 working_buffer[bufidx++] = data;
870 if ((bufidx == 8)&&(buflast == 0))
871 buflast = 8 + getShort(&working_buffer[6]);
872 if (buflast)
873 {
874 if (bufidx == buflast)
875 {
876 U16 r, c, l, f;
877
878 r = getShort(&working_buffer[0]);
879 c = getShort(&working_buffer[2]);
880 f = getShort(&working_buffer[4]);
881 l = getShort(&working_buffer[6]);
882 working_buffer[8+l] = 0;
883
884 add_wb_array(r, c, f, opcode, (U16)0, &working_buffer[8],
885 (U16)strlen((char *)&working_buffer[8]), 0, 0);
886 }
887 }
888 break;
889 case 0x04: /* Label - UNI */
890 working_buffer[bufidx++] = data;
891 if (file_version == EXCEL95)
892 {
893 if (bufidx == last)
894 {
895 U16 r, c, f;
896
897 r = getShort(&working_buffer[0]);
898 c = getShort(&working_buffer[2]);
899 f = getShort(&working_buffer[4]);
900 working_buffer[bufidx] = 0;
901
902 add_wb_array(r, c, f, opcode, (U16)0, &working_buffer[8],
903 (U16)strlen((char *)&working_buffer[8]), 0, 0);
904 }
905 }
906 else if (file_version == EXCEL97)
907 { /* Remember, bufidx is 1 more than it should be */
908 if ((bufidx == 8)&&(buflast == 0))
909 { /* buflast = working_buffer[7]; */
910 cch = getShort(&working_buffer[6]);
911 buflast = cch + 9;
912 }
913 if (bufidx == 9)
914 {
915 if (working_buffer[8] == 1)
916 buflast = (cch << 1) + 9;
917 }
918 if (buflast)
919 {
920 if (bufidx == buflast)
921 {
922 U16 r, c, f;
923 U16 len;
924
925 r = getShort(&working_buffer[0]);
926 c = getShort(&working_buffer[2]);
927 if (version == 2)
928 f = getShort(&working_buffer[4]);
929 else /* Unknown version */
930 f = 0;
931 working_buffer[bufidx] = 0;
932
933 len = (U16)strlen((char *)&working_buffer[8]);
934 if (working_buffer[8] == 1)
935 {
936 UnicodeStrings = 2;
937 add_wb_array(r, c, f, opcode, (U16)2, &working_buffer[9], (U16)(cch << 1), 0, 0);
938 }
939 else
940 add_wb_array(r, c, f, opcode, (U16)0, &working_buffer[8], len, 0, 0);
941 }
942 }
943 }
944 break;
945 case 0x05: /* Boolerr */
946 working_buffer[bufidx++] = data;
947 if (bufidx == last)
948 {
949 U16 r, c, f;
950 char temp[16];
951
952 r = getShort(&working_buffer[0]);
953 c = getShort(&working_buffer[2]);
954 if (version == 2)
955 {
956 f = getShort(&working_buffer[4]);
957 decodeBoolErr(working_buffer[6], working_buffer[7], temp);
958 add_wb_array(r, c, f, opcode, (U16)0, (U8 *)temp, (U16)strlen(temp), 0, 0);
959 }
960 else
961 {
962 f = 0;
963 Unsupported = 1;
964 strcpy(temp, "****Bool");
965 add_wb_array(r, c, f, opcode, (U16)0, (U8 *)temp, (U16)strlen(temp), 0, 0);
966 }
967 }
968 break;
969 /************
970 * This function has 2 entry points. 1 is the mainline FC opcode.
971 * In this event there are several bytes that setup the type of
972 * strings that will follow. Then there is the continue entry
973 * point which is immediate - e.g location 0.
974 *************/
975 case 0xFC: /* Packed String Array A.K.A. SST Shared String Table...UNI */
976 if ((count > 7)||(cont_opcode == 1)) /* Skip the 1st 8 locations they are bs */
977 {
978 /* if ((count == 0)&&(data == 0)&&(buflast)) */
979 if ((count == 0)&&(cont_opcode == 1)&&(buflast))
980 {
981 /* printf("Adjusting...\n"); */
982 /* printf("I:%04X BL:%04X\n", bufidx, buflast); */
983 cont_str_array = 1;
984 cont_grbit = data;
985 return;
986 }
987
988 working_buffer[bufidx] = data;
989 bufidx++;
990
991 if((cont_str_array)&&(grbit & 0x01)&& !(cont_grbit & 0x01))
992 { /* ASCII -> unicode */
993 working_buffer[bufidx] = 0;
994 bufidx++;
995 }
996
997 if (buflast == 0) /* Header processor */
998 {
999 if (bufidx == 0x03) /* After 3 locations we have length */
1000 { /* and type of chars... */
1001 cch = getShort(&working_buffer[0]);
1002 grbit = working_buffer[2];
1003
1004 if (grbit < 0x04) /* Normal run */
1005 {
1006 nonascii = 0;
1007 bufidx = 0;
1008 crun = 0;
1009 extrst = 0;
1010 buflast = cch << (grbit & 0x01);
1011
1012 /* special case for empty strings */
1013 if (!cch && !buflast)
1014 add_str_array(0, (U8 *)0, 0, 0, 0);
1015 else
1016 memset(working_buffer, 0, WBUFF_SIZE);
1017 }
1018 }
1019 else if (bufidx == 0x05)
1020 {
1021 if ((grbit & 0x0C) == 0x08) /* Rich string only */
1022 {
1023 nonascii = 0;
1024 bufidx = 0;
1025 crun = getShort(&working_buffer[3]);
1026 extrst = 0;
1027 buflast = (cch << (grbit & 0x01)) + (crun*4);
1028 /* printf("rtbuflast:%X cch%X grbit:%X extrst:%X crun:%X last:%X\n",
1029 buflast, cch, grbit, extrst, crun, last);
1030 printf("%02X %02X %02X %02X %02X %02X\n",
1031 working_buffer[0], working_buffer[1], working_buffer[2],
1032 working_buffer[3], working_buffer[4], working_buffer[5]); */
1033 memset(working_buffer, 0, WBUFF_SIZE);
1034 }
1035 }
1036 else if (bufidx == 0x07)
1037 {
1038 if ((grbit & 0x0C) == 0x04) /* Extended string only */
1039 {
1040 nonascii = 0;
1041 bufidx = 0;
1042 crun = 0;
1043 extrst = getLong(&working_buffer[3]);
1044 buflast = (cch << (grbit & 0x01)) + extrst;
1045 /* printf("esbuflast:%X cch%X grbit:%X extrst:%X last:%X\n",
1046 buflast, cch, grbit, extrst, last);
1047 printf("%02X %02X %02X %02X %02X %02X\n",
1048 working_buffer[0], working_buffer[1], working_buffer[2],
1049 working_buffer[3], working_buffer[4], working_buffer[5]); */
1050 memset(working_buffer, 0, WBUFF_SIZE);
1051 }
1052 }
1053 else if (bufidx == 0x09)
1054 {
1055 if ((grbit & 0x0C) == 0x0C)
1056 {
1057 /* Rich String + Extended String **/
1058 nonascii = 0;
1059 bufidx = 0;
1060 crun = getShort(&working_buffer[3]);
1061 extrst = getLong(&working_buffer[5]);
1062 buflast = (cch << (grbit & 0x01)) + extrst + (crun*4);
1063 /* printf("xrtbuflast:%X cch%X grbit:%X extrst:%X crun:%X last:%X\n",
1064 buflast, cch, grbit, extrst, crun, last);
1065 printf("%02X %02X %02X %02X %02X %02X\n",
1066 working_buffer[0], working_buffer[1], working_buffer[2],
1067 working_buffer[3], working_buffer[4], working_buffer[5]); */
1068 memset(working_buffer, 0, WBUFF_SIZE);
1069 }
1070 }
1071 /* printf("*%02X ", data); */
1072 }
1073 else /* payload processor */
1074 {
1075 /* if (cont_opcode == 1)
1076 printf(" %02X", data); */
1077 if (data > 127)
1078 nonascii = 1;
1079 if (bufidx == buflast)
1080 {
1081 U8 uni;
1082 U16 len = (U16)(cch << (grbit & 0x01));
1083 /* int i; */
1084
1085 if (grbit & 01)
1086 {
1087 uni = 2;
1088 UnicodeStrings = 2;
1089 }
1090 else
1091 uni = nonascii;
1092 working_buffer[bufidx] = 0;
1093 /* fprintf(stderr,":buflast-"); */
1094 /* { int i; */
1095 /* for (i=0; i<buflast; i++) */
1096 /* putchar(working_buffer[i]); */
1097 /* fprintf(stderr,"\nNext String:%d\n", next_string); */
1098 /* } */
1099
1100 if (crun)
1101 add_str_array(uni, working_buffer, len, working_buffer+len, crun);
1102 else
1103 add_str_array(uni, working_buffer, len, 0, 0);
1104 if (uni > UnicodeStrings) /* Try to "upgrade" charset */
1105 UnicodeStrings = uni;
1106 bufidx = 0;
1107 buflast = 0;
1108 cch = 0;
1109 cont_str_array = 0;
1110 memset(working_buffer, 0, WBUFF_SIZE);
1111 }
1112 }
1113 }
1114 break;
1115 case 0xFD: /* String Array Index A.K.A. LABELSST */
1116 working_buffer[count] = data;
1117 if (count == (last - 1))
1118 {
1119 U32 i;
1120 U16 r, c, f;
1121
1122 /* This is byte reversed... */
1123 r = getShort(&working_buffer[0]);
1124 c = getShort(&working_buffer[2]);
1125 f = getShort(&working_buffer[4]);
1126 i = getLong(&working_buffer[6]);
1127 if (i < next_string)
1128 {
1129 /* printf("String used:%d\n", (int)i); */
1130 if (str_array[i])
1131 {
1132 if (str_array[i]->str)
1133 add_wb_array(
1134 r, c, f, opcode,
1135 str_array[i]->uni, str_array[i]->str,
1136 str_array[i]->len, str_array[i]->crun_cnt, str_array[i]->fmt_run);
1137 }
1138 else /* Error, so just set it empty */
1139 add_wb_array( r, c, f, opcode,
1140 (U16)0, (U8 *)"String Table Error", 18, 0, 0);
1141 }
1142 else
1143 MaxStringsExceeded = 1;
1144 }
1145 break;
1146 case 0x31: /* Font */
1147 working_buffer[bufidx++] = data;
1148 if (bufidx > 14) /* Address 14 has length in unicode chars */
1149 {
1150 if ((file_version == EXCEL95)&&(bufidx == last))
1151 { /* Microsoft doesn't stick to their documentation. Excel 97 is supposed
1152 to be 0x0231...but its not. Have to use file_version to separate them. */
1153 unsigned int i;
1154 U16 size, attr, c_idx, b, su;
1155 U8 u;
1156
1157 size = getShort(&working_buffer[0]);
1158 attr = getShort(&working_buffer[2]);
1159 c_idx = getShort(&working_buffer[4]);
1160 b = getShort(&working_buffer[6]);
1161 su = getShort(&working_buffer[8]);
1162 u = working_buffer[10];
1163 buflast = working_buffer[14];
1164 for (i=0; i<buflast; i++)
1165 working_buffer[i] = working_buffer[i+15];
1166
1167 working_buffer[buflast] = 0;
1168 /* printf("S:%04X A:%04X C:%04X B:%04X SU:%04X U:%02X\n",
1169 size, attr,c_idx,b,su,u);
1170 printf("f:%s\n", working_buffer); */
1171 add_font(size, attr, c_idx, b, su, u, 0, &working_buffer[0], 0);
1172 }
1173 else if ((file_version == EXCEL97)&&(bufidx == last))
1174 { /* Microsoft doesn't stick to their documentation. Excel 97 is supposed
1175 to be 0x0231...but its not. Have to use file_version to separate them. */
1176 unsigned int i;
1177 U16 len;
1178 U16 size, attr, c_idx, b, su;
1179 U8 u, uni=0;
1180
1181 size = getShort(&working_buffer[0]);
1182 attr = getShort(&working_buffer[2]);
1183 c_idx = getShort(&working_buffer[4]);
1184 b = getShort(&working_buffer[6]);
1185 su = getShort(&working_buffer[8]);
1186 u = working_buffer[10];
1187 buflast = working_buffer[14];
1188
1189 for (i=0; i<(buflast-2); i++)
1190 { /* This looks at the 2nd byte to see if its unicode... */
1191 if (working_buffer[(i<<1)+17] != 0)
1192 uni = 2;
1193 }
1194
1195 if (uni == 2)
1196 len = (U16)(buflast<<1);
1197 else
1198 len = (U16)buflast;
1199
1200 if (uni == 0)
1201 {
1202 for (i=0; i<len; i++)
1203 {
1204 working_buffer[i] = working_buffer[(i<<1)+16];
1205 if ((working_buffer[i] > 0x0080U) && (uni == 0))
1206 uni = 1;
1207 }
1208 }
1209 else
1210 {
1211 for (i=0; i<len; i++)
1212 working_buffer[i] = working_buffer[i+16];
1213 }
1214
1215 working_buffer[len] = 0;
1216
1217 /* printf("S:%04X A:%04X C:%04X B:%04X SU:%04X U:%02X\n",
1218 size, attr,c_idx,b,su,u);
1219 printf("BL:%d L:%d Uni:%d\n", buflast, len, uni);
1220 printf("%X %X %X %X\n", working_buffer[15], working_buffer[16], working_buffer[17], working_buffer[18]);
1221 printf("f:%s\n", working_buffer); */
1222 add_font(size, attr, c_idx, b, su, u, uni, &working_buffer[0], len);
1223 }
1224 }
1225 break;
1226 case 0x14: /* Header */
1227 break;
1228 case 0x15: /* Footer */
1229 break;
1230 case 0x06: /* Formula */
1231 working_buffer[bufidx++] = data;
1232 if (bufidx == last)
1233 {
1234 U16 r, c, f;
1235 U8 calc_val[64];
1236
1237 r = getShort(&working_buffer[0]);
1238 c = getShort(&working_buffer[2]);
1239 f = getShort(&working_buffer[4]);
1240 if ((working_buffer[12] == 0xFF)&&(working_buffer[13] == 0xFF))
1241 { /* Formula evaluates to Bool, Err, or String */
1242 if (working_buffer[6] == 1) /* Boolean */
1243 {
1244 decodeBoolErr(working_buffer[8], 0, (char *)calc_val);
1245 opcode = 0x0105;
1246 }
1247 else if (working_buffer[6] == 2) /* Err */
1248 {
1249 decodeBoolErr(working_buffer[8], 1, (char *)calc_val);
1250 opcode = 0x0105;
1251 }
1252 else
1253 { /* String UNI */
1254 str_formula_row = r;
1255 str_formula_col = c;
1256 str_formula_format = f;
1257 break;
1258 }
1259 }
1260 else
1261 { /* Otherwise...this is a number */
1262 F64 n;
1263 getDouble(&working_buffer[6], &n);
1264 sprintf((char *)calc_val, "%.15g", n);
1265 opcode = 0x0103; /* To fix up OutputCellFormatted... */
1266 }
1267 add_wb_array(r, c, f, opcode, (U16)0, calc_val, (U16)strlen((char *)calc_val), 0, 0);
1268 }
1269 break;
1270 case 0x07: /* String Formula Results */
1271 working_buffer[bufidx++] = data;
1272 if (bufidx == last)
1273 {
1274 U8 *str;
1275 U8 uni = 0;
1276 U16 len = getShort(&working_buffer[0]);
1277 if (len > (last-3))
1278 len = (U16)(last-3);
1279 if (file_version == EXCEL97)
1280 {
1281 /* Check for unicode. Terminate the buffer at 2x len
1282 since unicode is 2bytes per char. Then see if
1283 strlen is short...upperbyte is usually 0 in
1284 western chararcter sets. */
1285 int t = len << 1;
1286 if ((t+3) < WBUFF_SIZE)
1287 working_buffer[t+3] = 0;
1288 else
1289 working_buffer[len+3] = 0;
1290 if ((len+3) < last)
1291 {
1292 uni = 2;
1293 len = (U16)t;
1294 }
1295 str = &working_buffer[3];
1296 }
1297 else if (file_version == EXCEL95)
1298 {
1299 str = &working_buffer[2];
1300 working_buffer[len+2] = 0;
1301 }
1302 else
1303 {
1304 if (OutputXML)
1305 str = (U8*)"<NotImplemented/>String Formula";
1306 else
1307 str = (U8*)"***String Formula";
1308 len = (U16)strlen((char*)str);
1309 NotImplemented++;
1310 }
1311 add_wb_array(str_formula_row, str_formula_col, str_formula_format, opcode, uni, str, len, 0, 0);
1312 }
1313 break;
1314 case 0x5C: /* Author's name A.K.A. WRITEACCESS */
1315 working_buffer[bufidx++] = data;
1316 if ((bufidx == last)&&(author.str == 0))
1317 {
1318 if (file_version == EXCEL97)
1319 {
1320 author.len = getShort(&working_buffer[0]);
1321 if ((int)working_buffer[2] & 0x01)
1322 {
1323 author.len *= (U16)2;
1324 author.uni = 2;
1325 }
1326 else
1327 author.uni = 0;
1328 if (author.len > (last-2))
1329 author.len = (U16)(last-2);
1330 author.str = (U8 *)malloc(author.len+1);
1331 if (author.str)
1332 {
1333 memcpy(author.str, &working_buffer[3], author.len);
1334 author.str[author.len] = 0;
1335 }
1336 }
1337 else if (file_version == EXCEL95)
1338 {
1339 author.len = working_buffer[0];
1340 author.str = (U8 *)malloc(author.len+1);
1341 if (author.str)
1342 {
1343 memcpy(author.str, &working_buffer[1], author.len);
1344 author.str[author.len] = 0;
1345 }
1346 author.uni = 0;
1347 }
1348 }
1349 break;
1350 case 0x08: /* Row Data */
1351 /* There's actually some other interesting things
1352 here that we're not collecting. For now, we'll
1353 Just get the dimensions of the sheet. */
1354 working_buffer[bufidx++] = data;
1355 if (bufidx == last)
1356 {
1357 /* question...what is the actual limit?
1358 This can go as high as 64K. Is this really OK? */
1359 U16 i, r, fc, lc, d, xf;
1360 r = getShort(&working_buffer[0]);
1361 fc = getShort(&working_buffer[2]);
1362 lc = (U16)(getShort(&working_buffer[4]) - (U16)1);
1363 d = getShort(&working_buffer[12]);
1364 xf = getShort(&working_buffer[14]);
1365
1366 if (ws_array[sheet_count] == 0)
1367 if (ws_init(sheet_count))
1368 return;
1369
1370 if (r > ws_array[sheet_count]->biggest_row)
1371 {
1372 if (r < ws_array[sheet_count]->max_rows)
1373 ws_array[sheet_count]->biggest_row = r;
1374 else
1375 { /* Resize the array... */
1376 if (MaxRowExceeded == 0)
1377 {
1378 int diff = (r/ROWS_INCR) + 1;
1379 if(resize_c_array(ws_array[sheet_count], ROWS_INCR*diff, 0))
1380 {
1381 ws_array[sheet_count]->biggest_row = ws_array[sheet_count]->max_rows - 1;
1382 MaxRowExceeded = 1;
1383 return;
1384 }
1385 else
1386 ws_array[sheet_count]->biggest_row = r;
1387 }
1388 else
1389 return;
1390 }
1391 }
1392
1393 if (lc > ws_array[sheet_count]->biggest_col)
1394 {
1395 if (lc < ws_array[sheet_count]->max_cols)
1396 ws_array[sheet_count]->biggest_col = lc;
1397 else
1398 { /* Resize array... */
1399 if (MaxColExceeded == 0)
1400 {
1401 int diff = (lc/COLS_INCR) + 1;
1402 if (resize_c_array(ws_array[sheet_count], 0, (U16)(COLS_INCR*diff)))
1403 {
1404 ws_array[sheet_count]->biggest_col = (S16)(ws_array[sheet_count]->max_cols - 1);
1405 MaxColExceeded = 1;
1406 lc = ws_array[sheet_count]->max_cols;
1407 }
1408 else
1409 ws_array[sheet_count]->biggest_col = lc;
1410 }
1411 else
1412 lc = ws_array[sheet_count]->max_cols;
1413 }
1414 }
1415 if ((fc < ws_array[sheet_count]->max_cols)&&(d & 0x0080)) /* fGhostDirty flag */
1416 {
1417 for (i=fc; i<lc; i++)
1418 { /* Set the default attr... */
1419 update_cell_xf(r, i, xf);
1420 }
1421 }
1422 }
1423 break;
1424 case 0x22: /* 1904 Flag - MacIntosh Dates or PC Dates */
1425 working_buffer[bufidx++] = data;
1426 if (bufidx == 2)
1427 DatesR1904 = getShort(&working_buffer[0]);
1428 break;
1429 case 0x085: /* BoundSheet */
1430 working_buffer[bufidx++] = data;
1431 if (bufidx == last)
1432 { /* This is based on Office 97 info... */
1433 if ((working_buffer[4] & 0x0F) == 0)
1434 { /* Worksheet as opposed to chart, etc */
1435 U16 len;
1436 U8 uni=0;
1437 if (file_version == EXCEL97)
1438 {
1439 len = (U16)working_buffer[6]; /* FIXME: Check this !!! Was GetShort */
1440 if (working_buffer[7] & 0x01)
1441 {
1442 uni = 2;
1443 len = (U16)(len<<1);
1444 }
1445 if (len != 0)
1446 {
1447 working_buffer[8 + len + 1] = 0;
1448 add_ws_title(uni, &working_buffer[8], len);
1449 }
1450 }
1451 else
1452 {
1453 len = working_buffer[6];
1454 if (len != 0)
1455 {
1456 working_buffer[7 + len + 1] = 0;
1457 add_ws_title(uni, &working_buffer[7], len);
1458 }
1459 }
1460 }
1461 }
1462 break;
1463 case 0x7E: /* RK Number */
1464 working_buffer[bufidx++] = data;
1465 if (bufidx == last)
1466 { /* This is based on Office 97 info... */
1467 U16 r, c, f;
1468 U32 t;
1469 S32 n, n2; /* Must be signed long !!! */
1470 F64 d;
1471 char temp[64];
1472
1473 r = getShort(&working_buffer[0]);
1474 c = getShort(&working_buffer[2]);
1475 f = getShort(&working_buffer[4]);
1476 n = getLong(&working_buffer[6]);
1477 t = n & 0x03;
1478 n2 = n>>2;
1479 switch (t)
1480 {
1481 case 0:
1482 RKtoDouble(n2, &d);
1483 sprintf(temp, "%.15g", d);
1484 break;
1485 case 1:
1486 RKtoDouble(n2, &d);
1487 sprintf(temp, "%.15g", d / 100.0);
1488 break;
1489 case 2:
1490 sprintf(temp, "%ld", (S32)n2);
1491 break;
1492 default:
1493 d = (F64) n2;
1494 sprintf(temp, "%.15g", d / 100.0 );
1495 break;
1496 }
1497 add_wb_array(r, c, f, opcode, (U16)0, (U8 *)temp, (U16)strlen(temp), 0, 0);
1498 }
1499 break;
1500 case 0xBC: /* Shared Formula's */
1501 /* working_buffer[bufidx++] = data;
1502 if (bufidx == last)
1503 {
1504 int fr, lr, fc, lc, i, j;
1505 fr = getShort(&working_buffer[0]);
1506 lr = getShort(&working_buffer[2]);
1507 fc = working_buffer[4];
1508 lc = working_buffer[5];
1509 for (i=fr; i<=lr; i++)
1510 {
1511 for (j=fc; j<=lc; j++)
1512 add_wb_array(i, j, (U16)0, opcode, 0, "***SHRFORMULA", 13);
1513 }
1514 NotImplemented = 1;
1515 } */
1516 break;
1517 case 0x21: /* Arrays */
1518 working_buffer[bufidx++] = data;
1519 if (bufidx == last)
1520 {
1521 U16 fr, lr, fc, lc, i, j;
1522 fr = getShort(&working_buffer[0]);
1523 lr = getShort(&working_buffer[2]);
1524 fc = working_buffer[4];
1525 lc = working_buffer[5];
1526 for (i=fr; i<=lr; i++)
1527 {
1528 for (j=fc; j<=lc; j++)
1529 add_wb_array(i, j, (U16)0, opcode, 0, (U8 *)"***Array", 8, 0, 0);
1530 }
1531 NotImplemented = 1;
1532 }
1533 break;
1534 case 0xBD: /* MULRK */
1535 working_buffer[bufidx++] = data;
1536 if (bufidx == last)
1537 {
1538 U16 r, fc, lc;
1539 int i;
1540 r = getShort(&working_buffer[0]);
1541 fc = getShort(&working_buffer[2]);
1542 lc = getShort(&working_buffer[last-2]);
1543 for (i=0; i<=(lc-fc); i++)
1544 {
1545 U32 t;
1546 S32 n2, n; /* Must be signed long !!! */
1547 U16 f;
1548 F64 d;
1549 char temp[64];
1550
1551 f = getShort(&working_buffer[4+(i*6)]);
1552 n = getLong(&working_buffer[6+(i*6)]);
1553 t = n & 0x03;
1554 n2 = n>>2;
1555 switch (t)
1556 {
1557 case 0:
1558 RKtoDouble(n2, &d);
1559 sprintf(temp, "%.15g", d);
1560 break;
1561 case 1:
1562 RKtoDouble(n2, &d);
1563 sprintf(temp, "%.15g", d / 100.0);
1564 break;
1565 case 2:
1566 sprintf(temp, " %ld", (S32)n2);
1567 break;
1568 default:
1569 d = (F64) n2;
1570 sprintf(temp, "%.15g", d / 100.0 );
1571 break;
1572 }
1573 /* printf("%08X %02X %s %d %d\n", n2, t, temp, r, fc+i); */
1574 add_wb_array(r, fc+i, f, opcode, (U16)0, (U8 *)temp, (U16)strlen(temp), 0, 0);
1575 }
1576 }
1577 break;
1578 case 0xBE: /* MULBLANK */
1579 working_buffer[bufidx++] = data;
1580 if (bufidx == last)
1581 {
1582 U16 r, fc, lc, j, f;
1583 r = getShort(&working_buffer[0]);
1584 fc = getShort(&working_buffer[2]);
1585 lc = getShort(&working_buffer[last-2]);
1586 for (j=0; j<=(lc-fc); j++)
1587 { /* This just stores format strings... */
1588 f = getShort(&working_buffer[4+(j*2)]);
1589 add_wb_array(r, fc+j, f, opcode, (U16)0, (U8 *)0, (U16)0, 0, 0);
1590 }
1591 }
1592 break;
1593 case 0x18: /* Name UNI */
1594 working_buffer[bufidx++] = data;
1595 if (bufidx == last)
1596 {
1597 char *ptr;
1598 working_buffer[bufidx] = 0;
1599 ptr = (char *)strstr((char *)&working_buffer[15], "LastUpdate");
1600 if (ptr)
1601 {
1602 ptr += 13;
1603 lastUpdated = (char *)malloc(strlen(ptr)+1);
1604 if (lastUpdated)
1605 strcpy(lastUpdated, ptr);
1606 }
1607 else
1608 {
1609 ptr = (char *)strstr((char *)&working_buffer[15], "Title");
1610 if (ptr)
1611 {
1612 ptr += 8;
1613 title = (char *)malloc(strlen(ptr)+1);
1614 if (title)
1615 strcpy(title, ptr);
1616 }
1617 }
1618 }
1619 break;
1620 case 0xE0: /* Extended format */
1621 working_buffer[bufidx++] = data;
1622 if (bufidx == last)
1623 {
1624 U16 fnt_idx;
1625 U16 fmt_idx;
1626 U16 gen;
1627 U16 align;
1628 U16 indent;
1629 U16 b_style;
1630 U16 b_l_color;
1631 U32 b_t_color;
1632 U16 cell_color;
1633
1634 fnt_idx = getShort(&working_buffer[0]);
1635 fmt_idx = getShort(&working_buffer[2]);
1636 gen = getShort(&working_buffer[4]);
1637 align = getShort(&working_buffer[6]);
1638 indent = getShort(&working_buffer[8]);
1639 b_style = getShort(&working_buffer[10]);
1640 if (file_version == EXCEL95)
1641 {
1642 b_l_color = 0;
1643 b_t_color = 0;
1644 cell_color = (U16)(getShort(&working_buffer[12]) & (U16)0x1FFF);
1645 }
1646 else /* Excel 97 + */
1647 {
1648 b_l_color = getShort(&working_buffer[12]);
1649 b_t_color = getLong(&working_buffer[14]);
1650 cell_color = getShort(&working_buffer[18]);
1651 }
1652
1653 /* printf("XF:%02X FG:%02X BG:%02X\n", next_xf, cell_color&0x007F, (cell_color&0x1F80)>>7); */
1654 /* printf("XF:%02X M:%02X b_t:%04X<br>\n", next_xf, indent, b_t_color); */
1655 add_xf_array(fnt_idx, fmt_idx, gen, align, indent, b_style,
1656 b_l_color, b_t_color, cell_color);
1657 }
1658 break;
1659 case 0xE5: /* CELL MERGE INSTRUCTIONS */
1660 working_buffer[bufidx++] = data;
1661 if (bufidx == last)
1662 {
1663 U16 num, fr, lr, fc, lc, i, j, k;
1664 ws_array[sheet_count]->spanned = 1;
1665 num = getShort(&working_buffer[0]);
1666 if (ws_array[sheet_count]->c_array == 0)
1667 return;
1668
1669 for (i=0; i<num; i++)
1670 {
1671 cell *c;
1672 fr = getShort(&working_buffer[2+(i*8)]);
1673 lr = getShort(&working_buffer[4+(i*8)]);
1674 fc = getShort(&working_buffer[6+(i*8)]);
1675 lc = getShort(&working_buffer[8+(i*8)]);
1676 if (sheet_count < (int)max_worksheets)
1677 {
1678 if (ws_array[sheet_count] == 0)
1679 {
1680 if (ws_init(sheet_count))
1681 return;
1682 }
1683 if (ws_array[sheet_count]->c_array)
1684 {
1685 if ((fr > lr)||(fr > ws_array[sheet_count]->biggest_row)||(lr > ws_array[sheet_count]->biggest_row))
1686 lr = (U16)ws_array[sheet_count]->biggest_row;
1687 if ((fc > lc)||(fc > ws_array[sheet_count]->biggest_col)||(lc > ws_array[sheet_count]->biggest_col))
1688 lc = ws_array[sheet_count]->biggest_col;
1689 for(j=fr; j<=lr; j++)
1690 { /* For each row */
1691 for(k=fc; k<=lc; k++)
1692 { /* for each column */
1693 c = ws_array[sheet_count]->c_array[(j*ws_array[sheet_count]->max_cols)+k];
1694 if (c != 0)
1695 {
1696 c->spanned = 1;
1697 c->rowspan = 0;
1698 if (k == fc)
1699 c->colspan = (U16)((lc-fc)+1);
1700 else
1701 c->colspan = 0;
1702 }
1703 /* else
1704 { / Need to create one...
1705 printf("Bad One at:%d %d %d<br>\n", sheet_count, j, k);
1706 } */
1707 }
1708 }
1709 }
1710 /* Now reset the first one... */
1711 /* printf("s:%d fr:%d fc:%d lr:%d lc:%d<br>\n", sheet_count, fr, fc, lr, lc); */
1712 c = ws_array[sheet_count]->c_array[(fr*ws_array[sheet_count]->max_cols)+fc];
1713 if (c != 0)
1714 {
1715 c->spanned = 0;
1716 c->rowspan = (U16)(lr-fr);
1717 c->colspan = (U16)(lc-fc);
1718 if (c->rowspan)
1719 c->rowspan++;
1720 if (c->colspan)
1721 c->colspan++;
1722 }
1723 }
1724 }
1725 }
1726 break;
1727 case 0xB8: /* Hyperlink */
1728 working_buffer[bufidx++] = data;
1729 if (bufidx == last)
1730 { /* This is based on Office 97 info... */
1731 U16 r, c, uni_type, off;
1732 U32 len;
1733
1734 r = getShort(&working_buffer[0]);
1735 c = getShort(&working_buffer[4]);
1736 if (working_buffer[32] == 0xE0)
1737 { /* Unicode format */
1738 len = getLong(&working_buffer[48]);
1739 off = 52;
1740 uni_type = 2;
1741 }
1742 else
1743 { /* Ascii format */
1744 len = getLong(&working_buffer[50]);
1745 off = 54;
1746 uni_type = 0;
1747 }
1748 if (len > (U32)(bufidx - off))
1749 { /* correct misidentified links */
1750 if (uni_type == 0)
1751 {
1752 off = 36;
1753 uni_type = 2;
1754 len = getLong(&working_buffer[32]) * 2;
1755 }
1756 else
1757 len = bufidx - off; /* safety measure to make sure it doen't blow up */
1758 }
1759 update_cell_hyperlink(r, c, &working_buffer[off], len, uni_type);
1760 }
1761 break;
1762 case 0x92: /* Color Palette */
1763 working_buffer[bufidx++] = data;
1764 if (bufidx == last)
1765 { /* This is based on Office 97 info... */
1766 int i;
1767 U8 red, green, blue;
1768 U16 cnt = getShort(&working_buffer[0]);
1769 numCustomColors = cnt;
1770 customColors = (U8 **)calloc(cnt+1, sizeof(char *));
1771 for (i=0; i<cnt; i++)
1772 {
1773 char color_string[8];
1774 red = (unsigned char)working_buffer[(4*i)+2];
1775 green = (unsigned char)working_buffer[(4*i)+3];
1776 blue = (unsigned char)working_buffer[(4*i)+4];
1777 /* printf("%02X%02X%02X\n", (int)red, (int)green, (int)blue); */
1778 sprintf(color_string, "%02X%02X%02X", (int)red, (int)green, (int)blue);
1779 customColors[i] = (U8 *)strdup(color_string);
1780 }
1781 }
1782 break;
1783 case 0x42: /* CodePage */
1784 working_buffer[bufidx++] = data;
1785 if (bufidx == last)
1786 {
1787 CodePage = getShort(&working_buffer[0]);
1788 if (CodePage == 1200)
1789 CodePage = 0; /* Unicode inside, old behavior is OK */
1790 }
1791 break;
1792 default:
1793 break;
1794 }
1795 }
1796
1797
1798
1799
1800
1801
1802 /*! returns 1 on error, 0 on success */
ws_init(int i)1803 int ws_init(int i)
1804 {
1805 U32 j;
1806 U16 k;
1807 if (i >= (int)max_worksheets)
1808 return 1;
1809
1810 ws_array[i] = (work_sheet *)malloc(sizeof(work_sheet));
1811 if (ws_array[i])
1812 {
1813 ws_array[i]->spanned = 0;
1814 ws_array[i]->first_row = 0;
1815 ws_array[i]->biggest_row = -1;
1816 ws_array[i]->max_rows = ROWS_INCR;
1817 ws_array[i]->first_col = 0;
1818 ws_array[i]->biggest_col = -1;
1819 ws_array[i]->max_cols = COLS_INCR;
1820 uni_string_clear(&ws_array[i]->ws_title);
1821 ws_array[i]->c_array = (cell **)malloc(ROWS_INCR*COLS_INCR*sizeof(cell *));
1822 if (ws_array[i]->c_array == 0)
1823 return 1;
1824 for (j=0; j<ROWS_INCR; j++)
1825 for (k=0; k<COLS_INCR; k++)
1826 ws_array[i]->c_array[(j*ws_array[i]->max_cols)+k] = 0;
1827 }
1828 else
1829 return 1;
1830
1831 return 0;
1832 }
1833
1834 /*! returns 1 on error, 0 on success */
add_more_worksheet_ptrs(void)1835 int add_more_worksheet_ptrs(void)
1836 {
1837 work_sheet **tws_array;
1838 int pages;
1839
1840 if (MaxWorksheetsExceeded)
1841 return 1;
1842
1843 if (sheet_count > (int)max_worksheets)
1844 pages = (((sheet_count - max_worksheets)/WORKSHEETS_INCR) + 1) * WORKSHEETS_INCR;
1845 else
1846 pages = WORKSHEETS_INCR;
1847 tws_array = (work_sheet **)realloc(ws_array,
1848 (max_worksheets + pages) * sizeof(work_sheet *));
1849
1850 if (tws_array == NULL)
1851 {
1852 MaxWorksheetsExceeded = 1;
1853 return 1;
1854 }
1855 else
1856 { /* Next init the array... */
1857 unsigned int i;
1858
1859 ws_array = tws_array;
1860
1861 for (i=max_worksheets; i<max_worksheets+pages; i++)
1862 ws_array[i] = 0;
1863
1864 max_worksheets += pages;
1865 last_sheet = max_worksheets - 1;
1866 }
1867 return 0;
1868 }
1869
resize_c_array(work_sheet * ws,U32 new_rows,U16 new_cols)1870 int resize_c_array(work_sheet *ws, U32 new_rows, U16 new_cols)
1871 {
1872 cell **tc_array;
1873 if (ws == 0)
1874 return 1;
1875 if (ws->c_array == 0)
1876 return 1;
1877
1878 tc_array = (cell **)malloc((ws->max_rows+new_rows)*(ws->max_cols+new_cols)*sizeof(cell *));
1879
1880 if (tc_array == NULL)
1881 return 1;
1882 else
1883 {
1884 U32 j;
1885 U16 k;
1886
1887 memset(tc_array, 0, (ws->max_rows+new_rows)*(ws->max_cols+new_cols)*sizeof(cell *));
1888 for (j=0; j<(ws->max_rows); j++)
1889 {
1890 for (k=0; k<ws->max_cols; k++)
1891 tc_array[(j*(ws->max_cols+new_cols))+k] = ws->c_array[(j*ws->max_cols)+k];
1892 }
1893 ws->max_cols += new_cols;
1894 ws->max_rows += new_rows;
1895 free(ws->c_array);
1896 ws->c_array = tc_array;
1897 }
1898 return 0;
1899 }
1900
add_wb_array(U16 r,U16 c,U16 xf,U16 type,U8 uni,U8 * str,U16 len,U16 crun_cnt,U8 * fmt_run)1901 void add_wb_array(U16 r, U16 c, U16 xf, U16 type, U8 uni,
1902 U8 *str, U16 len, U16 crun_cnt, U8 *fmt_run)
1903 {
1904 work_sheet *ws;
1905
1906 if ((sheet_count < 0)||(r > HARD_MAX_ROWS)||(c > HARD_MAX_COLS))
1907 return;
1908 if (sheet_count >= (int)max_worksheets)
1909 {
1910 if (add_more_worksheet_ptrs())
1911 return;
1912 }
1913 if (ws_array[sheet_count] == 0)
1914 {
1915 if (ws_init(sheet_count))
1916 return;
1917 }
1918 ws = ws_array[sheet_count];
1919 if (r >= ws->max_rows)
1920 {
1921 if (MaxRowExceeded)
1922 return;
1923 else
1924 {
1925 int diff = ((r-ws->max_rows)/ROWS_INCR)+1;
1926 if(resize_c_array(ws, ROWS_INCR*diff, 0))
1927 {
1928 MaxRowExceeded = 1;
1929 return;
1930 }
1931 }
1932 }
1933 if (c >= ws->max_cols)
1934 {
1935 if (MaxColExceeded)
1936 return;
1937 else
1938 {
1939 U16 diff = (U16)(((c-ws->max_cols)/COLS_INCR)+1);
1940 if(resize_c_array(ws, 0, (U16)(COLS_INCR*diff)))
1941 {
1942 MaxColExceeded = 1;
1943 return;
1944 }
1945 }
1946 }
1947 if (ws->c_array[(r*ws->max_cols)+c] == 0)
1948 {
1949 if (r > ws_array[sheet_count]->biggest_row)
1950 ws_array[sheet_count]->biggest_row = r;
1951 if (c > ws_array[sheet_count]->biggest_col)
1952 ws_array[sheet_count]->biggest_col = c;
1953 ws->c_array[(r*ws->max_cols)+c] = (cell *)malloc(sizeof(cell));
1954 if (ws->c_array[(r*ws->max_cols)+c])
1955 {
1956 if (str)
1957 {
1958 ws->c_array[(r*ws->max_cols)+c]->ustr.str = (U8 *)malloc(len+1);
1959 if (ws->c_array[(r*ws->max_cols)+c]->ustr.str)
1960 {
1961 memcpy(ws->c_array[(r*ws->max_cols)+c]->ustr.str, str, len);
1962 ws->c_array[(r*ws->max_cols)+c]->ustr.str[len] = 0;
1963 }
1964 ws->c_array[(r*ws->max_cols)+c]->ustr.uni = uni;
1965 ws->c_array[(r*ws->max_cols)+c]->ustr.len = len;
1966 if (fmt_run && crun_cnt)
1967 {
1968 int rlen = crun_cnt*4;
1969
1970 ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run = malloc(rlen);
1971 if (ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run)
1972 {
1973 memcpy(ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run, fmt_run, rlen);
1974 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = crun_cnt;
1975 }
1976 else
1977 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = 0;
1978 }
1979 else
1980 {
1981 ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run = 0;
1982 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = 0;
1983 }
1984 }
1985 else
1986 uni_string_clear(&ws->c_array[(r*ws->max_cols)+c]->ustr);
1987
1988 ws->c_array[(r*ws->max_cols)+c]->xfmt = xf;
1989 ws->c_array[(r*ws->max_cols)+c]->type = type;
1990 ws->c_array[(r*ws->max_cols)+c]->spanned = 0;
1991 ws->c_array[(r*ws->max_cols)+c]->rowspan = 0;
1992 ws->c_array[(r*ws->max_cols)+c]->colspan = 0;
1993 uni_string_clear(&ws->c_array[(r*ws->max_cols)+c]->h_link);
1994 }
1995 }
1996 else /* Default attributes already copied */
1997 {
1998 if (r > ws_array[sheet_count]->biggest_row)
1999 ws_array[sheet_count]->biggest_row = r;
2000 if (c > ws_array[sheet_count]->biggest_col)
2001 ws_array[sheet_count]->biggest_col = c;
2002 if (str)
2003 { /* Check if a place holder is there and free it */
2004 if (ws->c_array[(r*ws->max_cols)+c]->ustr.str != 0)
2005 free(ws->c_array[(r*ws->max_cols)+c]->ustr.str);
2006
2007 ws->c_array[(r*ws->max_cols)+c]->ustr.str = (U8 *)malloc(len+1);
2008 if (ws->c_array[(r*ws->max_cols)+c]->ustr.str)
2009 {
2010 memcpy(ws->c_array[(r*ws->max_cols)+c]->ustr.str, str, len);
2011 ws->c_array[(r*ws->max_cols)+c]->ustr.str[len] = 0;
2012 }
2013 ws->c_array[(r*ws->max_cols)+c]->ustr.len = len;
2014 ws->c_array[(r*ws->max_cols)+c]->ustr.uni = uni;
2015 if (fmt_run && crun_cnt)
2016 {
2017 int rlen = crun_cnt*4;
2018
2019 ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run = malloc(rlen);
2020 if (ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run)
2021 {
2022 memcpy(ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run, fmt_run, rlen);
2023 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = crun_cnt;
2024 }
2025 else
2026 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = 0;
2027 }
2028 else
2029 {
2030 ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run = 0;
2031 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = 0;
2032 }
2033 }
2034 else
2035 {
2036 if (ws->c_array[(r*ws->max_cols)+c]->ustr.str == 0)
2037 {
2038 ws->c_array[(r*ws->max_cols)+c]->ustr.len = 0;
2039 ws->c_array[(r*ws->max_cols)+c]->ustr.uni = 0;
2040 ws->c_array[(r*ws->max_cols)+c]->ustr.fmt_run = 0;
2041 ws->c_array[(r*ws->max_cols)+c]->ustr.crun_cnt = 0;
2042 }
2043 }
2044 ws->c_array[(r*ws->max_cols)+c]->xfmt = xf;
2045 ws->c_array[(r*ws->max_cols)+c]->type = type;
2046 ws->c_array[(r*ws->max_cols)+c]->spanned = 0;
2047 ws->c_array[(r*ws->max_cols)+c]->rowspan = 0;
2048 ws->c_array[(r*ws->max_cols)+c]->colspan = 0;
2049 }
2050 }
2051
update_cell_xf(U16 r,U16 c,U16 xf)2052 void update_cell_xf(U16 r, U16 c, U16 xf)
2053 {
2054 work_sheet *ws;
2055
2056 if ((sheet_count < 0)||(r > HARD_MAX_ROWS)||(c > HARD_MAX_COLS))
2057 return;
2058 if (sheet_count >= (int)max_worksheets)
2059 {
2060 if (add_more_worksheet_ptrs())
2061 return;
2062 }
2063 if (ws_array[sheet_count] == 0)
2064 {
2065 if (ws_init(sheet_count))
2066 return;
2067 }
2068 if (r >= ws_array[sheet_count]->max_rows)
2069 {
2070 if (MaxRowExceeded)
2071 return;
2072 else
2073 {
2074 int diff = ((r-ws_array[sheet_count]->max_rows)/ROWS_INCR)+1;
2075 if(resize_c_array(ws_array[sheet_count], ROWS_INCR*diff, 0))
2076 {
2077 MaxRowExceeded = 1;
2078 return;
2079 }
2080 }
2081 }
2082 if (c >= ws_array[sheet_count]->max_cols)
2083 {
2084 if (MaxColExceeded)
2085 return;
2086 else
2087 {
2088 int diff = ((c-ws_array[sheet_count]->max_cols)/COLS_INCR)+1;
2089 if (resize_c_array(ws_array[sheet_count], 0, (U16)(COLS_INCR*diff)))
2090 {
2091 MaxColExceeded = 1;
2092 return;
2093 }
2094 }
2095 }
2096
2097 ws = ws_array[sheet_count];
2098 if (ws->c_array[(r*ws->max_cols)+c] == 0)
2099 {
2100 ws->c_array[(r*ws->max_cols)+c] = (cell *)malloc(sizeof(cell));
2101 if (ws->c_array[(r*ws->max_cols)+c])
2102 {
2103 uni_string_clear(&ws->c_array[(r*ws->max_cols)+c]->ustr);
2104 ws->c_array[(r*ws->max_cols)+c]->xfmt = xf;
2105 ws->c_array[(r*ws->max_cols)+c]->type = 1; /* This is the Blank Cell type */
2106
2107 if (r > ws_array[sheet_count]->biggest_row)
2108 ws_array[sheet_count]->biggest_row = r;
2109 if (c > ws_array[sheet_count]->biggest_col)
2110 ws_array[sheet_count]->biggest_col = c;
2111 ws->c_array[(r*ws->max_cols)+c]->spanned = 0;
2112 ws->c_array[(r*ws->max_cols)+c]->rowspan = 0;
2113 ws->c_array[(r*ws->max_cols)+c]->colspan = 0;
2114 uni_string_clear(&ws->c_array[(r*ws->max_cols)+c]->h_link);
2115 }
2116 }
2117 /* else
2118 {
2119 printf("R:%02X C:%02X XF:%02X is:%02X\n",
2120 r, c, xf, ws->c_array[r][c]->xfmt);
2121 } */
2122 }
2123
update_cell_hyperlink(U16 r,U16 c,U8 * hyperlink,int len,U16 uni)2124 void update_cell_hyperlink(U16 r, U16 c, U8 *hyperlink, int len, U16 uni)
2125 {
2126 work_sheet *ws;
2127
2128 if (sheet_count < 0) /* Used to do a "0 <" check on r & c */
2129 return;
2130 if (sheet_count >= (int)max_worksheets)
2131 {
2132 if (add_more_worksheet_ptrs())
2133 return;
2134 }
2135 if (ws_array[sheet_count] == 0)
2136 {
2137 if (ws_init(sheet_count))
2138 return;
2139 }
2140 if (r >= ws_array[sheet_count]->max_rows)
2141 {
2142 if (MaxRowExceeded)
2143 return;
2144 else
2145 {
2146 int diff = ((r-ws_array[sheet_count]->max_rows)/ROWS_INCR)+1;
2147 if(resize_c_array(ws_array[sheet_count], ROWS_INCR*diff, 0))
2148 {
2149 MaxRowExceeded = 1;
2150 return;
2151 }
2152 }
2153 }
2154 if (c >= ws_array[sheet_count]->max_cols)
2155 {
2156 if (MaxColExceeded)
2157 return;
2158 else
2159 {
2160 int diff = ((c-ws_array[sheet_count]->max_cols)/COLS_INCR)+1;
2161 if(resize_c_array(ws_array[sheet_count], 0, (U16)(COLS_INCR*diff)))
2162 {
2163 MaxColExceeded = 1;
2164 return;
2165 }
2166 }
2167 }
2168
2169 ws = ws_array[sheet_count];
2170 if (ws->c_array[(r*ws->max_cols)+c] == 0)
2171 { /* should not get here, but just in case */
2172 return;
2173 }
2174 if (ws->c_array[(r*ws->max_cols)+c]->h_link.str == 0)
2175 {
2176 ws->c_array[(r*ws->max_cols)+c]->h_link.str = (U8 *)malloc(len);
2177 if (ws->c_array[(r*ws->max_cols)+c]->h_link.str)
2178 memcpy(ws->c_array[(r*ws->max_cols)+c]->h_link.str, hyperlink, len);
2179 ws->c_array[(r*ws->max_cols)+c]->h_link.uni = uni;
2180 if (len)
2181 {
2182 if (uni < 2)
2183 ws->c_array[(r*ws->max_cols)+c]->h_link.len = (U16)(len-1);
2184 else
2185 ws->c_array[(r*ws->max_cols)+c]->h_link.len = (U16)(len-2);
2186 }
2187 }
2188 /* else
2189 {
2190 printf("R:%02X C:%02X XF:%02X is:%s\n",
2191 r, c, xf, ws->c_array[r][c]->h_link.str);
2192 } */
2193 }
2194
add_str_array(U8 uni,U8 * str,U16 len,U8 * fmt_run,U8 crun_cnt)2195 void add_str_array(U8 uni, U8 *str, U16 len, U8 *fmt_run, U8 crun_cnt)
2196 {
2197
2198 if ((str == 0)||(len == 0))
2199 {
2200 next_string++; /* increment for empty strings, too */
2201 return;
2202 }
2203 if (next_string >= max_strings)
2204 {
2205 uni_string **tstr_array;
2206 size_t new_size = (max_strings + STRINGS_INCR) * sizeof(uni_string *);
2207
2208 tstr_array = (uni_string **)realloc(str_array, new_size);
2209
2210 if (tstr_array == NULL)
2211 {
2212 MaxStringsExceeded = 1;
2213 /* fprintf(stderr, "%s: cannot allocate %d bytes for string storage %d: %s",
2214 PRGNAME, new_size, errno, strerror(errno)); */
2215 return;
2216 }
2217 else
2218 {
2219 unsigned long i;
2220
2221 str_array = tstr_array;
2222
2223 /* Clear the new string slots */
2224 for (i=max_strings; i<(max_strings + STRINGS_INCR); i++)
2225 str_array[i] = 0;
2226
2227 max_strings += STRINGS_INCR;
2228 }
2229 }
2230
2231 if (str_array[next_string] == 0)
2232 {
2233 str_array[next_string] = (uni_string *)malloc(sizeof(uni_string));
2234 if (str_array[next_string])
2235 {
2236 str_array[next_string]->str = (U8 *)malloc(len+1);
2237 if (str_array[next_string]->str)
2238 {
2239 memcpy(str_array[next_string]->str, str, len);
2240 str_array[next_string]->str[len] = 0;
2241 str_array[next_string]->len = len;
2242 str_array[next_string]->uni = uni;
2243 if (fmt_run && crun_cnt)
2244 {
2245 int rlen = crun_cnt*4;
2246
2247 str_array[next_string]->fmt_run = malloc(rlen);
2248 if (str_array[next_string]->fmt_run)
2249 {
2250 memcpy(str_array[next_string]->fmt_run, fmt_run, rlen);
2251 str_array[next_string]->crun_cnt = crun_cnt;
2252 }
2253 else
2254 str_array[next_string]->crun_cnt = 0;
2255 }
2256 else
2257 {
2258 str_array[next_string]->fmt_run = 0;
2259 str_array[next_string]->crun_cnt = 0;
2260 }
2261 }
2262 }
2263 }
2264 next_string++;
2265 }
2266
add_font(U16 size,U16 attr,U16 c_idx,U16 bold,U16 super,U8 underline,U16 uni,U8 * n,U16 len)2267 void add_font(U16 size, U16 attr, U16 c_idx, U16 bold, U16 super, U8 underline,
2268 U16 uni, U8 *n, U16 len)
2269 {
2270 if (n == 0)
2271 return;
2272 if (next_font >= max_fonts)
2273 {
2274 font_attr **tfont_array;
2275 fnt_cnt *tf_cnt;
2276 tfont_array = (font_attr **)realloc(font_array, (max_fonts * FONTS_INCR) * sizeof(font_attr *));
2277 tf_cnt = (fnt_cnt *)realloc(f_cnt, (max_fonts * FONTS_INCR) * sizeof(fnt_cnt));
2278
2279 if ((tf_cnt == NULL) || (tfont_array == NULL))
2280 {
2281 MaxFontsExceeded = 1;
2282 return;
2283 }
2284 else
2285 { /* Next init the array... */
2286 unsigned int i;
2287
2288 font_array = tfont_array;
2289 f_cnt = tf_cnt;
2290
2291 for (i=max_fonts; i<max_fonts+FONTS_INCR; i++)
2292 {
2293 font_array[i] = 0;
2294 f_cnt[i].name = 0;
2295 }
2296 max_fonts += FONTS_INCR;
2297 }
2298 }
2299
2300 if (font_array[next_font] == 0)
2301 {
2302 font_array[next_font] = (font_attr *)malloc(sizeof(font_attr));
2303 if (font_array[next_font])
2304 {
2305 font_array[next_font]->name.str = (U8 *)malloc(len+1);
2306 if (font_array[next_font]->name.str)
2307 {
2308 font_array[next_font]->attr = attr;
2309 font_array[next_font]->c_idx = c_idx;
2310 font_array[next_font]->bold = bold;
2311 font_array[next_font]->super = super;
2312 font_array[next_font]->underline = underline;
2313 font_array[next_font]->name.uni = uni;
2314 memcpy(font_array[next_font]->name.str, n, len);
2315 font_array[next_font]->name.str[len] = 0;
2316 font_array[next_font]->name.len = len;
2317 font_array[next_font]->name.fmt_run = 0;
2318 font_array[next_font]->name.crun_cnt = 0;
2319
2320 /* We will "pre-digest" the font size.. */
2321 if (size >= 0x02D0) /* 36 pts */
2322 font_array[next_font]->size = 7;
2323 else if (size >= 0x01E0) /* 24 pts */
2324 font_array[next_font]->size = 6;
2325 else if (size >= 0x0168) /* 18 pts */
2326 font_array[next_font]->size = 5;
2327 else if (size >= 0x00F0) /* 12 pts */
2328 font_array[next_font]->size = 4;
2329 else if (size >= 0x00C8) /* 10 pts */
2330 font_array[next_font]->size = 3;
2331 else if (size >= 0x00A0) /* 8 pts */
2332 font_array[next_font]->size = 2;
2333 else
2334 font_array[next_font]->size = 1;
2335 }
2336 }
2337 }
2338 next_font++;
2339 if (next_font == 4) /* Per the doc's - number 4 doesn't exist. */
2340 next_font++;
2341 }
2342
add_ws_title(U16 uni,U8 * n,U16 len)2343 void add_ws_title(U16 uni, U8 *n, U16 len)
2344 {
2345 if (n == 0)
2346 return;
2347
2348 if (next_ws_title >= max_worksheets)
2349 {
2350 if (add_more_worksheet_ptrs())
2351 return;
2352 }
2353
2354 if (ws_array[next_ws_title] == 0)
2355 {
2356 if (ws_init(next_ws_title))
2357 return;
2358 }
2359 if (ws_array[next_ws_title]->ws_title.str == 0)
2360 {
2361 ws_array[next_ws_title]->ws_title.str = (U8 *)malloc(len+1);
2362 if (ws_array[next_ws_title]->ws_title.str)
2363 {
2364 ws_array[next_ws_title]->ws_title.uni = uni;
2365 memcpy(ws_array[next_ws_title]->ws_title.str, n, len);
2366 ws_array[next_ws_title]->ws_title.str[len] = 0;
2367 ws_array[next_ws_title]->ws_title.len = len;
2368 ws_array[next_ws_title]->ws_title.crun_cnt = 0;
2369 ws_array[next_ws_title]->ws_title.fmt_run = 0;
2370 }
2371 }
2372 next_ws_title++;
2373 }
2374
add_xf_array(U16 fnt_idx,U16 fmt_idx,U16 gen,U16 align,U16 indent,U16 b_style,U16 b_l_color,U32 b_t_color,U16 cell_color)2375 void add_xf_array(U16 fnt_idx, U16 fmt_idx, U16 gen, U16 align,
2376 U16 indent, U16 b_style, U16 b_l_color, U32 b_t_color, U16 cell_color)
2377 {
2378 if (next_xf >= max_xformats)
2379 {
2380 xf_attr **txf_array;
2381
2382 txf_array = (xf_attr **)realloc(xf_array, (max_xformats + XFORMATS_INCR) * sizeof(xf_attr *));
2383 if (txf_array == NULL)
2384 {
2385 MaxXFExceeded = 1;
2386 return;
2387 }
2388 else
2389 {
2390 unsigned int i;
2391
2392 xf_array = txf_array;
2393
2394 for (i=max_xformats; i<(max_xformats + XFORMATS_INCR); i++)
2395 xf_array[i] = 0;
2396
2397 max_xformats += XFORMATS_INCR;
2398 }
2399 }
2400
2401 if (xf_array[next_xf] == 0)
2402 {
2403 xf_array[next_xf] = (xf_attr *)malloc(sizeof(xf_attr));
2404 if (xf_array[next_xf])
2405 {
2406 xf_array[next_xf]->fnt_idx = fnt_idx;
2407 xf_array[next_xf]->fmt_idx = fmt_idx;
2408 xf_array[next_xf]->gen = gen;
2409 xf_array[next_xf]->align = align;
2410 xf_array[next_xf]->indent = indent;
2411 xf_array[next_xf]->b_style = b_style;
2412 xf_array[next_xf]->b_l_color = b_l_color;
2413 xf_array[next_xf]->b_t_color = b_t_color;
2414 xf_array[next_xf]->cell_color = cell_color;
2415 }
2416 next_xf++;
2417 }
2418 }
2419
decodeBoolErr(U16 value,U16 flag,char * str)2420 void decodeBoolErr(U16 value, U16 flag, char *str)
2421 {
2422 if (str == 0)
2423 return;
2424
2425 if (flag == 0)
2426 {
2427 if (value == 1)
2428 strcpy(str, "TRUE");
2429 else
2430 strcpy(str, "FALSE");
2431 }
2432 else
2433 {
2434 switch(value)
2435 {
2436 case 0x00:
2437 strcpy(str, "#NULL!");
2438 break;
2439 case 0x07:
2440 strcpy(str, "#DIV/0!");
2441 break;
2442 case 0x0F:
2443 strcpy(str, "#VALUE!");
2444 break;
2445 case 0x17:
2446 strcpy(str, "#REF!");
2447 break;
2448 case 0x1D:
2449 strcpy(str, "#NAME?");
2450 break;
2451 case 0x24:
2452 strcpy(str, "#NUM!");
2453 break;
2454 case 0x2A:
2455 strcpy(str, "#N/A");
2456 break;
2457 default:
2458 strcpy(str, "#ERR");
2459 break;
2460 }
2461 }
2462 }
2463
IsCellNumeric(cell * c)2464 int IsCellNumeric(cell *c)
2465 {
2466 int ret_val = 0;
2467
2468 switch (c->type & 0x00FF)
2469 {
2470 case 0x02: /* Int */
2471 case 0x03: /* Float */
2472 /* case 0x06: */ /* Formula */
2473 /* case 0x08: */
2474 case 0x7E: /* RK */
2475 /* case 0xBC: */
2476 /* case 0x21: */
2477 case 0xBD: /* MulRK */
2478 ret_val = 1;
2479 break;
2480 default:
2481 break;
2482 }
2483 return ret_val;
2484 }
2485
2486 /*! \retval 0 not safe at all.
2487 \retval 1 extended format is OK
2488 \retval 2 Fonts OK */
IsCellSafe(cell * c)2489 int IsCellSafe(cell *c)
2490 {
2491 int safe = 0;
2492
2493 if (c->xfmt < next_xf)
2494 {
2495 if (xf_array[c->xfmt])
2496 {
2497 safe = 1;
2498 if (xf_array[c->xfmt]->fnt_idx < next_font)
2499 {
2500 if (font_array[xf_array[c->xfmt]->fnt_idx])
2501 safe = 2;
2502 }
2503 }
2504 }
2505 return safe;
2506 }
2507
IsCellFormula(cell * c)2508 int IsCellFormula(cell *c)
2509 {
2510 if ((c->type > 0x0100)||(c->type == 0x0006))
2511 return 1;
2512 else
2513 return 0;
2514 }
2515
output_cell(cell * c,int xml)2516 void output_cell(cell *c, int xml)
2517 {
2518 html_attr h;
2519
2520 if (c == NULL)
2521 printf( xml ? "" : "<TD> ");
2522 else if (c->spanned != 0)
2523 return;
2524 else
2525 { /* Determine whether or not its of numeric origin.. */
2526 int numeric = IsCellNumeric(c); /* 0=Text 1=Numeric */
2527 html_flag_init(&h);
2528 if (c->xfmt == 0)
2529 { /* Unknown format... */
2530 printf( xml ? "" : "<TD>"); /* This section doesn't use Unicode */
2531 if (c->ustr.str)
2532 OutputString(&(c->ustr));
2533 else
2534 printf( xml ? "" : " ");
2535 }
2536 else
2537 { /* This is the BIFF7 & 8 stuff... */
2538 int safe;
2539 int nullString = 1;
2540
2541 safe = IsCellSafe(c);
2542
2543 if (c->ustr.str)
2544 {
2545 if (c->ustr.uni < 2) /* UNI? */
2546 nullString = null_string(c->ustr.str);
2547 else
2548 nullString = 0;
2549 }
2550
2551 /* First take care of text color & alignment */
2552 printf( xml ? "" : "<TD");
2553 if ((c->rowspan != 0)||(c->colspan != 0))
2554 {
2555 if (c->colspan)
2556 printf( xml ? "<colspan>%d</colspan>" : " COLSPAN=\"%d\"", c->colspan);
2557 if (c->rowspan)
2558 printf( xml ? "<rowspan>%d</rowspan>" : " ROWSPAN=\"%d\"", c->rowspan);
2559 }
2560 if ((safe > 0)&&(!nullString))
2561 {
2562 switch(xf_array[c->xfmt]->align & 0x0007)
2563 { /* Override default table alignment when needed */
2564 case 2:
2565 case 6: /* Center across selection */
2566 if (strcmp(default_alignment, "center") != 0)
2567 printf( xml ? "" : " ALIGN=\"center\"");
2568 break;
2569 case 0: /* General alignment */
2570 if (numeric) /* Numbers */
2571 {
2572 if (strcmp(default_alignment, "right") != 0)
2573 printf( xml ? "" : " ALIGN=\"right\"");
2574 }
2575 else if ((c->type & 0x00FF) == 0x05)
2576 { /* Boolean */
2577 if (strcmp(default_alignment, "center") != 0)
2578 printf( xml ? "" : " ALIGN=\"center\"");
2579 }
2580 else
2581 {
2582 if (strcmp(default_alignment, "left") != 0)
2583 printf( xml ? "" : " ALIGN=\"left\"");
2584 }
2585 break;
2586 case 3:
2587 if (strcmp(default_alignment, "right") != 0)
2588 printf( xml ? "" : " ALIGN=\"right\"");
2589 break;
2590 case 1:
2591 default:
2592 if (strcmp(default_alignment, "left") != 0)
2593 printf( xml ? "" : " ALIGN=\"left\"");
2594 break;
2595 }
2596 switch((xf_array[c->xfmt]->align & 0x0070)>>4)
2597 {
2598 case 0:
2599 printf( xml ? "" : " VALIGN=\"top\"");
2600 break;
2601 case 1:
2602 printf( xml ? "" : " VALIGN=\"center\"");
2603 break;
2604 case 2: /* General alignment */
2605 if (safe > 1)
2606 {
2607 if ((font_array[xf_array[c->xfmt]->fnt_idx]->super & 0x0003) == 0x0001)
2608 printf( xml ? "" : " VALIGN=\"top\""); /* Superscript */
2609 }
2610 break;
2611 default:
2612 if (safe > 1)
2613 {
2614 if ((font_array[xf_array[c->xfmt]->fnt_idx]->super & 0x0003) == 0x0001)
2615 printf( xml ? "" : " VALIGN=\"top\""); /* Superscript */
2616 }
2617 break;
2618 }
2619 }
2620 /* Next do the bgcolor... BGCOLOR="" */
2621 if (safe && use_colors)
2622 {
2623 int fgcolor;
2624 /* int bgcolor = (xf_array[c->xfmt]->cell_color & 0x3F80) >> 7; */
2625 fgcolor = (xf_array[c->xfmt]->cell_color & 0x007F);
2626 /* printf(" XF:%X BG Color:%d, FG Color:%d", c->xfmt, bgcolor, fgcolor); */
2627
2628 /* Might be better by blending bg & fg colors?
2629 If valid, fgcolor != black and fgcolor != white */
2630 if( ! xml )
2631 {
2632 if (numCustomColors)
2633 {
2634 if (fgcolor < numCustomColors)
2635 {
2636 if (strcmp(default_background_color, (char *)customColors[fgcolor-8]) != 0)
2637 printf(" BGCOLOR=\"%s\"", customColors[fgcolor-8]);
2638 }
2639 }
2640 else
2641 {
2642 if (fgcolor < MAX_COLORS)
2643 {
2644 if (strcmp(default_background_color, colorTab[fgcolor]) != 0)
2645 printf(" BGCOLOR=\"%s\"", colorTab[fgcolor]);
2646 }
2647 }
2648 }
2649 }
2650
2651 /* Next set the border color... */
2652 if (safe && use_colors)
2653 {
2654 int lcolor, rcolor, tcolor, bcolor;
2655 lcolor = xf_array[c->xfmt]->b_l_color & 0x007F;
2656 rcolor = (xf_array[c->xfmt]->b_l_color & 0x3F80) >> 7;
2657 tcolor = xf_array[c->xfmt]->b_t_color & 0x007F;
2658 bcolor = (xf_array[c->xfmt]->b_t_color & 0x3F80) >> 7;
2659 if (((lcolor & rcolor & tcolor & bcolor) == lcolor)&&(lcolor < MAX_COLORS))
2660 { /* if they are all the same...do it...that is if its different from BLACK */
2661 if (numCustomColors == 0) /* Don't do custom borders */
2662 {
2663 if ((strcmp(colorTab[lcolor], "000000") != 0)&&(strcmp(colorTab[lcolor], "FFFFFF") != 0))
2664 {
2665 if( !xml )
2666 printf(" BORDERCOLOR=\"%s\"", colorTab[lcolor]);
2667 }
2668 }
2669 }
2670 }
2671
2672 /* Close up the <TD>... */
2673 printf(xml ? "" : ">");
2674
2675 /* Next set font properties */
2676 if (safe > 1 && !xml )
2677 {
2678 if (!nullString)
2679 output_start_font_attribute(&h, xf_array[c->xfmt]->fnt_idx);
2680 }
2681
2682 /* Finally, take care of font modifications */
2683 if ((safe > 1)&&(!nullString))
2684 {
2685 if ((font_array[xf_array[c->xfmt]->fnt_idx]->underline&0x0023) > 0)
2686 {
2687 if (c->h_link.str)
2688 {
2689 printf("<A href=\"");
2690 if (c->h_link.uni)
2691 {
2692 if (memchr((char *)c->h_link.str, ':', c->h_link.len) == 0)
2693 {
2694 if (memchr((char *)c->h_link.str, '@', c->h_link.len))
2695 printf("mailto:");
2696 }
2697 }
2698 OutputString(&(c->h_link));
2699 printf("\">");
2700 h.uflag = 2;
2701 }
2702 else
2703 {
2704 printf("<U>");
2705 h.uflag = 1;
2706 }
2707 }
2708 output_start_html_attr(&h, xf_array[c->xfmt]->fnt_idx, 0);
2709 }
2710 if (c->ustr.str)
2711 {
2712 if (safe)
2713 output_formatted_data(&(c->ustr), xf_array[c->xfmt]->fmt_idx, numeric, IsCellFormula(c));
2714 else
2715 OutputString(&(c->ustr));
2716 }
2717 else
2718 printf( xml ? "" : " ");
2719 /* printf(" T:%02X", c->type & 0x00FF); */
2720 }
2721
2722 /* Now close the tags... */
2723 output_end_html_attr(&h);
2724 if (h.fflag)
2725 printf("</FONT>");
2726 }
2727
2728 if (!aggressive)
2729 printf( xml ? "" : "</TD>\n");
2730 }
2731
output_formatted_data(uni_string * u,U16 idx,int numeric,int formula)2732 void output_formatted_data(uni_string *u, U16 idx, int numeric, int formula)
2733 {
2734 if ((idx < max_xformats)&&(u->str))
2735 {
2736 if ((formula_warnings)&&(formula))
2737 {
2738 if( OutputXML )
2739 printf( "<NotAccurate/>" );
2740 else
2741 printf("** ");
2742 notAccurate++;
2743 }
2744 if (numeric)
2745 {
2746 int year, month, date;
2747 long num;
2748 F64 dnum;
2749 int hr, minu, sec, msec;
2750
2751 /* printf("idx:%d ", idx); */
2752 switch (idx)
2753 {
2754 case 0x00: /* General */
2755 dnum = atof((char *)u->str);
2756 printf("%.15g", dnum);
2757 break;
2758 case 0x01: /* Number 0 */
2759 dnum = atof((char *)u->str);
2760 printf("%.0f", dnum);
2761 break;
2762 case 0x02: /* Number 0.00 */
2763 dnum = atof((char *)u->str);
2764 printf("%.2f", dnum);
2765 break;
2766 case 0x03: /* Number w/comma 0,000 */
2767 PrintFloatComma("%.0f", 0, (F64)atof((char *)u->str));
2768 break;
2769 case 0x04: /* Number w/comma 0,000.00 */
2770 PrintFloatComma("%.2f", 0, (F64)atof((char *)u->str));
2771 break;
2772 case 0x05: /* Currency, no decimal */
2773 PrintFloatComma("%.0f", 1, (F64)atof((char *)u->str));
2774 break;
2775 case 0x06: /* Currency, no decimal Red on Neg */
2776 PrintFloatComma("%.0f", 1, (F64)atof((char *)u->str));
2777 break;
2778 case 0x07: /* Currency with decimal */
2779 PrintFloatComma("%.2f", 1, (F64)atof((char *)u->str));
2780 break;
2781 case 0x08: /* Currency with decimal Red on Neg */
2782 PrintFloatComma("%.2f", 1, (F64)atof((char *)u->str));
2783 break;
2784 case 0x09: /* Percent 0% */
2785 if (Csv)
2786 printf("\"");
2787 dnum = 100.0*atof((char *)u->str);
2788 printf("%.0f%%", dnum);
2789 if (Csv)
2790 printf("\"");
2791 break;
2792 case 0x0A: /* Percent 0.00% */
2793 if (Csv)
2794 printf("\"");
2795 dnum = 100.0*atof((char *)u->str);
2796 printf("%.2f%%", dnum);
2797 if (Csv)
2798 printf("\"");
2799 break;
2800 case 0x0B: /* Scientific 0.00+E00 */
2801 if (Csv)
2802 printf("\"");
2803 dnum = atof((char *)u->str);
2804 printf("%.2E", dnum);
2805 if (Csv)
2806 printf("\"");
2807 break;
2808 case 0x0C: /* Fraction 1 number e.g. 1/2, 1/3 */
2809 if (Csv)
2810 printf("\"");
2811 dnum = atof((char *)u->str);
2812 print_as_fraction(dnum, 1);
2813 if (Csv)
2814 printf("\"");
2815 break;
2816 case 0x0D: /* Fraction 2 numbers e.g. 1/50, 25/33 */
2817 if (Csv)
2818 printf("\"");
2819 dnum = atof((char *)u->str);
2820 print_as_fraction(dnum, 2);
2821 if (Csv)
2822 printf("\"");
2823 break;
2824 case 0x0E: /* Date: m-d-y */
2825 if (Csv)
2826 printf("\"");
2827 num = atol((char *)u->str);
2828 NumToDate(num, &year, &month, &date);
2829 printf("%d-%d-%02d", month, date, year);
2830 if (Csv)
2831 printf("\"");
2832 break;
2833 case 0x0F: /* Date: d-mmm-yy */
2834 if (Csv)
2835 printf("\"");
2836 num = atol((char *)u->str);
2837 NumToDate(num, &year, &month, &date);
2838 printf("%d-%s-%02d", date, month_abbr[month-1], year);
2839 if (Csv)
2840 printf("\"");
2841 break;
2842 case 0x10: /* Date: d-mmm */
2843 if (Csv)
2844 printf("\"");
2845 num = atol((char *)u->str);
2846 NumToDate(num, &year, &month, &date);
2847 printf("%d-%s", date, month_abbr[month-1]);
2848 if (Csv)
2849 printf("\"");
2850 break;
2851 case 0x11: /* Date: mmm-yy */
2852 if (Csv)
2853 printf("\"");
2854 num = atol((char *)u->str);
2855 NumToDate(num, &year, &month, &date);
2856 printf("%s-%02d", month_abbr[month-1], year);
2857 if (Csv)
2858 printf("\"");
2859 break;
2860 case 0x12: /* Time: h:mm AM/PM */
2861 if (Csv)
2862 printf("\"");
2863 FracToTime(u->str, &hr, &minu, 0, 0);
2864 if (hr == 0)
2865 printf("12:%02d AM", minu);
2866 else if (hr < 12)
2867 printf("%d:%02d AM", hr, minu);
2868 else if (hr == 12)
2869 printf("12:%02d PM", minu);
2870 else
2871 printf("%d:%02d PM", hr-12, minu);
2872 if (Csv)
2873 printf("\"");
2874 break;
2875 case 0x13: /* Time: h:mm:ss AM/PM */
2876 if (Csv)
2877 printf("\"");
2878 FracToTime(u->str, &hr, &minu, &sec, 0);
2879 if (hr == 0)
2880 printf("12:%02d:%02d AM", minu, sec);
2881 else if (hr < 12)
2882 printf("%d:%02d:%02d AM", hr, minu, sec);
2883 else if (hr == 12)
2884 printf("12:%02d:%02d PM", minu, sec);
2885 else
2886 printf("%d:%02d:%02d PM", hr-12, minu, sec);
2887 if (Csv)
2888 printf("\"");
2889 break;
2890 case 0x14: /* Time: h:mm */
2891 if (Csv)
2892 printf("\"");
2893 FracToTime(u->str, &hr, &minu, 0, 0);
2894 printf("%d:%02d", hr, minu);
2895 if (Csv)
2896 printf("\"");
2897 break;
2898 case 0x15: /* Time: h:mm:ss */
2899 if (Csv)
2900 printf("\"");
2901 FracToTime(u->str, &hr, &minu, &sec, 0);
2902 if ((hr != 0)||(minu != 0)||(sec != 0))
2903 printf("%d:%02d:%02d", hr, minu, sec);
2904 else
2905 {
2906 if (Ascii)
2907 putchar(' ');
2908 else
2909 printf(OutputXML ? "" : " ");
2910 }
2911 if (Csv)
2912 printf("\"");
2913 break;
2914 case 0x25: /* Number with comma, no decimal */
2915 if (Csv)
2916 printf("\"");
2917 PrintFloatComma("%.0f", 0, (F64)atof((char *)u->str));
2918 if (Csv)
2919 printf("\"");
2920 break;
2921 case 0x26: /* Number with comma, no decimal, red on negative */
2922 if (Csv)
2923 printf("\"");
2924 PrintFloatComma("%.0f", 0, (F64)atof((char *)u->str));
2925 if (Csv)
2926 printf("\"");
2927 break;
2928 case 0x27: /* Number with comma & decimal */
2929 if (Csv)
2930 printf("\"");
2931 PrintFloatComma("%.2f", 0, (F64)atof((char *)u->str));
2932 if (Csv)
2933 printf("\"");
2934 break;
2935 case 0x28: /* Number with comma & decimal, red on negative */
2936 if (Csv)
2937 printf("\"");
2938 PrintFloatComma("%.2f", 0, (F64)atof((char *)u->str));
2939 if (Csv)
2940 printf("\"");
2941 break;
2942 case 0x29: /* Number with comma, no decimal */
2943 if (Csv)
2944 printf("\"");
2945 PrintFloatComma("%.2f", 0, (F64)atof((char *)u->str));
2946 if (Csv)
2947 printf("\"");
2948 break;
2949 case 0x2a: /* Currency, no decimal */
2950 if (Csv)
2951 printf("\"");
2952 PrintFloatComma("%.0f", 1, (F64)atof((char *)u->str));
2953 if (Csv)
2954 printf("\"");
2955 break;
2956 case 0x2B: /* Number w/comma & decimal 0,000.00 */
2957 if (Csv)
2958 printf("\"");
2959 PrintFloatComma("%.2f", 0, (F64)atof((char *)u->str));
2960 if (Csv)
2961 printf("\"");
2962 break;
2963 case 0x2C: /* Accounting Currency $0,000.00 */
2964 {
2965 F64 acc_val = atof((char *)u->str);
2966 if (Csv)
2967 printf("\"");
2968 if (acc_val < 0.0)
2969 PrintFloatComma(" (%.2f)", 1, fabs(acc_val));
2970 else
2971 PrintFloatComma(" %.2f", 1, acc_val);
2972 if (Csv)
2973 printf("\"");
2974 break;
2975 }
2976 case 0x2D: /* Time: mm:ss */
2977 if (Csv)
2978 printf("\"");
2979 FracToTime(u->str, &hr, &minu, &sec, 0);
2980 printf("%02d:%02d", minu, sec);
2981 if (Csv)
2982 printf("\"");
2983 break;
2984 case 0x2E: /* Time: [h]:mm:ss */
2985 if (Csv)
2986 printf("\"");
2987 FracToTime(u->str, &hr, &minu, &sec, 0);
2988 if (hr)
2989 printf("%d:%02d:%02d", hr, minu, sec);
2990 else
2991 printf("%02d:%02d", minu, sec);
2992 if (Csv)
2993 printf("\"");
2994 break;
2995 case 0x2F: /* Time: mm:ss.0 */
2996 if (Csv)
2997 printf("\"");
2998 FracToTime(u->str, &hr, &minu, &sec, &msec);
2999 printf("%02d:%02d.%01d", minu, sec, msec);
3000 if (Csv)
3001 printf("\"");
3002 break;
3003 case 0x31: /* Text - if we are here...its a number */
3004 dnum = atof((char *)u->str);
3005 printf("%g", dnum);
3006 break;
3007 default: /* Unsupported...but, if we are here, its a number */
3008 {
3009 char *ptr = strchr((char *)u->str, '.');
3010 if( OutputXML )
3011 printf( "<NoFormat/>" );
3012 dnum = atof((char *)u->str);
3013 if (ptr)
3014 {
3015 if (Csv)
3016 printf("\"%.15g\"", dnum );
3017 else if (OutputXML)
3018 printf("%.15g", dnum );
3019 else
3020 printf("%.15g *", dnum );
3021 }
3022 else
3023 {
3024 num = atol((char *)u->str);
3025 if (Csv)
3026 printf("%ld", num);
3027 else if (OutputXML)
3028 printf("%ld", num );
3029 else
3030 printf("%ld *", num );
3031 }
3032
3033 /* printf(" F:%02X", idx); */
3034 NoFormat++ ;
3035 }
3036 break;
3037 }
3038 }
3039 else /* Text data */
3040 OutputString(u);
3041 }
3042 else /* Error handling just dump it. */
3043 OutputString(u);
3044 }
3045
3046
3047
PrintFloatComma(char * fformat,int is_currency,F64 d)3048 void PrintFloatComma(char *fformat, int is_currency, F64 d)
3049 {
3050 int len, int_len, dec_len;
3051 char *ptr2, buf[64];
3052
3053 sprintf(buf, fformat, fabs(d));
3054 len = strlen(buf);
3055 ptr2 = strchr(buf, '.');
3056 if (ptr2)
3057 {
3058 int_len = ptr2 - buf;
3059 dec_len = len - int_len;
3060 if (isdigit(buf[0]) == 0)
3061 {
3062 char *ptr = &buf[0];
3063 while (isdigit(*ptr) == 0)
3064 {
3065 int_len--;
3066 ptr++;
3067 if (*ptr == 0)
3068 break;
3069 }
3070 }
3071 }
3072 else
3073 {
3074 int_len = len;
3075 dec_len = 0;
3076 }
3077
3078 if (int_len > 3)
3079 { /* we have to do it the hard way... */
3080 char rbuf[64], buf2[64];
3081 int neg, i, j, count=0;
3082
3083 if (d < 0.0)
3084 neg = 1;
3085 else
3086 neg = 0;
3087
3088 /* reverse the string. Its easier to work this way. */
3089 for (i=0, j=len-1; i<len;i++, j--)
3090 rbuf[i] = buf[j];
3091 rbuf[len] = 0;
3092 if (ptr2)
3093 {
3094 memcpy(buf2, rbuf, dec_len);
3095 i = dec_len;
3096 j = dec_len;
3097 }
3098 else
3099 {
3100 i = 0;
3101 j = 0;
3102 }
3103
3104 for ( ;i<len;i++, j++)
3105 {
3106 buf2[j] = rbuf[i];
3107 count++;
3108 if ((count%3)==0)
3109 {
3110 if (isdigit(rbuf[i+1]))
3111 buf2[++j] = ',';
3112 }
3113 }
3114 if (neg)
3115 buf2[j++] = '-';
3116 if (is_currency)
3117 buf2[j++] = (char)currency_symbol;
3118 buf2[j] = 0;
3119
3120 len = strlen(buf2);
3121 for (i=0, j=len-1; i<len;i++, j--)
3122 buf[i] = buf2[j];
3123 buf[len] = 0;
3124 if (Csv)
3125 printf("\"%s\"", buf);
3126 else
3127 printf("%s", buf);
3128 }
3129 else /* too short for commas, just output it as is. */
3130 {
3131 if (is_currency)
3132 putchar((char)currency_symbol);
3133 printf(fformat, d);
3134 }
3135 }
3136
print_as_fraction(F64 d,int digits)3137 void print_as_fraction(F64 d, int digits)
3138 {
3139 F64 i, j, w, r, closest=1.0, lim = 9.0;
3140 int ci=1, cj=1;
3141
3142 /* Take care of negative sign */
3143 if (digits == 2)
3144 lim = 99.0;
3145 if (d < 0)
3146 putchar('-');
3147
3148 /** take care of whole number part */
3149 w = fabs(d);
3150 if (w >= 1.0)
3151 {
3152 int n = (int)w;
3153 printf("%d ", n);
3154 r = w - (F64)n;
3155 }
3156 else
3157 r = w;
3158
3159 /* Get closest fraction - brute force */
3160 for (j=lim; j>0.0; j--)
3161 {
3162 for (i=lim; i>=0.0; i--)
3163 {
3164 if ( fabs((i/j)-r) <= closest)
3165 {
3166 closest = fabs((i/j)-r);
3167 ci = (int)i;
3168 cj = (int)j;
3169 }
3170 }
3171 }
3172
3173 /* Done, print it... */
3174 if (ci != 0)
3175 printf("%d/%d", ci, cj);
3176 }
3177
trim_sheet_edges(unsigned int sheet)3178 void trim_sheet_edges(unsigned int sheet)
3179 {
3180 cell *ce;
3181 int not_done = 1;
3182 S32 r;
3183 U16 c;
3184
3185 if ((sheet >= max_worksheets)||(ws_array[sheet] == 0)||
3186 (trim_edges == 0)||(ws_array[sheet]->spanned))
3187 return;
3188 if (ws_array[sheet]->c_array == 0)
3189 return;
3190 if ( (ws_array[sheet]->biggest_row == -1) ||
3191 (ws_array[sheet]->biggest_col == -1) )
3192 return;
3193
3194 /* First find top edge */
3195 for (r=ws_array[sheet]->first_row; r<=ws_array[sheet]->biggest_row; r++)
3196 {
3197 for (c=ws_array[sheet]->first_col; c<=ws_array[sheet]->biggest_col; c++)
3198 { /* This stuff happens for each cell... */
3199 ce = ws_array[sheet]->c_array[(r*ws_array[sheet]->max_cols)+c];
3200 if (ce)
3201 {
3202 if (ce->ustr.str)
3203 {
3204 if (!null_string(ce->ustr.str))
3205 {
3206 not_done = 0;
3207 break;
3208 }
3209 }
3210 }
3211 }
3212 if (!not_done)
3213 break;
3214 }
3215 if (not_done)
3216 ws_array[sheet]->first_row = ws_array[sheet]->biggest_row;
3217 else
3218 ws_array[sheet]->first_row = r;
3219
3220 /* Second Find bottom edge */
3221 not_done = 1;
3222 for (r=ws_array[sheet]->biggest_row; r>(S32)ws_array[sheet]->first_row; r--)
3223 {
3224 for (c=ws_array[sheet]->first_col; c<=ws_array[sheet]->biggest_col; c++)
3225 { /* This stuff happens for each cell... */
3226 ce = ws_array[sheet]->c_array[(r*ws_array[sheet]->max_cols)+c];
3227 if (ce)
3228 {
3229 if (ce->ustr.str)
3230 {
3231 if (!null_string(ce->ustr.str))
3232 {
3233 not_done = 0;
3234 break;
3235 }
3236 }
3237 }
3238 }
3239 if (!not_done)
3240 break;
3241 }
3242 ws_array[sheet]->biggest_row = r;
3243
3244 /* Third find left edge */
3245 not_done = 1;
3246 for (c=ws_array[sheet]->first_col; c<=ws_array[sheet]->biggest_col; c++)
3247 {
3248 for (r=ws_array[sheet]->first_row; r<=ws_array[sheet]->biggest_row; r++)
3249 { /* This stuff happens for each cell... */
3250 ce = ws_array[sheet]->c_array[(r*ws_array[sheet]->max_cols)+c];
3251 if (ce)
3252 {
3253 if (ce->ustr.str)
3254 {
3255 if (!null_string(ce->ustr.str))
3256 {
3257 not_done = 0;
3258 break;
3259 }
3260 }
3261 }
3262 }
3263 if (!not_done)
3264 break;
3265 }
3266 if (not_done)
3267 ws_array[sheet]->first_col = ws_array[sheet]->biggest_col;
3268 else
3269 ws_array[sheet]->first_col = c;
3270
3271 /* Last, find right edge */
3272 not_done = 1;
3273 for (c=ws_array[sheet]->biggest_col; c>ws_array[sheet]->first_col; c--)
3274 {
3275 for (r=ws_array[sheet]->first_row; r<=ws_array[sheet]->biggest_row; r++)
3276 { /* This stuff happens for each cell... */
3277 ce = ws_array[sheet]->c_array[(r*ws_array[sheet]->max_cols)+c];
3278 if (ce)
3279 {
3280 if (ce->ustr.str)
3281 {
3282 if (!null_string(ce->ustr.str))
3283 {
3284 not_done = 0;
3285 break;
3286 }
3287 }
3288 }
3289 }
3290 if (!not_done)
3291 break;
3292 }
3293 ws_array[sheet]->biggest_col = c;
3294 }
3295
3296 /***************
3297 *! Figures out the best font & alignment for the current table.
3298 * Also sets the default_font and default_alignment.
3299 ****************/
update_default_font(unsigned int sheet)3300 void update_default_font(unsigned int sheet)
3301 {
3302 cell *ce;
3303 int r, c, f;
3304
3305 if ((sheet >= max_worksheets)||(ws_array[sheet] == 0))
3306 return;
3307 if (ws_array[sheet]->c_array == 0)
3308 return;
3309
3310 /* Clear the book-keeping info... */
3311 for (r=0; r<FONTS_INCR; r++)
3312 {
3313 f_cnt[r].cnt = 0;
3314 if (f_cnt[r].name)
3315 {
3316 if (f_cnt[r].name->str)
3317 free(f_cnt[r].name->str);
3318 free(f_cnt[r].name);
3319 f_cnt[r].name = 0;
3320 }
3321 }
3322 if (default_font.str)
3323 free(default_font.str);
3324 for (r=0; r<7; r++)
3325 fnt_size_cnt[r] = 0;
3326
3327 /* Now check each cell to see what its using. */
3328 for (r=ws_array[sheet]->first_row; r<=ws_array[sheet]->biggest_row; r++)
3329 {
3330 for (c=ws_array[sheet]->first_col; c<=ws_array[sheet]->biggest_col; c++)
3331 { /* This stuff happens for each cell... */
3332 ce = ws_array[sheet]->c_array[(r*ws_array[sheet]->max_cols)+c];
3333 if (ce)
3334 {
3335 if ((ce->xfmt < next_xf)&&(ce->ustr.str))
3336 {
3337 if (strcmp((char *)ce->ustr.str, " "))
3338 {
3339 if (ce->xfmt < next_xf)
3340 {
3341 if (xf_array[ce->xfmt])
3342 {
3343 unsigned int fn = xf_array[ce->xfmt]->fnt_idx;
3344 if (fn < next_font)
3345 {
3346 if (font_array[fn])
3347 {
3348 if (font_array[fn]->name.str)
3349 {
3350 /* Here's where we check & increment count... */
3351 incr_f_cnt(&(font_array[fn]->name));
3352 if ((font_array[fn]->size < 8)&&(font_array[fn]->size))
3353 fnt_size_cnt[font_array[fn]->size-1]++;
3354 }
3355 }
3356 }
3357 }
3358 }
3359 }
3360 }
3361 }
3362 }
3363 }
3364
3365 f = get_default_font();
3366 if (f == -1)
3367 {
3368 default_font.str = (U8 *)malloc(6);
3369 if (default_font.str)
3370 {
3371 strcpy((char *)default_font.str, "Arial");
3372 default_font.uni = 0;
3373 default_font.len = 5;
3374 }
3375 }
3376 else
3377 {
3378 default_font.str = (U8 *)malloc(f_cnt[f].name->len+1);
3379 if (default_font.str)
3380 {
3381 memcpy(default_font.str, f_cnt[f].name->str, f_cnt[f].name->len);
3382 default_font.str[f_cnt[f].name->len] = 0;
3383 default_font.uni = f_cnt[f].name->uni;
3384 default_font.len = f_cnt[f].name->len;
3385 }
3386 }
3387
3388 /* Find the font size with the most counts...
3389 Just re-using variables, c - max cnt, f = position of max cnt */
3390 c = 0;
3391 f = 3;
3392 for (r=0; r<7; r++)
3393 {
3394 if (fnt_size_cnt[r] > c)
3395 {
3396 c = fnt_size_cnt[r];
3397 f = r;
3398 }
3399 }
3400 if (fnt_size_cnt[2] == c) /* favor size 3... */
3401 default_fontsize = 3;
3402 else
3403 default_fontsize = f+1;
3404
3405 for (r=0; r<FONTS_INCR; r++)
3406 {
3407 if (f_cnt[r].name != 0)
3408 {
3409 if (f_cnt[r].name->str != 0)
3410 free(f_cnt[r].name->str);
3411 free(f_cnt[r].name);
3412 f_cnt[r].name= 0;
3413 }
3414 }
3415 }
3416
incr_f_cnt(uni_string * name)3417 void incr_f_cnt(uni_string *name)
3418 {
3419 int i;
3420
3421 if ((name == 0)||(name->str == 0)||(name->str[0] == 0))
3422 return;
3423
3424 for (i=0; i<FONTS_INCR; i++)
3425 {
3426 if (f_cnt[i].name)
3427 {
3428 if (uni_string_comp(name, f_cnt[i].name) == 0)
3429 f_cnt[i].cnt++;
3430 }
3431 else
3432 {
3433 f_cnt[i].name = (uni_string *)malloc(sizeof(uni_string));
3434 if (f_cnt[i].name)
3435 {
3436 f_cnt[i].name->str = (U8 *)malloc(name->len+1);
3437 if (f_cnt[i].name->str)
3438 {
3439 memcpy(f_cnt[i].name->str, name->str, name->len);
3440 f_cnt[i].name->str[name->len] = 0;
3441 f_cnt[i].name->uni = name->uni;
3442 f_cnt[i].name->len = name->len;
3443 f_cnt[i].cnt = 1;
3444 break;
3445 }
3446 }
3447 }
3448 }
3449 }
3450
get_default_font(void)3451 int get_default_font(void)
3452 {
3453 int i, m = -1;
3454
3455 for (i=0; i<FONTS_INCR; i++)
3456 {
3457 if (f_cnt[i].name)
3458 {
3459 if (f_cnt[i].name->str)
3460 {
3461 if (f_cnt[i].cnt > m)
3462 m = i;
3463 }
3464 }
3465 }
3466 return m;
3467 }
3468
update_default_alignment(unsigned int sheet,int row)3469 void update_default_alignment(unsigned int sheet, int row)
3470 {
3471 int i, left = 0, center = 0, right = 0;
3472 cell *c;
3473
3474 if ((sheet >= max_worksheets)||(ws_array[sheet] == 0))
3475 return;
3476 if (ws_array[sheet]->c_array == 0)
3477 return;
3478
3479 for (i=ws_array[sheet]->first_col; i<=ws_array[sheet]->biggest_col; i++)
3480 { /* This stuff happens for each cell... */
3481 c = ws_array[sheet]->c_array[(row*ws_array[sheet]->max_cols)+i];
3482 if (c)
3483 {
3484 int numeric = IsCellNumeric(c);
3485 if (c->xfmt == 0)
3486 { /* Unknown format... */
3487 left++;
3488 }
3489 else
3490 { /* Biff 8 stuff... */
3491 if ((c->xfmt < next_xf)&&(c->ustr.str))
3492 {
3493 if (strcmp((char *)c->ustr.str, " "))
3494 {
3495 if (xf_array[c->xfmt])
3496 {
3497 switch(xf_array[c->xfmt]->align & 0x0007)
3498 { /* Override default table alignment when needed */
3499 case 2:
3500 case 6: /* Center across selection */
3501 center++;
3502 break;
3503 case 0: /* General alignment */
3504 if (numeric) /* Numbers */
3505 right++;
3506 else if ((c->type & 0x00FF) == 0x05) /* Boolean */
3507 center++;
3508 else
3509 left++;
3510 break;
3511 case 3:
3512 right++;
3513 break;
3514 case 1: /* fall through... */
3515 default:
3516 left++;
3517 break;
3518 }
3519 }
3520 }
3521 }
3522 }
3523 }
3524 }
3525 if ((center == 0)&&(left == 0)&&(right == 0))
3526 default_alignment = "";
3527 else if ((center >= left)&&(center >= right)) /* Favor center since its the longest word */
3528 default_alignment = "center";
3529 else if ((right >= center)&&(right >= left))
3530 default_alignment = "right"; /* Favor right since its second longest */
3531 else
3532 default_alignment = "left";
3533 }
3534
3535
OutputString(uni_string * u)3536 void OutputString(uni_string *u)
3537 {
3538 unsigned int i;
3539
3540 if (u == 0)
3541 return;
3542
3543 if (u->uni < 2)
3544 {
3545 if (null_string(u->str))
3546 {
3547 if (Ascii == 0)
3548 printf(OutputXML ? "" : " ");
3549 else if (!Csv)
3550 printf(" ");
3551 }
3552 else
3553 {
3554 if (Ascii) /* If Ascii output requested, simply output the string */
3555 { /* These are broken up for performance */
3556 if (Csv)
3557 {
3558 for (i=0; i<u->len; i++)
3559 {
3560 if (u->str[i] == 0x22)
3561 printf("\"\"");
3562 else
3563 putchar(u->str[i]);
3564 }
3565 }
3566 else
3567 {
3568 for (i=0; i<u->len; i++)
3569 putchar(u->str[i]);
3570 }
3571 return;
3572 }
3573 if (u->crun_cnt)
3574 {
3575 U16 loc, fnt_idx, crun_cnt=0;
3576 int format_changed = 0;
3577 html_attr h_flags;
3578
3579 /* read the first format run */
3580 update_crun_info(&loc, &fnt_idx, crun_cnt, u->fmt_run);
3581 html_flag_init(&h_flags);
3582 for (i=0; i<u->len; i++)
3583 {
3584 if (i == loc)
3585 { /* Time to change formats */
3586 if (format_changed)
3587 { /* if old attributs, close */
3588 output_end_html_attr(&h_flags);
3589 if (h_flags.fflag)
3590 printf("</FONT>");
3591 }
3592 else
3593 { /* FIXME: Also need to consider that a font may already be set for
3594 the cell, in which case a closing tag should be set. */
3595 format_changed = 1;
3596 }
3597
3598 /* set new attr */
3599 output_start_font_attribute(&h_flags, fnt_idx);
3600 output_start_html_attr(&h_flags, fnt_idx, 1);
3601
3602 /* get next fmt_run */
3603 if (crun_cnt < u->crun_cnt)
3604 {
3605 crun_cnt++;
3606 update_crun_info(&loc, &fnt_idx, crun_cnt, u->fmt_run);
3607 }
3608 }
3609 OutputCharCorrected(u->str[i]);
3610 }
3611 if (format_changed)
3612 {
3613 output_end_html_attr(&h_flags);
3614 if (h_flags.fflag)
3615 printf("</FONT>");
3616 }
3617 }
3618 else
3619 {
3620 for (i=0; i<u->len; i++)
3621 OutputCharCorrected(u->str[i]);
3622 }
3623 }
3624 }
3625 else
3626 {
3627 if (u->len == 0)
3628 {
3629 if (Ascii)
3630 printf(" ");
3631 else
3632 printf(OutputXML ? "" : " ");
3633 }
3634 else
3635 {
3636 if (u->len == 2)
3637 {
3638 if (memcmp(u->str, "& ", 2) == 0)
3639 printf("…");
3640 else
3641 {
3642 for (i=0; i<u->len; i+=2)
3643 print_utf8(getShort(&(u->str[i])));
3644 }
3645 }
3646 else
3647 {
3648 for (i=0; i<u->len; i+=2)
3649 print_utf8(getShort(&(u->str[i])));
3650 }
3651 }
3652 }
3653 }
3654
OutputCharCorrected(U8 c)3655 void OutputCharCorrected(U8 c)
3656 {
3657 if (MultiByte && (c & 0x80))
3658 {
3659 putchar(c);
3660 return;
3661 }
3662 switch (c)
3663 { /* Special char handlers here... */
3664 case 0x3C:
3665 printf("<");
3666 break;
3667 case 0x3E:
3668 printf(">");
3669 break;
3670 case 0x26:
3671 printf("&");
3672 break;
3673 case 0x22:
3674 printf(""");
3675 break;
3676 /* Also need to cover 128-159 since MS uses this area... */
3677 case 0x80: /* Euro Symbol */
3678 printf("€");
3679 break;
3680 case 0x82: /* baseline single quote */
3681 printf("‚");
3682 break;
3683 case 0x83: /* florin */
3684 printf("ƒ");
3685 break;
3686 case 0x84: /* baseline double quote */
3687 printf("„");
3688 break;
3689 case 0x85: /* ellipsis */
3690 printf("…");
3691 break;
3692 case 0x86: /* dagger */
3693 printf("†");
3694 break;
3695 case 0x87: /* double dagger */
3696 printf("‡");
3697 break;
3698 case 0x88: /* circumflex accent */
3699 printf("ˆ");
3700 break;
3701 case 0x89: /* permile */
3702 printf("‰");
3703 break;
3704 case 0x8A: /* S Hacek */
3705 printf("Š");
3706 break;
3707 case 0x8B: /* left single guillemet */
3708 printf("‹");
3709 break;
3710 case 0x8C: /* OE ligature */
3711 printf("Œ");
3712 break;
3713 case 0x8E: /* #LATIN CAPITAL LETTER Z WITH CARON */
3714 printf("Ž");
3715 break;
3716 case 0x91: /* left single quote ? */
3717 printf("‘");
3718 break;
3719 case 0x92: /* right single quote ? */
3720 printf("’");
3721 break;
3722 case 0x93: /* left double quote */
3723 printf("“");
3724 break;
3725 case 0x94: /* right double quote */
3726 printf("”");
3727 break;
3728 case 0x95: /* bullet */
3729 printf("•");
3730 break;
3731 case 0x96: /* endash */
3732 printf("–");
3733 break;
3734 case 0x97: /* emdash */
3735 printf("—");
3736 break;
3737 case 0x98: /* tilde accent */
3738 printf("˜");
3739 break;
3740 case 0x99: /* trademark ligature */
3741 printf("™");
3742 break;
3743 case 0x9A: /* s Haceks Hacek */
3744 printf("š");
3745 break;
3746 case 0x9B: /* right single guillemet */
3747 printf("›");
3748 break;
3749 case 0x9C: /* oe ligature */
3750 printf("œ");
3751 break;
3752 case 0x9F: /* Y Dieresis */
3753 printf("Ÿ");
3754 break;
3755 case 0xE1: /* a acute */
3756 printf("�");
3757 break;
3758 case 0xE9: /* e acute */
3759 printf("�");
3760 break;
3761 case 0xED: /* i acute */
3762 printf("�");
3763 break;
3764 case 0xF3: /* o acute */
3765 printf("�");
3766 break;
3767 case 0xFA: /* u acute */
3768 printf("�");
3769 break;
3770 case 0xFD: /* y acute */
3771 printf("�");
3772 break;
3773 case 0xB0: /* degrees */
3774 printf("deg.");
3775 break;
3776 default:
3777 putchar(c);
3778 break;
3779 }
3780 }
3781
update_crun_info(U16 * loc,U16 * fmt_idx,U16 crun_cnt,U8 * fmt_run)3782 void update_crun_info(U16 *loc, U16 *fmt_idx, U16 crun_cnt, U8 *fmt_run)
3783 {
3784 U16 tloc, tfmt_idx;
3785 U16 offset = (U16)(crun_cnt*4);
3786
3787 tloc = getShort(&fmt_run[offset]);
3788 tfmt_idx = getShort(&fmt_run[offset+2]);
3789 *loc = tloc;
3790 *fmt_idx = tfmt_idx;
3791 }
3792
put_utf8(U16 c)3793 void put_utf8(U16 c)
3794 {
3795 putchar((int)0x0080 | (c & 0x003F));
3796 }
3797
print_utf8(U16 c)3798 void print_utf8(U16 c)
3799 {
3800 if (c < 0x80)
3801 OutputCharCorrected(c);
3802 else if (c < 0x800)
3803 {
3804 putchar(0xC0 | (c >> 6));
3805 put_utf8(c);
3806 }
3807 else
3808 {
3809 putchar(0xE0 | (c >> 12));
3810 put_utf8((U16)(c >> 6));
3811 put_utf8(c);
3812 }
3813 }
3814
uni_string_clear(uni_string * str)3815 void uni_string_clear(uni_string *str)
3816 {
3817 if (str == 0)
3818 return;
3819
3820 str->str = 0;
3821 str->uni = 0;
3822 str->len = 0;
3823 str->fmt_run = 0;
3824 str->crun_cnt = 0;
3825 }
3826
uni_string_comp(uni_string * s1,uni_string * s2)3827 int uni_string_comp(uni_string *s1, uni_string *s2)
3828 {
3829 if ((s1 == 0)||(s2 == 0))
3830 return -1;
3831 if ((s1->str == 0)||(s2->str == 0))
3832 return -1;
3833
3834 if ((s1->uni == s2->uni) && (s1->len == s2->len))
3835 return memcmp(s1->str, s2->str, s1->len);
3836 else
3837 return -1;
3838 }
3839
3840
3841
html_flag_init(html_attr * h)3842 void html_flag_init(html_attr *h)
3843 {
3844 h->fflag = 0;
3845 h->bflag = 0;
3846 h->iflag = 0;
3847 h->sflag = 0;
3848 h->uflag = 0;
3849 h->sbflag = 0;
3850 h->spflag = 0;
3851 }
3852
output_start_font_attribute(html_attr * h,U16 fnt_idx)3853 void output_start_font_attribute(html_attr *h, U16 fnt_idx)
3854 {
3855 if (uni_string_comp(&default_font, &(font_array[fnt_idx]->name)) != 0)
3856 {
3857 h->fflag = 1;
3858 printf("<FONT FACE=\"");
3859 OutputString(&(font_array[fnt_idx]->name));
3860 printf("\"");
3861 }
3862 if (font_array[fnt_idx]->c_idx != 0x7FFF)
3863 {
3864 char color[8];
3865 if (numCustomColors)
3866 {
3867 if ((font_array[fnt_idx]->c_idx < numCustomColors)&&use_colors)
3868 strcpy(color, (char *)customColors[font_array[fnt_idx]->c_idx-8]);
3869 else
3870 strcpy(color, "000000");
3871 }
3872 else
3873 {
3874 if ((font_array[fnt_idx]->c_idx < MAX_COLORS)&&use_colors)
3875 strcpy(color, colorTab[font_array[fnt_idx]->c_idx]);
3876 else
3877 strcpy(color, "000000");
3878 }
3879 if (strcmp(color, "000000") != 0)
3880 {
3881 if (h->fflag)
3882 printf(" COLOR=\"%s\"", color);
3883 else
3884 {
3885 h->fflag = 1;
3886 printf("<FONT COLOR=\"%s\"", color);
3887 }
3888 }
3889 }
3890 if (font_array[fnt_idx]->super & 0x0003)
3891 {
3892 if (h->fflag)
3893 printf(" SIZE=2"); /* Sub & Superscript */
3894 else
3895 {
3896 h->fflag = 1;
3897 printf("<FONT SIZE=2"); /* Sub & Superscript */
3898 }
3899 }
3900 else
3901 {
3902 if (h->fflag)
3903 {
3904 if (font_array[fnt_idx]->size != default_fontsize)
3905 printf(" SIZE=%d", font_array[fnt_idx]->size);
3906 }
3907 else
3908 {
3909 if (font_array[fnt_idx]->size != default_fontsize)
3910 {
3911 h->fflag = 1;
3912 printf("<FONT SIZE=%d", font_array[fnt_idx]->size);
3913 }
3914 }
3915 }
3916 if (h->fflag)
3917 printf(">");
3918 }
3919
3920
3921