ms-excel-read.c 106 KB
Newer Older
1
/**
2 3
 * ms-excel.c: MS Excel support for Gnumeric
 *
4
 * Authors:
5
 *    Michael Meeks (michael@imaginator.com)
6
 *    Jody Goldberg (jgoldberg@home.com)
7
 *
Jody Goldberg's avatar
Jody Goldberg committed
8
 * (C) 1998, 1999, 2000 Michael Meeks, Jody Goldberg
9
 **/
10

11
#include <config.h>
Jon K Hellan's avatar
Jon K Hellan committed
12
#include "command-context.h"
13

14 15
#include "ms-formula-read.h"
#include "ms-excel-read.h"
16
#include "ms-obj.h"
17
#include "ms-chart.h"
18
#include "gnumeric-chart.h"
19
#include "ms-escher.h"
20
#include "print-info.h"
Jody Goldberg's avatar
Jody Goldberg committed
21
#include "selection.h"
22
#include "parse-util.h"	/* for cell_name */
23
#include "ranges.h"
24
#include "expr-name.h"
25
#include "style.h"
26
#include "eval.h"
27
#include "cell-comment.h"
28
#include "application.h"
29
#include "workbook.h"
30
#include "ms-excel-util.h"
31
#include "ms-excel-xf.h"
32
#include "workbook-view.h"
33

34 35 36
/* #define NO_DEBUG_EXCEL */

/* Used in src/main.c to toggle debug messages on & off */
37 38 39 40 41 42
/*
 * As a convention
 * 0 = quiet, no experimental features.
 * 1 = enable experimental features
 * >1 increasing levels of detail.
 */
Michael Meeks's avatar
Michael Meeks committed
43
int ms_excel_read_debug    = 0;
Michael Meeks's avatar
Michael Meeks committed
44
int ms_excel_write_debug   = 0;
45
int ms_excel_formula_debug = 0;
Michael Meeks's avatar
Michael Meeks committed
46 47
int ms_excel_color_debug   = 0;
int ms_excel_chart_debug   = 0;
48
extern int gnumeric_debugging;
49

50
/* Forward references */
Michael Meeks's avatar
Michael Meeks committed
51
static ExcelSheet *ms_excel_sheet_new       (ExcelWorkbook *wb,
Michael Meeks's avatar
Michael Meeks committed
52
					     const char *name);
Michael Meeks's avatar
Michael Meeks committed
53 54
static void        ms_excel_workbook_attach (ExcelWorkbook *wb,
					     ExcelSheet *ans);
55

56
void
Michael Meeks's avatar
Michael Meeks committed
57
ms_excel_unexpected_biff (BiffQuery *q, char const *const state)
58
{
59
#ifndef NO_DEBUG_EXCEL
60
	if (ms_excel_read_debug > 0) {
61 62 63
		printf ("Unexpected Opcode in %s : 0x%x, length 0x%x\n",
			state, q->opcode, q->length);
		if (ms_excel_read_debug > 2)
64
			ms_ole_dump (q->data, q->length);
65
	}
66 67 68 69
#endif
}


70 71 72 73 74
/**
 * Generic 16 bit int index pointer functions.
 **/
static guint
biff_guint16_hash (const guint16 *d)
75 76 77 78
{
	return *d*2;
}

79 80
static guint
biff_guint32_hash (const guint32 *d)
81 82 83
{
	return *d*2;
}
84 85 86 87

static gint
biff_guint16_equal (const guint16 *a, const guint16 *b)
{
88 89
	if (*a == *b)
		return 1;
Michael Meeks's avatar
Michael Meeks committed
90
	return 0;
91 92 93 94
}
static gint
biff_guint32_equal (const guint32 *a, const guint32 *b)
{
95 96
	if (*a == *b)
		return 1;
Michael Meeks's avatar
Michael Meeks committed
97
	return 0;
98 99
}

100 101 102 103 104
/**
 * This returns whether there is a header byte
 * and sets various flags from it
 **/
