ms-excel-read.c 126 KB
Newer Older
1
/* vim: set sw=8: */
2
/**
3 4
 * ms-excel.c: MS Excel support for Gnumeric
 *
5
 * Authors:
Morten Welinder's avatar
Morten Welinder committed
6
 *    Michael Meeks (michael@ximian.com)
Jody Goldberg's avatar
Jody Goldberg committed
7
 *    Jody Goldberg (jody@gnome.org)
8
 *
9
 * (C) 1998-2001 Michael Meeks, Jody Goldberg
10
 * unicode and national language support (C) 2001 by Vlad Harchev <hvv@hippo.ru>
11
 **/
12

13 14
#include <gnumeric-config.h>
#include <gnumeric.h>
15

16
#include "boot.h"
17 18
#include "ms-formula-read.h"
#include "ms-excel-read.h"
19
#include "ms-obj.h"
20
#include "ms-chart.h"
21
#include "ms-escher.h"
22
#include "ms-excel-util.h"
23
#include "ms-excel-xf.h"
Jody Goldberg's avatar
Jody Goldberg committed
24 25 26 27 28 29 30 31 32 33 34

#include <workbook.h>
#include <workbook-view.h>
#include <sheet-style.h>
#include <sheet-merge.h>
#include <cell.h>
#include <style.h>
#include <format.h>
#include <formats.h>
#include <print-info.h>
#include <selection.h>
Jody Goldberg's avatar
Jody Goldberg committed
35
#include <validation.h>
Jody Goldberg's avatar
Jody Goldberg committed
36 37 38 39 40 41 42 43 44 45
#include <parse-util.h>	/* for cell_name */
#include <ranges.h>
#include <expr-name.h>
#include <value.h>
#include <gutils.h>
#include <application.h>
#include <io-context.h>
#include <sheet-object-cell-comment.h>
#include <sheet-object-widget.h>
#include <sheet-object-graphic.h>
Jody Goldberg's avatar
new.  
Jody Goldberg committed
46
#include <sheet-object-image.h>
47
#ifdef ENABLE_BONOBO
Jody Goldberg's avatar
Jody Goldberg committed
48
#  include <gnumeric-graph.h>
49
#endif
50

Jody Goldberg's avatar
Jody Goldberg committed
51 52 53
#include <libgnome/gnome-i18n.h>
#include <locale.h>

54 55
#define N_BYTES_BETWEEN_PROGRESS_UPDATES   0x1000

56 57 58 59 60 61 62
/* #define NO_DEBUG_EXCEL */
#ifndef NO_DEBUG_EXCEL
#define d(level, code)	do { if (ms_excel_read_debug > level) { code } } while (0)
#else
#define d(level, code)
#endif

63 64
static excel_iconv_t current_workbook_iconv = NULL;

65
/* Forward references */
66
static ExcelSheet *ms_excel_sheet_new (ExcelWorkbook *wb, char const *name);
67

68
void
69 70
ms_excel_unexpected_biff (BiffQuery *q, char const *state,
			  int debug_level)
71
{
72
#ifndef NO_DEBUG_EXCEL
73
	if (debug_level > 0) {
74
		printf ("Unexpected Opcode in %s: 0x%x, length 0x%x\n",
75
			state, q->opcode, q->length);
76
		if (debug_level > 2)
77
			ms_ole_dump (q->data, q->length);
78
	}
79 80 81 82
#endif
}


83 84 85 86
/**
 * Generic 16 bit int index pointer functions.
 **/
static guint
Jody Goldberg's avatar
Jody Goldberg committed
87
biff_guint16_hash (guint16 const *d)
88
{
89
	return *d * 2;
90 91
}

92
static guint
Jody Goldberg's avatar
Jody Goldberg committed
93
biff_guint32_hash (guint32 const *d)
94
{
95
	return *d * 2;
96
}
97 98

