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>&nbsp;");
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 ? "" : "&nbsp;");
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 ? "" : "&nbsp;");
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 ? "" : "&nbsp;");
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, "&nbsp;"))
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, "&nbsp;"))
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 ? "" : "&nbsp;");
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 ? "" : "&nbsp;");
3633 		}
3634 		else
3635 		{
3636 			if (u->len == 2)
3637 			{
3638 				if (memcmp(u->str, "& ", 2) == 0)
3639 					printf("&#8230;");
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("&lt;");
3666 			break;
3667 		case 0x3E:
3668 			printf("&gt;");
3669 			break;
3670 		case 0x26:
3671 			printf("&amp;");
3672 			break;
3673 		case 0x22:
3674 			printf("&quot;");
3675 			break;
3676 		/* Also need to cover 128-159 since MS uses this area... */
3677 		case 0x80:		/* Euro Symbol */
3678 			printf("&#8364;");
3679 			break;
3680 		case 0x82:		/* baseline single quote */
3681 			printf("&#8218;");
3682 			break;
3683 		case 0x83:		/* florin */
3684 			printf("&#402;");
3685 			break;
3686 		case 0x84:		/* baseline double quote */
3687 			printf("&#8222;");
3688 			break;
3689 		case 0x85:		/* ellipsis */
3690 			printf("&#8230;");
3691 			break;
3692 		case 0x86:		/* dagger */
3693 		    printf("&#8224;");
3694 		    break;
3695 		case 0x87:		/* double dagger */
3696 		    printf("&#8225;");
3697 		    break;
3698 		case 0x88:		/* circumflex accent */
3699 		    printf("&#710;");
3700 		    break;
3701 		case 0x89:		/* permile */
3702 		    printf("&#8240;");
3703 		    break;
3704 		case 0x8A:		/* S Hacek */
3705 		    printf("&#352;");
3706 		    break;
3707 		case 0x8B:		/* left single guillemet */
3708 		    printf("&#8249;");
3709 		    break;
3710 		case 0x8C:		/* OE ligature */
3711 		    printf("&#338;");
3712 		    break;
3713 		case 0x8E:		/*  #LATIN CAPITAL LETTER Z WITH CARON */
3714 			printf("&#381;");
3715 			break;
3716 		case 0x91:		/* left single quote ? */
3717 		    printf("&#8216;");
3718 		    break;
3719 		case 0x92:		/* right single quote ? */
3720 		    printf("&#8217;");
3721 		    break;
3722 		case 0x93:		/* left double quote */
3723 		    printf("&#8220;");
3724 		    break;
3725 		case 0x94:		/* right double quote */
3726 		    printf("&#8221;");
3727 		    break;
3728 		case 0x95:		/* bullet */
3729 		    printf("&#8226;");
3730 		    break;
3731 		case 0x96:		/* endash */
3732 		    printf("&#8211;");
3733 		    break;
3734 		case 0x97:		/* emdash */
3735 		    printf("&#8212;");
3736 		    break;
3737 		case 0x98:		/* tilde accent */
3738 		    printf("&#732;");
3739 		    break;
3740 		case 0x99:		/* trademark ligature */
3741 		    printf("&#8482;");
3742 		    break;
3743 		case 0x9A:		/* s Haceks Hacek */
3744 		    printf("&#353;");
3745 		    break;
3746 		case 0x9B:		/* right single guillemet */
3747 		    printf("&#8250;");
3748 		    break;
3749 		case 0x9C:		/* oe ligature */
3750 		    printf("&#339;");
3751 		    break;
3752 		case 0x9F:		/* Y Dieresis */
3753 		    printf("&#376;");
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