static gboolean
105
biff_string_get_flags (const guint8 *ptr,
106 107 108 109
		       gboolean *word_chars,
		       gboolean *extended,
		       gboolean *rich)
{
Michael Meeks's avatar
Michael Meeks committed
110
	guint8 header;
111

112
	header = MS_OLE_GET_GUINT8(ptr);
113
	/* I assume that this header is backwards compatible with raw ASCII */
114 115 116

	/* Its a proper Unicode header grbit byte */
	if (((header & 0xf2) == 0)) {
Michael Meeks's avatar
Michael Meeks committed
117 118 119 120 121 122 123 124 125
		*word_chars = (header & 0x1) != 0;
		*extended   = (header & 0x4) != 0;
		*rich       = (header & 0x8) != 0;
		return TRUE;
	} else { /* Some assumptions: FIXME ? */
		*word_chars = 0;
		*extended   = 0;
		*rich       = 0;
		return FALSE;
126 127 128
	}
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static void
get_xtn_lens (guint32 *pre_len, guint32 *end_len, const guint8 *ptr, gboolean ext_str, gboolean rich_str)
{
	*end_len = 0;
	*pre_len = 0;

	if (rich_str) { /* The data for this appears after the string */
		guint16 formatting_runs = MS_OLE_GET_GUINT16 (ptr);
		static int warned = FALSE;

		(*end_len) += formatting_runs * 4; /* 4 bytes per */
		(*pre_len) += 2;
		ptr        += 2;

		if (!warned)
			printf ("FIXME: rich string support unimplemented:"
				"discarding %d runs\n", formatting_runs);
		warned = TRUE;
	}
	if (ext_str) { /* NB this data always comes after the rich_str data */
		guint32 len_ext_rst = MS_OLE_GET_GUINT32 (ptr); /* A byte length */
		static int warned = FALSE;

		(*end_len) += len_ext_rst;
		(*pre_len) += 4;

		if (!warned)
			printf ("FIXME: extended string support unimplemented:"
				"ignoring %d bytes\n", len_ext_rst);
		warned = TRUE;
	}
}

162 163 164
/**
 *  This function takes a length argument as Biff V7 has a byte length
 * ( seemingly ).
165 166
 * it returns the length in bytes of the string in byte_length
 * or nothing if this is NULL.
167 168
 *  FIXME: see S59D47.HTM for full description
 **/
169
char *
170
biff_get_text (const guint8 *pos, guint32 length, guint32 *byte_length)
171
{
Michael Meeks's avatar
Michael Meeks committed
172
	guint32 lp;
173
	char *ans;
174
	const guint8 *ptr;
Michael Meeks's avatar
Michael Meeks committed
175 176 177
	guint32 byte_len;
	gboolean header;
	gboolean high_byte;
178
	static gboolean high_byte_warned = FALSE;
Michael Meeks's avatar
Michael Meeks committed
179 180
	gboolean ext_str;
	gboolean rich_str;
181

182
	if (!byte_length)
Michael Meeks's avatar
Michael Meeks committed
183 184
		byte_length = &byte_len;
	*byte_length = 0;
185

Jody Goldberg's avatar
Jody Goldberg committed
186
	if (!length) {
187 188 189
		/* FIXME FIXME FIXME : What about the 1 byte for the header ?
		 *                     The length may be wrong in this case.
		 */
Michael Meeks's avatar
Michael Meeks committed
190
		return 0;
191
	}
192

193 194 195
#ifndef NO_DEBUG_EXCEL
	if (ms_excel_read_debug > 1) {
		printf ("String :\n");
196
		ms_ole_dump (pos, length+1);
197 198 199
	}
#endif

200
	ans = (char *) g_new (char, length + 2);
201

202 203 204
	header = biff_string_get_flags (pos,
					&high_byte,
					&ext_str,
Michael Meeks's avatar
Michael Meeks committed
205
					&rich_str);
206
	if (header) {
Michael Meeks's avatar
Michael Meeks committed
207 208 209 210
		ptr = pos + 1;
		(*byte_length)++;
	} else
		ptr = pos;
211 212

	/* A few friendly warnings */
Michael Meeks's avatar
Michael Meeks committed
213 214
	if (high_byte && !high_byte_warned) {
		printf ("FIXME: unicode support unimplemented: truncating\n");
215 216
		high_byte_warned = TRUE;
	}
Michael Meeks's avatar
Michael Meeks committed
217

218 219
	{
		guint32 pre_len, end_len;
Michael Meeks's avatar
Michael Meeks committed
220

221 222 223
		get_xtn_lens (&pre_len, &end_len, ptr, ext_str, rich_str);
		ptr += pre_len;
		(*byte_length) += pre_len + end_len;
224
	}
Michael Meeks's avatar
Michael Meeks committed
225

226

227
#ifndef NO_DEBUG_EXCEL
Michael Meeks's avatar
Michael Meeks committed
228
	if (ms_excel_read_debug > 4) {
229
		printf ("String len %d, byte length %d: %d %d %d:\n",
Michael Meeks's avatar
Michael Meeks committed
230
			length, (*byte_length), high_byte, rich_str, ext_str);
231
		ms_ole_dump (pos, *byte_length);
232
	}
233
#endif
234

235
	for (lp = 0; lp < length; lp++) {
236
		guint16 c;
237 238

		if (high_byte) {
239
			c = MS_OLE_GET_GUINT16 (ptr);
240
			ptr+=2;
241 242
			ans[lp] = (char)c;
			(*byte_length) += 2;
243
		} else {
244
			c = MS_OLE_GET_GUINT8 (ptr);
245
			ptr+=1;
246 247
			ans[lp] = (char)c;
			(*byte_length) += 1;
248
		}
249
	}
250 251 252 253
	if (lp > 0)
		ans[lp] = 0;
	else
		g_warning ("Warning unterminated string floating");
254
	return ans;
255 256
}

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
static char *
get_utf8_chars (const char *ptr, guint len, gboolean high_byte)
{
	int    i;
	char *ans = g_new (char, len + 1);

	for (i = 0; i < len; i++) {
		guint16 c;

		if (high_byte) {
			c = MS_OLE_GET_GUINT16 (ptr);
			ptr+=2;
			ans [i] = (char)c;
		} else {
			c = MS_OLE_GET_GUINT8 (ptr);
			ptr+=1;
			ans [i] = (char)c;
		}
	}
	ans [i] = '\0';

	return ans;
}

static guint32
sst_bound_check (BiffQuery *q, guint32 offset)
{
	if (offset >= q->length) {
		guint32 d = offset - q->length;
286 287 288 289 290
		guint16 opcode;
		
		if (!ms_biff_query_peek_next (q, &opcode) ||
		    opcode != BIFF_CONTINUE)
			return 0;
291 292 293
		
		if (!ms_biff_query_next (q))
			return 0;
294 295

		return d;
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	} else
		return offset;
}

/*
 * NB. Whilst the string proper is split, and whilst we get several headers,
 * it seems that the attributes appear in a single block after the end
 * of the string, which may also be split over continues.
 */
static guint32
get_string (char **output, BiffQuery *q, guint32 offset, eBiff_version ver)
{
	guint32  new_offset;
	guint32  total_len;
	guint32  total_end_len;
	/* Will be localy scoped when gdb gets its act together */
		gboolean header;
		gboolean high_byte;
		gboolean ext_str = FALSE;
		gboolean rich_str = FALSE;
		guint32  chars_left;
		guint32  pre_len, end_len;
		guint32  get_len;
		char    *str;

	g_return_val_if_fail (q != NULL &&
			      q->data != NULL &&
			      output != NULL &&
			      offset < q->length, 0);

	*output       = NULL;
	total_len     = MS_OLE_GET_GUINT16 (q->data + offset);
	new_offset    = offset + 2;
	total_end_len = 0;

	do {
		new_offset = sst_bound_check (q, new_offset);
		
		header = biff_string_get_flags (q->data + new_offset,
						&high_byte,
						&ext_str,
						&rich_str);
		if (!header) {
			g_warning ("Seriously broken string with no header 0x%x", *(q->data + new_offset));
			ms_ole_dump (q->data + new_offset, q->length - new_offset);
			return 0;
		}

		new_offset++;

		get_xtn_lens (&pre_len, &end_len, q->data + new_offset, ext_str, rich_str);
		total_end_len += end_len;

		/* the - end_len is an educated guess based on insufficient data */
		chars_left = (q->length - new_offset - pre_len) / (high_byte?2:1);
		if (chars_left > total_len)
			get_len = total_len;
		else 
			get_len = chars_left;
		total_len -= get_len;
		g_assert (get_len >= 0);

		/* FIXME: split this simple bit out of here, it makes more sense damnit */
		str = get_utf8_chars (q->data + new_offset + pre_len, get_len, high_byte);
		new_offset += pre_len + get_len * (high_byte?2:1);

		if (!(*output))
			*output = str;
		else {
			char *old_output = *output;
			*output = g_strconcat (*output, str, NULL);
			g_free (str);
			g_free (old_output);
		}

	} while (total_len > 0);

	return sst_bound_check (q, new_offset + total_end_len);
}

static void
read_sst (ExcelWorkbook *wb, BiffQuery *q, eBiff_version ver)
{
	guint32 offset;
	int     k;

#ifndef NO_DEBUG_EXCEL
	if (ms_excel_read_debug>4) {
		printf ("SST\n");
		ms_ole_dump (q->data, q->length);
	}
#endif
	wb->global_string_max = MS_OLE_GET_GUINT32 (q->data + 4);
	wb->global_strings = g_new (char *, wb->global_string_max);

	offset = 8;

	for (k = 0; k < wb->global_string_max; k++) {
		offset = get_string (&wb->global_strings [k], q, offset, ver);

		if (!wb->global_strings [k]) {
#ifdef NO_DEBUG_EXCEL
			if (ms_excel_read_debug > 4)
				printf ("Blank string in table at : 0x%x with length %d\n",
					k, byte_len);
#endif
		}
#ifdef NO_DEBUG_EXCEL
		else if (ms_excel_read_debug > 4)
			puts (wb->global_strings[k]);
#endif
	}
}

410
char const *
411
biff_get_error_text (const guint8 err)
412
{
413
	char const *buf;
Jody Goldberg's avatar
Jody Goldberg committed
414
	switch (err) {
Michael Meeks's avatar
Michael Meeks committed
415
	case 0:  buf = gnumeric_err_NULL;  break;
416
	case 7:  buf = gnumeric_err_DIV0;  break;
Michael Meeks's avatar
Michael Meeks committed
417 418 419 420 421
	case 15: buf = gnumeric_err_VALUE; break;
	case 23: buf = gnumeric_err_REF;   break;
	case 29: buf = gnumeric_err_NAME;  break;
	case 36: buf = gnumeric_err_NUM;   break;
	case 42: buf = gnumeric_err_NA;    break;
422
	default:
Michael Meeks's avatar
Michael Meeks committed
423
		buf = _("#UNKNOWN!"); break;
424
	}
Michael Meeks's avatar
Michael Meeks committed
425
	return buf;
426 427
}

428 429 430
/**
 * See S59D5D.HTM
 **/
Michael Meeks's avatar
Michael Meeks committed
431
BIFF_BOF_DATA *
432
ms_biff_bof_data_new (BiffQuery *q)
433
{
434 435
	BIFF_BOF_DATA *ans = g_new (BIFF_BOF_DATA, 1);

436
	if ((q->opcode & 0xff) == BIFF_BOF &&
Michael Meeks's avatar
Michael Meeks committed
437
	    (q->length >= 4)) {
438 439 440
		/*
		 * Determine type from boff
		 */
441
		switch (q->opcode >> 8) {
442 443 444 445 446 447 448 449 450 451
		case 0:
			ans->version = eBiffV2;
			break;
		case 2:
			ans->version = eBiffV3;
			break;
		case 4:
			ans->version = eBiffV4;
			break;
		case 8:	/*
452
			 * More complicated
453
			 */
454
			{
455
#ifndef NO_DEBUG_EXCEL
Michael Meeks's avatar
Michael Meeks committed
456
				if (ms_excel_read_debug > 2) {
457
					printf ("Complicated BIFF version %d\n",
458
						MS_OLE_GET_GUINT16 (q->data));
459
					ms_ole_dump (q->data, q->length);
460 461
				}
#endif
Jody Goldberg's avatar
Jody Goldberg committed
462
				switch (MS_OLE_GET_GUINT16 (q->data)) {
463 464 465 466
				case 0x0600:
					ans->version = eBiffV8;
					break;
				case 0x500:
467
					ans->version = eBiffV7;		/*
468
									 * OR ebiff7 : FIXME ? !
469 470 471 472 473 474 475 476 477 478 479
									 */
					break;
				default:
					printf ("Unknown BIFF sub-number in BOF %x\n", q->opcode);
					ans->version = eBiffVUnknown;
				}
			}
			break;
		default:
			printf ("Unknown BIFF number in BOF %x\n", q->opcode);
			ans->version = eBiffVUnknown;
Arturo Espinosa's avatar
Arturo Espinosa committed
480
			printf ("Biff version %d\n", ans->version);
481
		}
482
		switch (MS_OLE_GET_GUINT16 (q->data + 2)) {
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
		case 0x0005:
			ans->type = eBiffTWorkbook;
			break;
		case 0x0006:
			ans->type = eBiffTVBModule;
			break;
		case 0x0010:
			ans->type = eBiffTWorksheet;
			break;
		case 0x0020:
			ans->type = eBiffTChart;
			break;
		case 0x0040:
			ans->type = eBiffTMacrosheet;
			break;
		case 0x0100:
			ans->type = eBiffTWorkspace;
			break;
		default:
			ans->type = eBiffTUnknown;
503
			printf ("Unknown BIFF type in BOF %x\n", MS_OLE_GET_GUINT16 (q->data + 2));
504 505 506
			break;
		}
		/*
507
		 * Now store in the directory array:
508
		 */
509
#ifndef NO_DEBUG_EXCEL
Michael Meeks's avatar
Michael Meeks committed
510
		if (ms_excel_read_debug > 2) {
511 512
			printf ("BOF %x, %d == %d, %d\n", q->opcode, q->length,
				ans->version, ans->type);
513
		}
514
#endif
515 516 517 518
	} else {
		printf ("Not a BOF !\n");
		ans->version = eBiffVUnknown;
		ans->type = eBiffTUnknown;
519
	}
520

521
	return ans;
522 523
}

Michael Meeks's avatar
Michael Meeks committed
524
void
Michael Meeks's avatar
Michael Meeks committed
525
ms_biff_bof_data_destroy (BIFF_BOF_DATA *data)
526
{
527
	g_free (data);
528 529
}

530 531 532
/**
 * See S59D61.HTM
 **/
533
static void
Michael Meeks's avatar
Michael Meeks committed
534
biff_boundsheet_data_new (ExcelWorkbook *wb, BiffQuery *q, eBiff_version ver)
535
{
Michael Meeks's avatar
Michael Meeks committed
536
	BiffBoundsheetData *ans = g_new (BiffBoundsheetData, 1);
537 538

	if (ver != eBiffV5 &&	/*
539
				 * Testing seems to indicate that Biff5 is compatibile with Biff7 here.
540
				 */
Arturo Espinosa's avatar
Arturo Espinosa committed
541
	    ver != eBiffV7 &&
Michael Meeks's avatar
Michael Meeks committed
542
	    ver != eBiffV8) {
543 544 545
		printf ("Unknown BIFF Boundsheet spec. Assuming same as Biff7 FIXME\n");
		ver = eBiffV7;
	}
546 547
	ans->streamStartPos = MS_OLE_GET_GUINT32 (q->data);
	switch (MS_OLE_GET_GUINT8 (q->data + 4)) {
548
	case 0:
549 550
		ans->type = eBiffTWorksheet;
		break;
551
	case 1:
552 553
		ans->type = eBiffTMacrosheet;
		break;
554
	case 2:
555 556
		ans->type = eBiffTChart;
		break;
557
	case 6:
558 559 560
		ans->type = eBiffTVBModule;
		break;
	default:
561
		printf ("Unknown sheet type : %d\n", MS_OLE_GET_GUINT8 (q->data + 4));
562 563 564
		ans->type = eBiffTUnknown;
		break;
	}
565
	switch ((MS_OLE_GET_GUINT8 (q->data + 5)) & 0x3) {
566 567 568 569 570 571 572 573 574 575
	case 00:
		ans->hidden = eBiffHVisible;
		break;
	case 01:
		ans->hidden = eBiffHHidden;
		break;
	case 02:
		ans->hidden = eBiffHVeryHidden;
		break;
	default:
576
		printf ("Unknown sheet hiddenness %d\n", (MS_OLE_GET_GUINT8 (q->data + 4)) & 0x3);
577 578 579
		ans->hidden = eBiffHVisible;
		break;
	}
580
	if (ver == eBiffV8) {
581
		int slen = MS_OLE_GET_GUINT16 (q->data + 6);
582
		ans->name = biff_get_text (q->data + 8, slen, NULL);
583
	} else {
584
		int slen = MS_OLE_GET_GUINT8 (q->data + 6);
585

586
		ans->name = biff_get_text (q->data + 7, slen, NULL);
587
	}
588

589
	/*
590
	 * printf ("Blocksheet : '%s', %d:%d offset %lx\n", ans->name, ans->type, ans->hidden, ans->streamStartPos);
591
	 */
Michael Meeks's avatar
Michael Meeks committed
592
	ans->index = (guint16)g_hash_table_size (wb->boundsheet_data_by_index);
593
	g_hash_table_insert (wb->boundsheet_data_by_index,
Michael Meeks's avatar
Michael Meeks committed
594
			     &ans->index, ans);
595
	g_hash_table_insert (wb->boundsheet_data_by_stream,
Michael Meeks's avatar
Michael Meeks committed
596
			     &ans->streamStartPos, ans);
597

598
	g_assert (ans->streamStartPos == MS_OLE_GET_GUINT32 (q->data));
599 600
	ans->sheet = ms_excel_sheet_new (wb, ans->name);
	ms_excel_workbook_attach (wb, ans->sheet);
601 602
}

603
static gboolean
Michael Meeks's avatar
Michael Meeks committed
604
biff_boundsheet_data_destroy (gpointer key, BiffBoundsheetData *d, gpointer userdata)
605
{
Michael Meeks's avatar
Michael Meeks committed
606 607 608
	g_free (d->name);
	g_free (d);
	return 1;
609 610
}

611 612 613
/**
 * NB. 'fount' is the correct, and original _English_
 **/
614
static void
Michael Meeks's avatar
Michael Meeks committed
615
biff_font_data_new (ExcelWorkbook *wb, BiffQuery *q)
616
{
Michael Meeks's avatar
Michael Meeks committed
617 618
	BiffFontData *fd = g_new (BiffFontData, 1);
	guint16 data;
Jody Goldberg's avatar
Jody Goldberg committed
619
	guint8 data1;
620

621 622
	fd->height = MS_OLE_GET_GUINT16 (q->data + 0);
	data = MS_OLE_GET_GUINT16 (q->data + 2);
623
	fd->italic     = (data & 0x2) == 0x2;
624
	fd->struck_out = (data & 0x8) == 0x8;
625
	fd->color_idx  = MS_OLE_GET_GUINT16 (q->data + 4);
626
	fd->color_idx &= 0x7f; /* Undocumented but a good idea */
627 628
	fd->boldness   = MS_OLE_GET_GUINT16 (q->data + 6);
	data = MS_OLE_GET_GUINT16 (q->data + 8);
Michael Meeks's avatar
Michael Meeks committed
629
	switch (data) {
630 631 632 633 634 635 636 637 638 639 640 641 642
	case 0:
		fd->script = eBiffFSNone;
		break;
	case 1:
		fd->script = eBiffFSSuper;
		break;
	case 2:
		fd->script = eBiffFSSub;
		break;
	default:
		printf ("Unknown script %d\n", data);
		break;
	}
Jody Goldberg's avatar
Jody Goldberg committed
643 644 645

	data1 = MS_OLE_GET_GUINT8 (q->data + 10);
	switch (data1) {
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
	case 0:
		fd->underline = eBiffFUNone;
		break;
	case 1:
		fd->underline = eBiffFUSingle;
		break;
	case 2:
		fd->underline = eBiffFUDouble;
		break;
	case 0x21:
		fd->underline = eBiffFUSingleAcc;
		break;
	case 0x22:
		fd->underline = eBiffFUDoubleAcc;
		break;
	}
662
	fd->fontname = biff_get_text (q->data + 15,
663
				      MS_OLE_GET_GUINT8 (q->data + 14), NULL);
664

665
#ifndef NO_DEBUG_EXCEL
666
	if (ms_excel_read_debug > 1) {
667 668
		printf ("Insert font '%s' size %d pts color %d\n",
			fd->fontname, fd->height / 20, fd->color_idx);
669
	}
670 671 672 673 674
#endif
#ifndef NO_DEBUG_EXCEL
		if (ms_excel_color_debug > 3) {
			printf ("Font color = 0x%x\n", fd->color_idx);
		}
675
#endif
Michael Meeks's avatar
Michael Meeks committed
676
        fd->index = g_hash_table_size (wb->font_data);
677
	if (fd->index >= 4) /* Wierd: for backwards compatibility */
Michael Meeks's avatar
Michael Meeks committed
678 679
		fd->index++;
	g_hash_table_insert (wb->font_data, &fd->index, fd);
680 681
}

682
static gboolean
Michael Meeks's avatar
Michael Meeks committed
683
biff_font_data_destroy (gpointer key, BiffFontData *fd, gpointer userdata)
684
{
Michael Meeks's avatar
Michael Meeks committed
685 686 687
	g_free (fd->fontname);
	g_free (fd);
	return 1;
688 689
}

690
char *excel_builtin_formats[EXCEL_BUILTIN_FORMAT_LEN] = {
691 692 693 694 695
/* 0x00 */	"", /* General */
/* 0x01 */	"0",
/* 0x02 */	"0.00",
/* 0x03 */	"#,##0",
/* 0x04 */	"#,##0.00",
Jody Goldberg's avatar
Jody Goldberg committed
696 697 698 699
/* 0x05 */	"$#,##0_);($#,##0)",
/* 0x06 */	"$#,##0_);[Red]($#,##0)",
/* 0x07 */	"$#,##0.00_);($#,##0.00)",
/* 0x08 */	"$#,##0.00_);[Red]($#,##0.00)",
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
/* 0x09 */	"0%",
/* 0x0a */	"0.00%",
/* 0x0b */	"0.00E+00",
/* 0x0c */	"#",
/* 0x0d */	"#",
/* 0x0e */	"m/d/yy",
/* 0x0f */	"d-mmm-yy",
/* 0x10 */	"d-mmm",
/* 0x11 */	"mmm-yy",
/* 0x12 */	"h:mm",
/* 0x13 */	"h:mm:ss",
/* 0x14 */	"h:mm",
/* 0x15 */	"h:mm:ss",
/* 0x16 */	"m/d/yy",
	0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x17-0x24 reserved for intl versions */
/* 0x25 */	"(#,##0_);(#,##0)",
/* 0x26 */	"(#,##0_);[Red](#,##0)",
/* 0x27 */	"(#,##0.00_);(#,##0.00)",
/* 0x28 */	"(#,##0.00_);[Red](#,##0.00)",
/* 0x29 */	"_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
/* 0x2a */	"_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
/* 0x2b */	"_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
/* 0x2c */	"_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
/* 0x2d */	"mm:ss",
/* 0x2e */	"[h]:mm:ss",
/* 0x2f */	"mm:ss.0",
/* 0x30 */	"##0.0E+0",
/* 0x31 */	"@"
728 729
};

730
/*
Michael Meeks's avatar
Michael Meeks committed
731 732
 * FIXME: This code falsely assumes that the builtin formats are
 * fixed. The builtins get translated to local currency formats. E.g.
733
 * Format data : 0x05 == '"kr"\ #,##0;"kr"\ \-#,##0'
Michael Meeks's avatar
Michael Meeks committed
734
*/
735
StyleFormat *
Michael Meeks's avatar
Michael Meeks committed
736
biff_format_data_lookup (ExcelWorkbook *wb, guint16 idx)
Michael Meeks's avatar
Michael Meeks committed
737
{
738
	char *ans = NULL;
739 740 741 742
	if (idx <= 0x31) {
		ans = excel_builtin_formats[idx];
		if (!ans)
			printf ("Foreign undocumented format\n");
Michael Meeks's avatar
Michael Meeks committed
743
	}
744

745
	if (!ans) {
Michael Meeks's avatar
Michael Meeks committed
746
		BiffFormatData *d = g_hash_table_lookup (wb->format_data,
747 748 749 750 751 752
							   &idx);
		if (!d) {
			printf ("Unknown format: 0x%x\n", idx);
			ans = 0;
		} else
			ans = d->name;
Michael Meeks's avatar
Michael Meeks committed
753
	}
754
	if (ans)
755
		return style_format_new (ans);
756
	else
Michael Meeks's avatar
Michael Meeks committed
757
		return NULL;
Michael Meeks's avatar
Michael Meeks committed
758 759
}

760
static gboolean
Michael Meeks's avatar
Michael Meeks committed
761
biff_format_data_destroy (gpointer key, BiffFormatData *d, gpointer userdata)
Michael Meeks's avatar
Michael Meeks committed
762
{
Michael Meeks's avatar
Michael Meeks committed
763 764 765
	g_free (d->name);
	g_free (d);
	return 1;
Michael Meeks's avatar
Michael Meeks committed
766 767
}

Michael Meeks's avatar
Michael Meeks committed
768
typedef struct {
769
	char const *name;
770
	gboolean    sheet_scope;
771
	gboolean    inserted;
Michael Meeks's avatar
Michael Meeks committed
772 773
	enum { BNDStore, BNDName } type;
	union {
Jody Goldberg's avatar
Jody Goldberg committed
774
		NamedExpression *name;
Michael Meeks's avatar
Michael Meeks committed
775 776 777 778 779
		struct {
			guint8   *data;
			guint16   len;
		} store;
	} v;
Michael Meeks's avatar
Michael Meeks committed
780
} BiffNameData;
Michael Meeks's avatar
Michael Meeks committed
781

782 783
static int externsheet = 0;

784 785 786 787 788
/*
 * We must not try and parse the data until we have
 * read all the sheets in ( for inter-sheet references in names ).
 */
static void
789
biff_name_data_new (ExcelWorkbook *wb, char const *name,
790 791
		    const guint16 sheet_index,
		    const guint8 *formula, const guint16 len,
792 793
		    gboolean const external,
		    gboolean const sheet_scope)
Michael Meeks's avatar
Michael Meeks committed
794
{
Michael Meeks's avatar
Michael Meeks committed
795
	BiffNameData *bnd = g_new (BiffNameData, 1);
796 797 798
	bnd->name        = name;
	bnd->sheet_scope = sheet_scope;
	bnd->type        = BNDStore;
799
	if (formula) {
Michael Meeks's avatar
Michael Meeks committed
800 801 802
		bnd->v.store.data = g_malloc (len);
		memcpy (bnd->v.store.data, formula, len);
		bnd->v.store.len  = len;
803
	} else {
Michael Meeks's avatar
Michael Meeks committed
804 805
		bnd->v.store.data = NULL;
		bnd->v.store.len  = 0;
806
	}
807 808

#ifndef NO_DEBUG_EXCEL
Michael Meeks's avatar
Michael Meeks committed
809
	if (ms_excel_read_debug > 1) {
810
		printf ("%s : %x %x sheet=%d '%s'\n",
811 812
			external ? "EXTERNNAME" : "NAME",
			externsheet,
813
			wb->name_data->len, sheet_index, bnd->name);
Michael Meeks's avatar
Michael Meeks committed
814
	}
815
	if (ms_excel_read_debug > 2)
816
		ms_ole_dump (bnd->v.store.data, bnd->v.store.len);
817
#endif
818
	g_ptr_array_add (wb->name_data, bnd);
Michael Meeks's avatar
Michael Meeks committed
819 820
}

821
ExprTree *
822
biff_name_data_get_name (ExcelSheet *sheet, int idx)
Michael Meeks's avatar
Michael Meeks committed
823
{
824 825 826 827 828 829 830 831
	BiffNameData *bnd;
	GPtrArray    *a;

	g_return_val_if_fail (sheet, NULL);
	g_return_val_if_fail (sheet->wb, NULL);

	a = sheet->wb->name_data;

832 833 834 835 836 837 838
	if (a == NULL || idx < 0 || a->len <= idx ||
	    (bnd = g_ptr_array_index (a, idx)) == NULL) {
		g_warning ("EXCEL : %x (of %x) UNKNOWN name\n", idx, a->len);
		return expr_tree_new_constant(value_new_string("Unknown name"));

	}

839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
	if (bnd->type == BNDStore && bnd->v.store.data) {
		char     *duff = "Some Error";
		ExprTree *tree = ms_excel_parse_formula (sheet->wb, sheet,
							 bnd->v.store.data,
							 0, 0, FALSE,
							 bnd->v.store.len,
							 NULL);

		if (!tree) { /* OK so it's a special 'AddIn' name */
			bnd->type   = BNDName;
			g_free (bnd->v.store.data);
			bnd->v.name = NULL;
		} else {
			bnd->type = BNDName;
			g_free (bnd->v.store.data);
			if (bnd->sheet_scope)
				bnd->v.name = expr_name_add (NULL, sheet->gnum_sheet,
							     bnd->name,
							     tree, &duff);
			else
				bnd->v.name = expr_name_add (sheet->wb->gnum_wb, NULL,
							     bnd->name,
							     tree, &duff);
			if (!bnd->v.name)
				printf ("Error: '%s' on name '%s'\n", duff,
					bnd->name);
#ifndef NO_DEBUG_EXCEL
			else if (ms_excel_read_debug > 1) {
867
				ParsePos ep;
868
				parse_pos_init (&ep, NULL, sheet->gnum_sheet, 0, 0);
869 870 871 872 873 874 875 876 877
				printf ("Parsed name : '%s' = '%s'\n",
					bnd->name, tree
					? expr_decode_tree (tree, &ep)
					: "error");
			}
#endif
		}
	}
	bnd->inserted = TRUE;
878 879 880 881
	if (bnd->type == BNDName && bnd->v.name)
		return expr_tree_new_name (bnd->v.name);
	else
		return expr_tree_new_constant (value_new_string (bnd->name));
Michael Meeks's avatar
Michael Meeks committed
882 883
}

884 885
static void
biff_name_data_destroy (BiffNameData *bnd)
Michael Meeks's avatar
Michael Meeks committed
886
{
887 888 889
	g_return_if_fail (bnd);

	if (bnd->name)
890
		g_free ((char *)bnd->name);
891
	bnd->name    = NULL;
Michael Meeks's avatar
Michael Meeks committed
892 893 894
	if (bnd->type == BNDStore) {
		if (bnd->v.store.data)
			g_free (bnd->v.store.data);
895
	} /* else: bnd->v.name is held in the sheet */
Michael Meeks's avatar
Michael Meeks committed
896
	g_free (bnd);
Michael Meeks's avatar
Michael Meeks committed
897 898
}

899
EXCEL_PALETTE_ENTRY const excel_default_palette[EXCEL_DEF_PAL_LEN] = {
900 901 902
/* These were generated by creating a sheet and
 * modifying the 1st color cell and saving.  This
 * created a custom palette.  I then loaded the sheet
Jody Goldberg's avatar
Jody Goldberg committed
903
 * into gnumeric and dumped the results.
904
 */
Jody Goldberg's avatar
Jody Goldberg committed
905 906
	{  0,  0,  0}, {255,255,255},  {255,  0,  0},  {  0,255,  0},
	{  0,  0,255}, {255,255,  0},  {255,  0,255},  {  0,255,255},
907

Jody Goldberg's avatar
Jody Goldberg committed
908 909
	{128,  0,  0}, {  0,128,  0},  {  0,  0,128},  {128,128,  0},
	{128,  0,128}, {  0,128,128},  {192,192,192},  {128,128,128},
910

Jody Goldberg's avatar
Jody Goldberg committed
911 912
	{153,153,255}, {153, 51,102},  {255,255,204},  {204,255,255},
	{102,  0,102}, {255,128,128},  {  0,102,204},  {204,204,255},
913

Jody Goldberg's avatar
Jody Goldberg committed
914 915
	{  0,  0,128}, {255,  0,255},  {255,255,  0},  {  0,255,255},
	{128,  0,128}, {128,  0,  0},  {  0,128,128},  {  0,  0,255},
916

Jody Goldberg's avatar
Jody Goldberg committed
917 918
	{  0,204,255}, {204,255,255},  {204,255,204},  {255,255,153},
	{153,204,255}, {255,153,204},  {204,153,255},  {255,204,153},
919

Jody Goldberg's avatar
Jody Goldberg committed
920 921 922 923 924
	{ 51,102,255}, { 51,204,204},  {153,204,  0},  {255,204,  0},
	{255,153,  0}, {255,102,  0},  {102,102,153},  {150,150,150},

	{  0, 51,102}, { 51,153,102},  {  0, 51,  0},  { 51, 51,  0},
	{153, 51,  0}, {153, 51,102},  { 51, 51,153},  { 51, 51, 51}
925 926
};

Michael Meeks's avatar
Michael Meeks committed
927
static ExcelPalette *
928 929
ms_excel_default_palette ()
{
Michael Meeks's avatar
Michael Meeks committed
930
	static ExcelPalette *pal = NULL;
931

Jody Goldberg's avatar
Jody Goldberg committed
932
	if (!pal) {
933
		int entries = EXCEL_DEF_PAL_LEN;
934
#ifndef NO_DEBUG_EXCEL
935
		if (ms_excel_color_debug > 3) {
936
			printf ("Creating default palette\n");
937
		}
938
#endif
Michael Meeks's avatar
Michael Meeks committed
939
		pal = (ExcelPalette *) g_malloc (sizeof (ExcelPalette));
940
		pal->length = entries;
941
		pal->red   = g_new (int, entries);
Michael Meeks's avatar
Michael Meeks committed
942
		pal->green = g_new (int, entries);
943
		pal->blue  = g_new (int, entries);
Michael Meeks's avatar
Michael Meeks committed
944
		pal->gnum_cols = g_new (StyleColor *, entries);
945 946

		while (--entries >= 0) {
947 948 949
			pal->red[entries]   = excel_default_palette[entries].r;
			pal->green[entries] = excel_default_palette[entries].g;
			pal->blue[entries]  = excel_default_palette[entries].b;
Michael Meeks's avatar
Michael Meeks committed
950
			pal->gnum_cols[entries] = NULL;
951 952 953 954 955 956
		}
	}

	return pal;
}

Michael Meeks's avatar