static gint
Jody Goldberg's avatar
Jody Goldberg committed
99
biff_guint16_equal (guint16 const *a, guint16 const *b)
100
{
101 102
	if (*a == *b)
		return 1;
Michael Meeks's avatar
Michael Meeks committed
103
	return 0;
104 105
}
static gint
Jody Goldberg's avatar
Jody Goldberg committed
106
biff_guint32_equal (guint32 const *a, guint32 const *b)
107
{
108 109
	if (*a == *b)
		return 1;
Michael Meeks's avatar
Michael Meeks committed
110
	return 0;
111 112
}

113 114 115 116 117
/**
 * This returns whether there is a header byte
 * and sets various flags from it
 **/
static gboolean
Jody Goldberg's avatar
Jody Goldberg committed
118
biff_string_get_flags (guint8 const *ptr,
119 120 121 122
		       gboolean *word_chars,
		       gboolean *extended,
		       gboolean *rich)
{
Michael Meeks's avatar
Michael Meeks committed
123
	guint8 header;
124

125
	header = MS_OLE_GET_GUINT8 (ptr);
126
	/* I assume that this header is backwards compatible with raw ASCII */
127 128 129

	/* Its a proper Unicode header grbit byte */
	if (((header & 0xf2) == 0)) {
Michael Meeks's avatar
Michael Meeks committed
130 131 132 133
		*word_chars = (header & 0x1) != 0;
		*extended   = (header & 0x4) != 0;
		*rich       = (header & 0x8) != 0;
		return TRUE;
134
	} else { /* Some assumptions: FIXME? */
Michael Meeks's avatar
Michael Meeks committed
135 136 137 138
		*word_chars = 0;
		*extended   = 0;
		*rich       = 0;
		return FALSE;
139 140 141
	}
}

142
static void
Jody Goldberg's avatar
Jody Goldberg committed
143
get_xtn_lens (guint32 *pre_len, guint32 *end_len, guint8 const *ptr, gboolean ext_str, gboolean rich_str)
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
{
	*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:"
170
				"ignoring %u bytes\n", len_ext_rst);
171 172 173 174
		warned = TRUE;
	}
}

175
static char *
176
get_chars (char const *ptr, guint length, gboolean high_byte)
177 178
{
	char* ans;
179
	guint32 lp;
180 181 182

	if (high_byte) {
		wchar_t* wc = g_new (wchar_t, length + 2);
Jody Goldberg's avatar
Jody Goldberg committed
183
		size_t retlength;
184
		ans = g_new (char, (length + 2) * 8);
185

186 187
		for (lp = 0; lp < length; lp++) {
			guint16 c = MS_OLE_GET_GUINT16 (ptr);
188
			ptr += 2;
189
			wc[lp] = c;
190
		}
191

192
		retlength = excel_wcstombs (ans, wc, length);
193
		g_free (wc);
194 195
		if (retlength == (size_t)-1)
			retlength = 0;
196
		ans[retlength] = 0;
197 198
		ans = g_realloc (ans, retlength + 2);
	} else {
199
		size_t inbytes = length,
200
			outbytes = (length + 2) * 8,
201
			retlength;
202
		char* inbuf = g_new (char, length), *outbufptr;
203
		char const * inbufptr = inbuf;
204

205 206 207
		ans = g_new (char, outbytes + 1);
		outbufptr = ans;
		for (lp = 0; lp < length; lp++) {
208
			inbuf[lp] = MS_OLE_GET_GUINT8 (ptr);
209 210
			ptr++;
		}
211 212
		excel_iconv (current_workbook_iconv,
			     &inbufptr, &inbytes, &outbufptr, &outbytes);
213

214 215
		retlength = outbufptr-ans;
		ans[retlength] = 0;
216
		ans = g_realloc (ans, retlength + 1);
217 218
		g_free (inbuf);
	}
219 220 221
	return ans;
}

222
/**
223 224
 * This function takes a length argument as Biff V7 has a byte length
 * (seemingly).
225 226
 * it returns the length in bytes of the string in byte_length
 * or nothing if this is NULL.
227
 * FIXME: see S59D47.HTM for full description
228
 **/
229
char *
230
biff_get_text (guint8 const *pos, guint32 length, guint32 *byte_length)
231
{
232
	char *ans;
Jody Goldberg's avatar
Jody Goldberg committed
233
	guint8 const *ptr;
Michael Meeks's avatar
Michael Meeks committed
234 235 236 237 238
	guint32 byte_len;
	gboolean header;
	gboolean high_byte;
	gboolean ext_str;
	gboolean rich_str;
239

240
	if (!byte_length)
Michael Meeks's avatar
Michael Meeks committed
241 242
		byte_length = &byte_len;
	*byte_length = 0;
243

Jody Goldberg's avatar
Jody Goldberg committed
244
	if (!length) {
245
		/* FIXME FIXME FIXME: What about the 1 byte for the header?
246 247
		 *                     The length may be wrong in this case.
		 */
Michael Meeks's avatar
Michael Meeks committed
248
		return 0;
249
	}
250

251
	d (5, {
252 253
		printf ("String:\n");
		ms_ole_dump (pos, length + 1);
254
	});
255

256 257 258
	header = biff_string_get_flags (pos,
					&high_byte,
					&ext_str,
Michael Meeks's avatar
Michael Meeks committed
259
					&rich_str);
260
	if (header) {
Michael Meeks's avatar
Michael Meeks committed
261 262 263 264
		ptr = pos + 1;
		(*byte_length)++;
	} else
		ptr = pos;
265

266 267
	{
		guint32 pre_len, end_len;
Michael Meeks's avatar
Michael Meeks committed
268

269 270 271
		get_xtn_lens (&pre_len, &end_len, ptr, ext_str, rich_str);
		ptr += pre_len;
		(*byte_length) += pre_len + end_len;
272
	}
Michael Meeks's avatar
Michael Meeks committed
273

274

275
	d (4, {
276
		printf ("String len %d, byte length %d: %d %d %d:\n",
Michael Meeks's avatar
Michael Meeks committed
277
			length, (*byte_length), high_byte, rich_str, ext_str);
278
		ms_ole_dump (pos, *byte_length);
279 280
	});

281

282 283
	if (!length) {
		ans = g_new (char, 2);
284
		g_warning ("Warning unterminated string floating");
285
	} else {
286
		(*byte_length) += (high_byte ? 2 : 1)*length;
Jody Goldberg's avatar
Jody Goldberg committed
287
		ans = get_chars ((char *) ptr, length, high_byte);
288
	}
289
	return ans;
290 291
}

292 293 294 295 296 297

static guint32
sst_bound_check (BiffQuery *q, guint32 offset)
{
	if (offset >= q->length) {
		guint32 d = offset - q->length;
298
		guint16 opcode;
299

300 301 302
		if (!ms_biff_query_peek_next (q, &opcode) ||
		    opcode != BIFF_CONTINUE)
			return 0;
303

304 305
		if (!ms_biff_query_next (q))
			return 0;
306 307

		return d;
308 309 310 311 312 313 314 315 316 317
	} 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
318
get_string (char **output, BiffQuery *q, guint32 offset, MsBiffVersion ver)
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
{
	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);
345

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
		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 */
362
		chars_left = (q->length - new_offset - pre_len) / (high_byte ? 2 : 1);
363 364
		if (chars_left > total_len)
			get_len = total_len;
365
		else
366 367 368 369 370
			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 */
Jody Goldberg's avatar
Jody Goldberg committed
371
		str = get_chars ((char *)(q->data + new_offset + pre_len), get_len, high_byte);
372
		new_offset += pre_len + get_len * (high_byte ? 2 : 1);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

		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
389
read_sst (BiffQuery *q, ExcelWorkbook *wb, MsBiffVersion ver)
390 391
{
	guint32 offset;
Jody Goldberg's avatar
Jody Goldberg committed
392
	unsigned k;
393

394
	d (4, {
395 396
		printf ("SST\n");
		ms_ole_dump (q->data, q->length);
397 398
	});

399 400 401 402 403 404
	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++) {
405
		offset = get_string (&wb->global_strings[k], q, offset, ver);
406

407
		if (!wb->global_strings[k]) {
408
			d (4, printf ("Blank string in table at 0x%x.\n", k););
409
		}
410
#ifndef NO_DEBUG_EXCEL
411 412 413 414 415 416
		else if (ms_excel_read_debug > 4)
			puts (wb->global_strings[k]);
#endif
	}
}

417
char const *
Jody Goldberg's avatar
Jody Goldberg committed
418
biff_get_error_text (guint8 const err)
419
{
420
	char const *buf;
Jody Goldberg's avatar
Jody Goldberg committed
421
	switch (err) {
Michael Meeks's avatar
Michael Meeks committed
422
	case 0:  buf = gnumeric_err_NULL;  break;
423
	case 7:  buf = gnumeric_err_DIV0;  break;
Michael Meeks's avatar
Michael Meeks committed
424 425 426 427 428
	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;
429
	default:
Michael Meeks's avatar
Michael Meeks committed
430
		buf = _("#UNKNOWN!"); break;
431
	}
Michael Meeks's avatar
Michael Meeks committed
432
	return buf;
433 434
}

435 436 437
/**
 * See S59D5D.HTM
 **/
438
MsBiffBofData *
439
ms_biff_bof_data_new (BiffQuery *q)
440
{
441
	MsBiffBofData *ans = g_new (MsBiffBofData, 1);
442

443
	if ((q->opcode & 0xff) == BIFF_BOF &&
Michael Meeks's avatar
Michael Meeks committed
444
	    (q->length >= 4)) {
445 446 447
		/*
		 * Determine type from boff
		 */
448
		switch (q->opcode >> 8) {
449
		case 0: ans->version = MS_BIFF_V2;
450
			break;
451
		case 2: ans->version = MS_BIFF_V3;
452
			break;
453
		case 4: ans->version = MS_BIFF_V4;
454
			break;
455 456
		case 8: /* More complicated */
		{
457
			d (2, {
458 459 460
				printf ("Complicated BIFF version 0x%x\n",
					MS_OLE_GET_GUINT16 (q->data));
				ms_ole_dump (q->data, q->length);
461 462
			});

463 464 465
			switch (MS_OLE_GET_GUINT16 (q->data)) {
			case 0x0600: ans->version = MS_BIFF_V8;
				     break;
466
			case 0x500: /* * OR ebiff7: FIXME ? !  */
467 468 469 470 471
				     ans->version = MS_BIFF_V7;
				     break;
			default:
				printf ("Unknown BIFF sub-number in BOF %x\n", q->opcode);
				ans->version = MS_BIFF_V_UNKNOWN;
472 473
			}
			break;
474 475
		}

476 477
		default:
			printf ("Unknown BIFF number in BOF %x\n", q->opcode);
478
			ans->version = MS_BIFF_V_UNKNOWN;
Arturo Espinosa's avatar
Arturo Espinosa committed
479
			printf ("Biff version %d\n", ans->version);
480
		}
481
		switch (MS_OLE_GET_GUINT16 (q->data + 2)) {
482 483 484 485 486 487
		case 0x0005: ans->type = MS_BIFF_TYPE_Workbook; break;
		case 0x0006: ans->type = MS_BIFF_TYPE_VBModule; break;
		case 0x0010: ans->type = MS_BIFF_TYPE_Worksheet; break;
		case 0x0020: ans->type = MS_BIFF_TYPE_Chart; break;
		case 0x0040: ans->type = MS_BIFF_TYPE_Macrosheet; break;
		case 0x0100: ans->type = MS_BIFF_TYPE_Workspace; break;
488
		default:
489
			ans->type = MS_BIFF_TYPE_Unknown;
490
			printf ("Unknown BIFF type in BOF %x\n", MS_OLE_GET_GUINT16 (q->data + 2));
491 492
			break;
		}
493 494 495
		/* Now store in the directory array: */
		d (2, printf ("BOF %x, %d == %d, %d\n", q->opcode, q->length,
			      ans->version, ans->type););
496 497
	} else {
		printf ("Not a BOF !\n");
498 499
		ans->version = MS_BIFF_V_UNKNOWN;
		ans->type = MS_BIFF_TYPE_Unknown;
500
	}
501

502
	return ans;
503 504
}

Michael Meeks's avatar
Michael Meeks committed
505
void
506
ms_biff_bof_data_destroy (MsBiffBofData *data)
507
{
508
	g_free (data);
509 510
}

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
static void
ms_excel_workbook_attach (ExcelWorkbook *wb, ExcelSheet *ans)
{
	g_return_if_fail (wb);
	g_return_if_fail (ans);

	workbook_sheet_attach (wb->gnum_wb, ans->gnum_sheet, NULL);
	g_ptr_array_add (wb->excel_sheets, ans);
}

static gboolean
ms_excel_workbook_detach (ExcelWorkbook *wb, ExcelSheet *ans)
{
	unsigned idx = 0;

	if (ans->gnum_sheet) {
		if (!workbook_sheet_detach (wb->gnum_wb, ans->gnum_sheet))
			return FALSE;
		/* Detaching the sheet deletes it */
		ans->gnum_sheet = NULL;
	}
	for (idx = 0; idx < wb->excel_sheets->len; idx++)
		if (g_ptr_array_index (wb->excel_sheets, idx) == ans) {
			g_ptr_array_index (wb->excel_sheets, idx) = NULL;
			return TRUE;
		}

	printf ("Sheet not in list of sheets !\n");
	return FALSE;
}

542 543 544
/**
 * See S59D61.HTM
 **/
545
static void
546
biff_boundsheet_data_new (BiffQuery *q, ExcelWorkbook *wb, MsBiffVersion ver)
547
{
548
	BiffBoundsheetData *ans;
549
	const char *default_name = "Unknown%d";
550

551 552
	/* Testing seems to indicate that Biff5 is compatibile with Biff7 here. */
	if (ver != MS_BIFF_V5 && ver != MS_BIFF_V7 && ver != MS_BIFF_V8) {
553
		printf ("Unknown BIFF Boundsheet spec. Assuming same as Biff7 FIXME\n");
554
		ver = MS_BIFF_V7;
555
	}
556 557

	ans = g_new (BiffBoundsheetData, 1);
558
	ans->streamStartPos = MS_OLE_GET_GUINT32 (q->data);
559 560 561

	g_return_if_fail (ans->streamStartPos == MS_OLE_GET_GUINT32 (q->data));

562
	switch (MS_OLE_GET_GUINT8 (q->data + 4)) {
563
	case 0: ans->type = MS_BIFF_TYPE_Worksheet;
564
		default_name = _("Sheet%d");
565
		break;
566
	case 1: ans->type = MS_BIFF_TYPE_Macrosheet;
567
		default_name = _("Macro%d");
568
		break;
569
	case 2: ans->type = MS_BIFF_TYPE_Chart;
570
		default_name = _("Chart%d");
571
		break;
572
	case 6: ans->type = MS_BIFF_TYPE_VBModule;
573
		default_name = _("Module%d");
574 575
		break;
	default:
576
		printf ("Unknown boundsheet type: %d\n", MS_OLE_GET_GUINT8 (q->data + 4));
577
		ans->type = MS_BIFF_TYPE_Unknown;
578
	}
579
	switch ((MS_OLE_GET_GUINT8 (q->data + 5)) & 0x3) {
580
	case 0: ans->hidden = MS_BIFF_H_VISIBLE;
581
		break;
582
	case 1: ans->hidden = MS_BIFF_H_HIDDEN;
583
		break;
584
	case 2: ans->hidden = MS_BIFF_H_VERY_HIDDEN;
585 586
		break;
	default:
587
		printf ("Unknown sheet hiddenness %d\n", (MS_OLE_GET_GUINT8 (q->data + 4)) & 0x3);
588
		ans->hidden = MS_BIFF_H_VISIBLE;
589
	}
590

591
	/* TODO: find some documentation on this.
592 593 594 595 596
	 * Sample data and OpenCalc imply that the docs are incorrect.  It
	 * seems like the name lenght is 1 byte.  Loading sample sheets in
	 * other locales universally seem to treat the first byte as a length
	 * and the second as the unicode flag header.
	 */
597
	ans->name = biff_get_text (q->data + 7,
598
		MS_OLE_GET_GUINT8 (q->data + 6), NULL);
599

600 601
	/* TODO: find some documentation on this.
	 * It appears that if the name is null it defaults to Sheet%d?
Jody Goldberg's avatar
Jody Goldberg committed
602 603
	 * However, we have only one test case and no docs.
	 */
604 605
	if (ans->name == NULL)
		ans->name = g_strdup_printf (default_name,
Jody Goldberg's avatar
Jody Goldberg committed
606 607
			g_hash_table_size (wb->boundsheet_data_by_index));

Jody Goldberg's avatar
Jody Goldberg committed
608
	d (1, printf ("Boundsheet: '%s', %d:%d\n", ans->name, ans->type,
609 610
		       ans->hidden););

Michael Meeks's avatar
Michael Meeks committed
611
	ans->index = (guint16)g_hash_table_size (wb->boundsheet_data_by_index);
612 613
	g_hash_table_insert (wb->boundsheet_data_by_index,  &ans->index, ans);
	g_hash_table_insert (wb->boundsheet_data_by_stream, &ans->streamStartPos, ans);
614

615 616 617 618 619 620 621
	/* AARRRGGGG : This is useless XL calls chart tabs 'worksheet' too */
	/* if (ans->type == MS_BIFF_TYPE_Worksheet) */

	/* FIXME : Use this kruft instead */
	if (ans->hidden == MS_BIFF_H_VISIBLE) {
		ans->sheet = ms_excel_sheet_new (wb, ans->name);
		ms_excel_workbook_attach (wb, ans->sheet);
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
622 623
	} else
		ans->sheet = NULL;
624 625
}

626
static gboolean
Michael Meeks's avatar
Michael Meeks committed
627
biff_boundsheet_data_destroy (gpointer key, BiffBoundsheetData *d, gpointer userdata)
628
{
Michael Meeks's avatar
Michael Meeks committed
629 630 631
	g_free (d->name);
	g_free (d);
	return 1;
632 633
}

634 635 636
/**
 * NB. 'fount' is the correct, and original _English_
 **/
637
static void
638
biff_font_data_new (BiffQuery *q, ExcelWorkbook *wb)
639
{
Michael Meeks's avatar
Michael Meeks committed
640 641
	BiffFontData *fd = g_new (BiffFontData, 1);
	guint16 data;
Jody Goldberg's avatar
Jody Goldberg committed
642
	guint8 data1;
643

644 645
	fd->height = MS_OLE_GET_GUINT16 (q->data + 0);
	data = MS_OLE_GET_GUINT16 (q->data + 2);
646
	fd->italic     = (data & 0x2) == 0x2;
647
	fd->struck_out = (data & 0x8) == 0x8;
648
	fd->color_idx  = MS_OLE_GET_GUINT16 (q->data + 4);
649
	fd->color_idx &= 0x7f; /* Undocumented but a good idea */
650 651
	fd->boldness   = MS_OLE_GET_GUINT16 (q->data + 6);
	data = MS_OLE_GET_GUINT16 (q->data + 8);
Michael Meeks's avatar
Michael Meeks committed
652
	switch (data) {
653
	case 0:
654
		fd->script = MS_BIFF_F_S_NONE;
655 656
		break;
	case 1:
657
		fd->script = MS_BIFF_F_S_SUPER;
658 659
		break;
	case 2:
660
		fd->script = MS_BIFF_F_S_SUB;
661 662 663 664 665
		break;
	default:
		printf ("Unknown script %d\n", data);
		break;
	}
Jody Goldberg's avatar
Jody Goldberg committed
666 667 668

	data1 = MS_OLE_GET_GUINT8 (q->data + 10);
	switch (data1) {
669
	case 0:
670
		fd->underline = MS_BIFF_F_U_NONE;
671 672
		break;
	case 1:
673
		fd->underline = MS_BIFF_F_U_SINGLE;
674 675
		break;
	case 2:
676
		fd->underline = MS_BIFF_F_U_DOUBLE;
677 678
		break;
	case 0x21:
679
		fd->underline = MS_BIFF_F_U_SINGLE_ACC;
680 681
		break;
	case 0x22:
682
		fd->underline = MS_BIFF_F_U_DOUBLE_ACC;
683 684
		break;
	}
685
	fd->fontname = biff_get_text (q->data + 15,
686
				      MS_OLE_GET_GUINT8 (q->data + 14), NULL);
687

688 689 690 691
	d (1, printf ("Insert font '%s' size %d pts color %d\n",
		      fd->fontname, fd->height / 20, fd->color_idx););
	d (3, printf ("Font color = 0x%x\n", fd->color_idx););

Michael Meeks's avatar
Michael Meeks committed
692
        fd->index = g_hash_table_size (wb->font_data);
693
	if (fd->index >= 4) /* Wierd: for backwards compatibility */
Michael Meeks's avatar
Michael Meeks committed
694 695
		fd->index++;
	g_hash_table_insert (wb->font_data, &fd->index, fd);
696 697
}

698
static gboolean
Michael Meeks's avatar
Michael Meeks committed
699
biff_font_data_destroy (gpointer key, BiffFontData *fd, gpointer userdata)
700
{
Michael Meeks's avatar
Michael Meeks committed
701 702 703
	g_free (fd->fontname);
	g_free (fd);
	return 1;
704 705
}

Jody Goldberg's avatar
const.  
Jody Goldberg committed
706
char const *excel_builtin_formats[EXCEL_BUILTIN_FORMAT_LEN] = {
Jody Goldberg's avatar
Jody Goldberg committed
707
/* 0x00 */	"General",
708 709 710 711
/* 0x01 */	"0",
/* 0x02 */	"0.00",
/* 0x03 */	"#,##0",
/* 0x04 */	"#,##0.00",
Jody Goldberg's avatar
Jody Goldberg committed
712 713 714 715
/* 0x05 */	"$#,##0_);($#,##0)",
/* 0x06 */	"$#,##0_);[Red]($#,##0)",
/* 0x07 */	"$#,##0.00_);($#,##0.00)",
/* 0x08 */	"$#,##0.00_);[Red]($#,##0.00)",
716 717 718
/* 0x09 */	"0%",
/* 0x0a */	"0.00%",
/* 0x0b */	"0.00E+00",
Jody Goldberg's avatar
Jody Goldberg committed
719
/* 0x0c */	"# ?/?",
720
/* 0x0d */	"# ?" "?/?" "?",  /* Don't accidentally use trigraph.  */
721 722 723 724
/* 0x0e		"m/d/yy" */ NULL,	/* locale specific, set in */
/* 0x0f		"d-mmm-yy", */ NULL,	/* ms_excel_read_init */
/* 0x10		"d-mmm", */ NULL,
/* 0x11 */	"mmm-yy",
Jody Goldberg's avatar
Jody Goldberg committed
725 726
/* 0x12 */	"h:mm AM/PM",
/* 0x13 */	"h:mm:ss AM/PM",
727 728
/* 0x14 */	"h:mm",
/* 0x15 */	"h:mm:ss",
729
/* 0x16		"m/d/yy h:mm", */ NULL,
730
	0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x17-0x24 reserved for intl versions */
Jody Goldberg's avatar
Jody Goldberg committed
731 732 733 734
/* 0x25 */	"#,##0_);(#,##0)",
/* 0x26 */	"#,##0_);[Red](#,##0)",
/* 0x27 */	"#,##0.00_);(#,##0.00)",
/* 0x28 */	"#,##0.00_);[Red](#,##0.00)",
735 736 737 738 739 740 741 742 743
/* 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 */	"@"
744 745
};

746 747
static StyleFormat *
ms_excel_wb_get_fmt (ExcelWorkbook *wb, guint16 idx)
Michael Meeks's avatar
Michael Meeks committed
748
{
Jody Goldberg's avatar
const.  
Jody Goldberg committed
749 750 751
	char const *ans = NULL;
	BiffFormatData const *d = g_hash_table_lookup (wb->format_data, &idx);

752 753 754
	if (d)
		ans = d->name;
	else if (idx <= 0x31) {
755 756 757
		ans = excel_builtin_formats[idx];
		if (!ans)
			printf ("Foreign undocumented format\n");
758 759
	} else
		printf ("Unknown format: 0x%x\n", idx);
760

761
	if (ans)
762
		return style_format_new_XL (ans, FALSE);
763
	else
Michael Meeks's avatar
Michael Meeks committed
764
		return NULL;
Michael Meeks's avatar
Michael Meeks committed
765 766
}

767
static gboolean
Michael Meeks's avatar
Michael Meeks committed
768
biff_format_data_destroy (gpointer key, BiffFormatData *d, gpointer userdata)
Michael Meeks's avatar
Michael Meeks committed
769
{
Michael Meeks's avatar
Michael Meeks committed
770 771 772
	g_free (d->name);
	g_free (d);
	return 1;
Michael Meeks's avatar
Michael Meeks committed
773 774
}

Michael Meeks's avatar
Michael Meeks committed
775
typedef struct {
776
	char const *name;
777
	int  sheet_index;	/* -1 indicates workbook level */
Michael Meeks's avatar
Michael Meeks committed
778 779
	enum { BNDStore, BNDName } type;
	union {
Jody Goldberg's avatar
Jody Goldberg committed
780
		NamedExpression *name;
Michael Meeks's avatar
Michael Meeks committed
781 782 783 784 785
		struct {
			guint8   *data;
			guint16   len;
		} store;
	} v;
Michael Meeks's avatar
Michael Meeks committed
786
} BiffNameData;
Michael Meeks's avatar
Michael Meeks committed
787

788 789
static int externsheet = 0;

790 791
/*
 * We must not try and parse the data until we have
792
 * read all the sheets in (for inter-sheet references in names).
793 794
 */
static void
795
biff_name_data_new (ExcelWorkbook *wb, char const *name,
796 797 798
		    int sheet_index,
		    guint8 const *formula, guint16 len,
		    gboolean external)
Michael Meeks's avatar
Michael Meeks committed
799
{
Michael Meeks's avatar
Michael Meeks committed
800
	BiffNameData *bnd = g_new (BiffNameData, 1);
801
	bnd->name        = name;
802
	bnd->sheet_index = sheet_index;
803
	bnd->type        = BNDStore;
804

805
	if (formula) {
Michael Meeks's avatar
Michael Meeks committed
806 807 808
		bnd->v.store.data = g_malloc (len);
		memcpy (bnd->v.store.data, formula, len);
		bnd->v.store.len  = len;
809
	} else {
Michael Meeks's avatar
Michael Meeks committed
810 811
		bnd->v.store.data = NULL;
		bnd->v.store.len  = 0;
812
	}