1 /* vm: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  * excel-xml-read.c : Read MS Excel 2003 SpreadsheetML
5  *
6  * Copyright (C) 2003-2008 Jody Goldberg (jody@gnome.org)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) version 3.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
21  * USA
22  */
23 #include <gnumeric-config.h>
24 #include <gnumeric.h>
25 #include <xml-io-version.h>
26 #include <sheet-view.h>
27 #include <sheet-style.h>
28 #include <sheet-merge.h>
29 #include <sheet-filter.h>
30 #include <sheet.h>
31 #include <ranges.h>
32 #include <style.h>
33 #include <style-border.h>
34 #include <style-color.h>
35 #include <gnm-format.h>
36 #include <cell.h>
37 #include <position.h>
38 #include <expr.h>
39 #include <expr-name.h>
40 #include <validation.h>
41 #include <value.h>
42 #include <selection.h>
43 #include <command-context.h>
44 #include <workbook-view.h>
45 #include <workbook.h>
46 #include <gutils.h>
47 #include <goffice/goffice.h>
48 
49 #include <gsf/gsf-libxml.h>
50 #include <gsf/gsf-input.h>
51 #include <gsf/gsf-utils.h>
52 #include <gmodule.h>
53 #include <glib/gi18n-lib.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <errno.h>
57 
58 /*****************************************************************************/
59 
60 /* A fake value of the right type, different from all the real enum values.  */
61 #define VALUE_FAKE_DATETIME ((GnmValueType)42)
62 
63 typedef struct {
64 	GnumericXMLVersion version;
65 	GOIOContext	*context;	/* The IOcontext managing things */
66 	WorkbookView	*wb_view;	/* View for the new workbook */
67 	Workbook	*wb;		/* The new workbook */
68 	Sheet		*sheet;		/* The current sheet */
69 	GnmCellPos	 pos;
70 	int              merge_across;
71 	GnmValueType	 val_type;
72 	GnmExprTop const*texpr;
73 	GnmRange	 array_range;
74 	char		*style_name;
75 	GnmStyle	*style;
76 	GnmStyle	*def_style;
77 	GHashTable	*style_hash;
78 	GsfDocMetaData	*metadata;	/* Document Properties */
79 } ExcelXMLReadState;
80 
81 enum {
82 	XL_NS_SS,
83 	XL_NS_O,
84 	XL_NS_XL,
85 	XL_NS_XSI,
86 	XL_NS_C,
87 	XL_NS_HTML
88 };
89 
90 /****************************************************************************/
91 
92 static gboolean xl_xml_warning (GsfXMLIn *xin, char const *fmt, ...)
93 	G_GNUC_PRINTF (2, 3);
94 
95 static gboolean
xl_xml_warning(GsfXMLIn * xin,char const * fmt,...)96 xl_xml_warning (GsfXMLIn *xin, char const *fmt, ...)
97 {
98 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
99 	char *msg;
100 	va_list args;
101 
102 	va_start (args, fmt);
103 	msg = g_strdup_vprintf (fmt, args);
104 	va_end (args);
105 
106 	if (IS_SHEET (state->sheet)) {
107 		char *tmp;
108 		if (state->pos.col >= 0 && state->pos.row >= 0)
109 			tmp = g_strdup_printf ("%s!%s : %s",
110 				state->sheet->name_quoted,
111 				cellpos_as_string (&state->pos), msg);
112 		else
113 			tmp = g_strdup_printf ("%s : %s",
114 				state->sheet->name_quoted, msg);
115 		g_free (msg);
116 		msg = tmp;
117 	}
118 
119 	go_io_warning (state->context, "%s", msg);
120 	g_warning ("%s", msg);
121 	g_free (msg);
122 
123 	return FALSE; /* convenience */
124 }
125 static void
unknown_attr(GsfXMLIn * xin,xmlChar const * const * attrs,char const * name)126 unknown_attr (GsfXMLIn *xin,
127 	      xmlChar const * const *attrs, char const *name)
128 {
129 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
130 
131 	g_return_if_fail (attrs != NULL);
132 
133 	if (state->version == GNM_XML_LATEST)
134 		go_io_warning (state->context,
135 			_("Unexpected attribute %s::%s == '%s'."),
136 			name, attrs[0], attrs[1]);
137 }
138 
139 typedef struct {
140 	char const * const name;
141 	int val;
142 } EnumVal;
143 
144 static gboolean
attr_enum(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,EnumVal const * enums,int * res)145 attr_enum (GsfXMLIn *xin, xmlChar const * const *attrs,
146 	   int ns_id, char const *name, EnumVal const *enums, int *res)
147 {
148 	g_return_val_if_fail (attrs != NULL, FALSE);
149 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
150 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
151 
152 	if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
153 		return FALSE;
154 
155 	for (; enums->name != NULL ; enums++)
156 		if (!strcmp (enums->name, attrs[1])) {
157 			*res = enums->val;
158 			return TRUE;
159 		}
160 	return xl_xml_warning (xin, "Invalid attribute '%s', unknown enum value '%s'",
161 			       name, attrs[1]);
162 }
163 
164 static gboolean
attr_bool(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,gboolean * res)165 attr_bool (GsfXMLIn *xin, xmlChar const * const *attrs,
166 	   int ns_id, char const *name, gboolean *res)
167 {
168 	g_return_val_if_fail (attrs != NULL, FALSE);
169 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
170 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
171 
172 	if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
173 		return FALSE;
174 	*res = g_ascii_strcasecmp ((gchar *)attrs[1], "false") && strcmp (attrs[1], "0");
175 
176 	return TRUE;
177 }
178 
179 static gboolean
attr_int(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,int * res)180 attr_int (GsfXMLIn *xin, xmlChar const * const *attrs,
181 	  int ns_id, char const *name, int *res)
182 {
183 	char *end;
184 	int tmp;
185 
186 	g_return_val_if_fail (attrs != NULL, FALSE);
187 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
188 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
189 
190 	if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
191 		return FALSE;
192 
193 	errno = 0;
194 	tmp = strtol ((gchar *)attrs[1], &end, 10);
195 	if (errno == ERANGE)
196 		return xl_xml_warning (xin, "Invalid attribute '%s', integer '%s' is out of range",
197 				       name, attrs[1]);
198 	if (*end)
199 		return xl_xml_warning (xin, "Invalid attribute '%s', expected integer, received '%s'",
200 				       name, attrs[1]);
201 
202 	*res = tmp;
203 	return TRUE;
204 }
205 
206 static gboolean
attr_float(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,gnm_float * res)207 attr_float (GsfXMLIn *xin, xmlChar const * const *attrs,
208 	    int ns_id, char const *name, gnm_float *res)
209 {
210 	char *end;
211 	double tmp;
212 
213 	g_return_val_if_fail (attrs != NULL, FALSE);
214 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
215 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
216 
217 	if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
218 		return FALSE;
219 
220 	tmp = gnm_strto ((gchar *)attrs[1], &end);
221 	if (*end)
222 		return xl_xml_warning (xin, "Invalid attribute '%s', expected number, received '%s'",
223 				       name, attrs[1]);
224 	*res = tmp;
225 	return TRUE;
226 }
227 
228 static GnmColor *
parse_color(GsfXMLIn * xin,xmlChar const * str,char const * name)229 parse_color (GsfXMLIn *xin, xmlChar const *str, char const *name)
230 {
231 	guint r, g, b;
232 
233 	g_return_val_if_fail (str != NULL, NULL);
234 
235 	if (3 == sscanf (str, "#%2x%2x%2x", &r, &g, &b))
236 		return gnm_color_new_rgb8 (r, g, b);
237 
238 	xl_xml_warning (xin, "Invalid attribute '%s', expected color, received '%s'",
239 			name, str);
240 	return NULL;
241 }
242 
243 static GnmColor *
attr_color(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name)244 attr_color (GsfXMLIn *xin, xmlChar const * const *attrs,
245 	    int ns_id, char const *name)
246 {
247 	g_return_val_if_fail (attrs != NULL, NULL);
248 	g_return_val_if_fail (attrs[0] != NULL, NULL);
249 
250 	if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
251 		return NULL;
252 	return parse_color (xin, attrs[1], name);
253 }
254 
255 static GnmExprTop const *
xl_xml_parse_expr(GsfXMLIn * xin,xmlChar const * expr_str,GnmParsePos const * pp)256 xl_xml_parse_expr (GsfXMLIn *xin, xmlChar const *expr_str,
257 		   GnmParsePos const *pp)
258 {
259 	GnmExprTop const *texpr;
260 	GnmParseError err;
261 	if (*expr_str != '=') {
262 		xl_xml_warning (xin, "Invalid formula '%s' does not begin with '='", expr_str);
263 		return NULL;
264 	}
265 	/* Odd, some time IF and CHOOSE show up with leading spaces ??
266 	 * = IF(....
267 	 * = CHOOSE(...
268 	 * I wonder if it is related to some of the funky old
269 	 * optimizations in * xls ? */
270 	while (' ' == *(++expr_str))
271 		;
272 	texpr = gnm_expr_parse_str (expr_str, pp,
273 		GNM_EXPR_PARSE_DEFAULT, gnm_conventions_xls_r1c1,
274 		parse_error_init (&err));
275 	if (NULL == texpr)
276 		xl_xml_warning (xin, "'%s' %s", expr_str, err.err->message);
277 	parse_error_free (&err);
278 
279 	return texpr;
280 }
281 
282 static void
xl_xml_doc_prop_start(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)283 xl_xml_doc_prop_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
284 {
285 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
286 	state->metadata = gsf_doc_meta_data_new ();
287 }
288 
289 static void
xl_xml_doc_prop_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)290 xl_xml_doc_prop_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
291 {
292 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
293 	go_doc_set_meta_data (GO_DOC (state->wb), state->metadata);
294 	g_object_unref (state->metadata);
295 	state->metadata = NULL;
296 }
297 
298 static void
xl_xml_read_prop_type(GsfXMLIn * xin,GType g_type)299 xl_xml_read_prop_type (GsfXMLIn *xin, GType g_type)
300 {
301 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
302 	GValue *res = g_new0 (GValue, 1);
303 	if (gsf_xml_gvalue_from_str (res, g_type, xin->content->str))
304 		gsf_doc_meta_data_insert
305 			(state->metadata,
306 			 g_strdup (xin->node->user_data.v_str), res);
307 	else
308 		 g_free (res);
309 }
310 
311 static void
xl_xml_read_prop(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)312 xl_xml_read_prop (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
313 {
314         xl_xml_read_prop_type (xin, G_TYPE_STRING);
315 }
316 
317 static void
xl_xml_read_prop_dt(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)318 xl_xml_read_prop_dt (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
319 {
320         xl_xml_read_prop_type (xin, GSF_TIMESTAMP_TYPE);
321 }
322 
323 static void
xl_xml_read_keywords(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)324 xl_xml_read_keywords (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
325 {
326 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
327 	gchar **strs, **orig_strs;
328 	GsfDocPropVector *keywords;
329 	GValue v = G_VALUE_INIT;
330 	int count = 0;
331 
332 	if (strlen (xin->content->str) == 0)
333 		return;
334 
335 	orig_strs = strs = g_strsplit (xin->content->str, " ", 0);
336 	keywords = gsf_docprop_vector_new ();
337 
338 	while (strs != NULL && *strs != NULL && strlen (*strs) > 0) {
339 		g_value_init (&v, G_TYPE_STRING);
340 		g_value_set_string (&v, *strs);
341 		gsf_docprop_vector_append (keywords, &v);
342 		g_value_unset (&v);
343 		count ++;
344 		strs++;
345 	}
346 	g_strfreev(orig_strs);
347 
348 	if (count > 0) {
349 		GValue *val = g_new0 (GValue, 1);
350 		g_value_init (val, GSF_DOCPROP_VECTOR_TYPE);
351 		g_value_set_object (val, keywords);
352 		gsf_doc_meta_data_insert (state->metadata,
353 					  g_strdup (xin->node->user_data.v_str), val);
354 	}
355 	g_object_unref (keywords);
356 }
357 
358 static void
xl_xml_table_start(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)359 xl_xml_table_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
360 {
361 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
362 	state->pos.col = 0;
363 }
364 
365 static void
xl_xml_col_start(GsfXMLIn * xin,xmlChar const ** attrs)366 xl_xml_col_start (GsfXMLIn *xin, xmlChar const **attrs)
367 {
368 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
369 	int tmp, span = 1;
370 	gboolean  auto_fit = TRUE, hidden = FALSE;
371 	gnm_float width = -1;
372 	GnmStyle *style = NULL;
373 
374 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
375 		if (attr_int (xin, attrs, XL_NS_SS, "Index", &tmp)) {
376 			if (tmp > 0)
377 				state->pos.col = tmp - 1;
378 		} else if (attr_int (xin, attrs, XL_NS_SS, "Span", &tmp)) {
379 			/* NOTE : span is odd.  It seems to apply as col+span
380 			 * rather than col+span-1 that is used for rows which
381 			 * is the more logical (to me) arrangement) */
382 			if (tmp > 0)
383 				span = tmp + 1;
384 		} else if (attr_bool (xin, attrs, XL_NS_SS, "AutoFitWidth", &auto_fit))
385 			;
386 		else if (attr_bool (xin, attrs, XL_NS_SS, "Hidden", &hidden))
387 			;
388 		else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "StyleID"))
389 			style = g_hash_table_lookup (state->style_hash, attrs[1]);
390 		else if (attr_float (xin, attrs, XL_NS_SS, "Width", &width))
391 			;
392 		else
393 			unknown_attr (xin, attrs, "Column");
394 
395 	if (NULL != style) {
396 		GnmRange r;
397 		r.start.col = state->pos.col;
398 		r.end.col   = state->pos.col + span - 1;
399 		r.start.row = 0;
400 		r.end.row  = gnm_sheet_get_max_rows (state->sheet) - 1;
401 		gnm_style_ref (style);
402 		sheet_style_set_range (state->sheet, &r, style);
403 	}
404 	if (width > 0.)
405 		for (tmp = 0 ; tmp < span ; tmp++)
406 			sheet_col_set_size_pts (state->sheet,
407 				state->pos.col + tmp, width, !auto_fit);
408 	if (hidden)
409 		colrow_set_visibility (state->sheet, TRUE, FALSE,
410 			state->pos.col, state->pos.col+span-1);
411 
412 	state->pos.col += span;
413 }
414 
415 static void
xl_xml_row_start(GsfXMLIn * xin,xmlChar const ** attrs)416 xl_xml_row_start (GsfXMLIn *xin, xmlChar const **attrs)
417 {
418 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
419 	int tmp, span = 1;
420 	gboolean  auto_fit = TRUE, hidden = FALSE;
421 	gnm_float height = -1;
422 	GnmStyle *style = NULL;
423 
424 	state->pos.col = 0;
425 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
426 		if (attr_int (xin, attrs, XL_NS_SS, "Index", &tmp)) {
427 			if (tmp > 0)
428 				state->pos.row = tmp - 1;
429 		} else if (attr_int (xin, attrs, XL_NS_SS, "Span", &tmp)) {
430 			if (tmp > 0)
431 				span = tmp;
432 		} else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "StyleID"))
433 			style = g_hash_table_lookup (state->style_hash, attrs[1]);
434 		else if (attr_bool (xin, attrs, XL_NS_SS, "AutoFitHeight", &auto_fit))
435 			;
436 		else if (attr_bool (xin, attrs, XL_NS_SS, "Hidden", &hidden))
437 			;
438 		else if (attr_float (xin, attrs, XL_NS_SS, "Height", &height))
439 			;
440 		else
441 			unknown_attr (xin, attrs, "Row");
442 
443 	if (height >= 0.)
444 		for (tmp = 0 ; tmp < span ; tmp++)
445 			sheet_row_set_size_pts (state->sheet, state->pos.row+tmp, height, !auto_fit);
446 	if (hidden)
447 		colrow_set_visibility (state->sheet, FALSE, FALSE,
448 			state->pos.row, state->pos.row+span-1);
449 
450 	if (NULL != style) {
451 		GnmRange r;
452 		r.start.row = state->pos.row;
453 		r.end.row   = state->pos.row + span - 1;
454 		r.start.col = 0;
455 		r.end.col  = gnm_sheet_get_max_cols (state->sheet) - 1;
456 		gnm_style_ref (style);
457 		sheet_style_set_range (state->sheet, &r, style);
458 	}
459 }
460 static void
xl_xml_row_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)461 xl_xml_row_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
462 {
463 	((ExcelXMLReadState *)xin->user_state)->pos.row++;
464 }
465 static void
xl_xml_cell_start(GsfXMLIn * xin,xmlChar const ** attrs)466 xl_xml_cell_start (GsfXMLIn *xin, xmlChar const **attrs)
467 {
468 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
469 	GnmStyle *style = NULL;
470 	int across = 0, down = 0, tmp;
471 	GnmParsePos pp;
472 
473 	parse_pos_init (&pp, NULL, state->sheet,
474 		state->pos.col, state->pos.row);
475 	state->array_range.start.col = -1; /* poison it */
476 	state->val_type = VALUE_STRING;
477 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
478 		if (attr_int (xin, attrs, XL_NS_SS, "Index", &tmp)) {
479 			if (tmp > 0)
480 				state->pos.col = tmp -1;
481 		} else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Formula")) {
482 			GnmExprTop const *texpr = xl_xml_parse_expr (xin, attrs[1], &pp);
483 			if (NULL != texpr) {
484 				if (NULL != state->texpr)
485 					gnm_expr_top_unref (state->texpr);
486 				state->texpr = texpr;
487 			}
488 		} else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "ArrayRange")) {
489 			GnmRangeRef rr;
490 			xmlChar const *end = rangeref_parse (&rr, attrs[1], &pp, gnm_conventions_xls_r1c1);
491 			if (end != attrs[1] && *end == '\0')
492 				range_init_rangeref (&state->array_range, &rr);
493 		} else if (attr_int (xin, attrs, XL_NS_SS, "MergeAcross", &across))
494 			   ;
495 		else if (attr_int (xin, attrs, XL_NS_SS, "MergeDown", &down))
496 			;
497 		else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "StyleID"))
498 			style = g_hash_table_lookup (state->style_hash, attrs[1]);
499 		else
500 			unknown_attr (xin, attrs, "Cell");
501 
502 	if (NULL != style) {
503 		gnm_style_ref (style);
504 		if (across > 0 || down > 0) {
505 			GnmRange r;
506 			r.start = r.end = state->pos;
507 			r.end.col += across;
508 			r.end.row += down;
509 			gnm_sheet_merge_add (state->sheet, &r, FALSE,
510 				GO_CMD_CONTEXT (state->context));
511 			sheet_style_set_range (state->sheet, &r, style);
512 		} else
513 			sheet_style_set_pos (state->sheet,
514 				state->pos.col, state->pos.row, style);
515 	}
516 	state->merge_across = across;
517 }
518 static void
xl_xml_cell_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)519 xl_xml_cell_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
520 {
521 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
522 	state->pos.col += (1 + state->merge_across);
523 }
524 static void
xl_xml_data_start(GsfXMLIn * xin,xmlChar const ** attrs)525 xl_xml_data_start (GsfXMLIn *xin, xmlChar const **attrs)
526 {
527 	static EnumVal const val_types[] = {
528 		{ "String",	VALUE_STRING },
529 		{ "Number",	VALUE_FLOAT },
530 		{ "Boolean",	VALUE_BOOLEAN },
531 		{ "Error",	VALUE_ERROR },
532 		{ "DateTime",	VALUE_FAKE_DATETIME },
533 		{ NULL, 0 }
534 	};
535 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
536 	int type;
537 
538 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
539 		if (attr_enum (xin, attrs, XL_NS_SS, "Type", val_types, &type))
540 			state->val_type = type;
541 		else
542 			unknown_attr (xin, attrs, "CellData");
543 }
544 
545 static void
xl_xml_data_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)546 xl_xml_data_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
547 {
548 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
549 	GnmCell *cell = sheet_cell_fetch (state->sheet, state->pos.col, state->pos.row);
550 	GnmValue *v;
551 
552 	if (state->val_type == VALUE_FAKE_DATETIME) {
553 		GDate date;
554 		unsigned y, mo, d, h, mi;
555 		double s;
556 		if (6 == sscanf (xin->content->str, "%u-%u-%uT%u:%u:%lg", &y, &mo, &d, &h, &mi, &s)) {
557 			g_date_clear (&date, 1);
558 			g_date_set_dmy (&date, d, mo, y);
559 			if (g_date_valid (&date)) {
560 				unsigned d_serial = go_date_g_to_serial (&date,
561 					workbook_date_conv (state->wb));
562 				v = value_new_float (d_serial + h/24. + mi/(24.*60.) + s/(24.*60.*60.));
563 			} else
564 				v = value_new_string (xin->content->str);
565 		} else
566 			v = value_new_string (xin->content->str);
567 	} else if (state->val_type == VALUE_FLOAT) {
568 			char *end;
569 			v  = value_new_float (gnm_strto (xin->content->str, &end));
570 			if (*end)
571 				xl_xml_warning
572 					(xin, _("Invalid content of ss:data "
573 						"element, expected number, "
574 						"received '%s'"),
575 					 xin->content->str);
576 	} else
577 		v = value_new_from_string (state->val_type, xin->content->str,
578 					   NULL, FALSE);
579 	if (NULL != state->texpr) {
580 		if (NULL != v)
581 			gnm_cell_set_expr_and_value (cell, state->texpr, v, TRUE);
582 		else
583 			gnm_cell_set_expr (cell, state->texpr);
584 		gnm_expr_top_unref (state->texpr);
585 		state->texpr = NULL;
586 	} else if (NULL != v)
587 		gnm_cell_set_value (cell, v);
588 	else {
589 		gnm_cell_set_text (cell, xin->content->str);
590 		xl_xml_warning
591 			(xin, _("Invalid content of ss:data "
592 				"element, received '%s'"),
593 			 xin->content->str);
594 	}
595 }
596 
597 static void
xl_xml_font(GsfXMLIn * xin,xmlChar const ** attrs)598 xl_xml_font (GsfXMLIn *xin, xmlChar const **attrs)
599 {
600 	static EnumVal const underlines[] = {
601 		{ "None",		UNDERLINE_NONE },
602 		{ "Single",		UNDERLINE_SINGLE },
603 		{ "SingleAccounting",	UNDERLINE_SINGLE_LOW },
604 		{ "Double",		UNDERLINE_DOUBLE },
605 		{ "DoubleAccounting",	UNDERLINE_DOUBLE_LOW },
606 		{ NULL, 0 }
607 	};
608 	static EnumVal const scripts[] = {
609 		{ "Superscript",	GO_FONT_SCRIPT_SUPER },
610 		{ "Subscript",		GO_FONT_SCRIPT_SUB },
611 		{ "None",		GO_FONT_SCRIPT_STANDARD },
612 		{ NULL, 0 }
613 	};
614 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
615 	GnmColor *color;
616 	gboolean b_tmp;
617 	int i_tmp;
618 	gnm_float tmp;
619 
620 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
621 		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Family"))
622 			;
623 		else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "FontName"))
624 			;
625 		else if (attr_float (xin, attrs, XL_NS_SS, "Size", &tmp))
626 			gnm_style_set_font_size	(state->style, tmp);
627 		else if (attr_bool (xin, attrs, XL_NS_SS, "Bold", &b_tmp))
628 			gnm_style_set_font_bold (state->style, b_tmp);
629 		else if (attr_bool (xin, attrs, XL_NS_SS, "Italic", &b_tmp))
630 			gnm_style_set_font_italic (state->style, b_tmp);
631 		else if (attr_bool (xin, attrs, XL_NS_SS, "StrikeThrough", &b_tmp))
632 			gnm_style_set_font_strike (state->style, b_tmp);
633 		else if (attr_enum (xin, attrs, XL_NS_SS, "Underline", underlines, &i_tmp))
634 			gnm_style_set_font_uline (state->style, i_tmp);
635 		else if (attr_enum (xin, attrs, XL_NS_SS, "VerticalAlign", scripts, &i_tmp))
636 			gnm_style_set_font_script (state->style, i_tmp);
637 		else if ((color = attr_color (xin, attrs, XL_NS_SS, "Color")))
638 			gnm_style_set_font_color (state->style, color);
639 		else
640 			unknown_attr (xin, attrs, "Style::Font");
641 }
642 
643 static void
xl_xml_alignment(GsfXMLIn * xin,xmlChar const ** attrs)644 xl_xml_alignment (GsfXMLIn *xin, xmlChar const **attrs)
645 {
646 	static EnumVal const valignments [] = {
647 		{ "Bottom", GNM_VALIGN_BOTTOM },
648 		{ "Center", GNM_VALIGN_CENTER },
649 		{ "Distributed", GNM_VALIGN_DISTRIBUTED },
650 		{ "Justify", GNM_VALIGN_JUSTIFY },
651 		{ "Top", GNM_VALIGN_TOP },
652 		{ NULL, 0 }
653 	};
654 	static EnumVal const halignments [] = {
655 		{ "Center", GNM_HALIGN_CENTER },
656 		{ "CenterAcrossSelection", GNM_HALIGN_CENTER_ACROSS_SELECTION },
657 		{ "Distributed", GNM_HALIGN_DISTRIBUTED },
658 		{ "Fill", GNM_HALIGN_FILL },
659 		{ "Justify", GNM_HALIGN_JUSTIFY },
660 		{ "Left", GNM_HALIGN_LEFT },
661 		{ "Right", GNM_HALIGN_RIGHT },
662 
663 		{ NULL, 0 }
664 	};
665 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
666 	gboolean b_tmp;
667 	int i_tmp;
668 
669 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
670 		if (attr_int (xin, attrs, XL_NS_SS, "Rotate", &i_tmp))
671 			gnm_style_set_rotation (state->style, i_tmp);
672 		else if (attr_bool (xin, attrs, XL_NS_SS, "WrapText", &b_tmp))
673 			gnm_style_set_wrap_text (state->style, b_tmp);
674 		else if (attr_enum (xin, attrs, XL_NS_SS, "Vertical", valignments, &i_tmp))
675 			gnm_style_set_align_v (state->style, i_tmp);
676 		else if (attr_enum (xin, attrs, XL_NS_SS, "Horizontal", halignments, &i_tmp))
677 			gnm_style_set_align_h (state->style, i_tmp);
678 		else if (attr_int (xin, attrs, XL_NS_SS, "Indent",  &i_tmp))
679 			gnm_style_set_indent (state->style, i_tmp);
680 }
681 
682 static void
xl_xml_border(GsfXMLIn * xin,xmlChar const ** attrs)683 xl_xml_border (GsfXMLIn *xin, xmlChar const **attrs)
684 {
685 	static EnumVal const sides[] = {
686 		{ "Top",		GNM_STYLE_BORDER_TOP },
687 		{ "Bottom",		GNM_STYLE_BORDER_BOTTOM },
688 		{ "Right",		GNM_STYLE_BORDER_RIGHT },
689 		{ "Left",		GNM_STYLE_BORDER_LEFT },
690 		{ "DiagonalLeft",	GNM_STYLE_BORDER_REV_DIAG },
691 		{ "DiagonalRight",	GNM_STYLE_BORDER_DIAG },
692 		{ NULL, 0 }
693 	};
694 	static EnumVal const line_styles[] = {
695 		{ "Continuous",		GNM_STYLE_BORDER_HAIR },		/* 1 2 3 */
696 		{ "Dash",		GNM_STYLE_BORDER_DASHED },		/* 1 2 */
697 		{ "DashDot",		GNM_STYLE_BORDER_DASH_DOT },	/* 1 2 */
698 		{ "DashDotDot",		GNM_STYLE_BORDER_DASH_DOT_DOT },	/* 1 2 */
699 		{ "Dot",		GNM_STYLE_BORDER_DOTTED },		/* 1 */
700 		{ "Double",		GNM_STYLE_BORDER_DOUBLE },		/* 3 */
701 		{ "SlantDashDot",	GNM_STYLE_BORDER_SLANTED_DASH_DOT },/* 2 */
702 		{ NULL, 0 }
703 	};
704 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
705 	GnmStyleBorderLocation location  = GNM_STYLE_BORDER_EDGE_MAX;
706 	GnmStyleBorderType	    line_type = GNM_STYLE_BORDER_MAX;
707 	GnmBorder	   *border;
708 	GnmColor	   *color = NULL, *new_color;
709 	int		   weight = 1, tmp;
710 
711 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
712 		if (attr_enum (xin, attrs, XL_NS_SS, "Position", sides, &tmp))
713 			location = tmp;
714 		else if (attr_enum (xin, attrs, XL_NS_SS, "LineStyle", line_styles, &tmp))
715 			line_type = tmp;
716 		else if (attr_int (xin, attrs, XL_NS_SS, "Weight", &weight))
717 			;
718 		else if ((new_color = attr_color (xin, attrs, XL_NS_SS, "Color"))) {
719 			style_color_unref (color);
720 			color = new_color;
721 		} else
722 			unknown_attr (xin, attrs, "Style::Border");
723 
724 	switch (line_type) {
725 	default:
726 		break;
727 	case GNM_STYLE_BORDER_HAIR:
728 		if (weight == 2)
729 			line_type = GNM_STYLE_BORDER_THIN;
730 		else if (weight >= 3)
731 			line_type = GNM_STYLE_BORDER_THICK;
732 		break;
733 	case GNM_STYLE_BORDER_DASHED:
734 		if (weight >= 2)
735 			line_type = GNM_STYLE_BORDER_MEDIUM_DASH;
736 		break;
737 	case GNM_STYLE_BORDER_DASH_DOT:
738 		if (weight >= 2)
739 			line_type = GNM_STYLE_BORDER_MEDIUM_DASH_DOT;
740 		break;
741 	case GNM_STYLE_BORDER_DASH_DOT_DOT:
742 		if (weight >= 2)
743 			line_type = GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT;
744 		break;
745 	}
746 
747 	if (color != NULL &&
748 	    location  != GNM_STYLE_BORDER_EDGE_MAX &&
749 	    line_type != GNM_STYLE_BORDER_MAX) {
750 		border = gnm_style_border_fetch (line_type,
751 			color, gnm_style_border_get_orientation (location));
752 		gnm_style_set_border (state->style,
753 				      GNM_STYLE_BORDER_LOCATION_TO_STYLE_ELEMENT (location),
754 				      border);
755 	} else if (color)
756 		    style_color_unref (color);
757 }
758 
759 static void
xl_xml_num_interior(GsfXMLIn * xin,xmlChar const ** attrs)760 xl_xml_num_interior (GsfXMLIn *xin, xmlChar const **attrs)
761 {
762 	static EnumVal const patterns[] = {
763 		{ "Solid",	1 },
764 		{ "Gray75",	2 },
765 		{ "Gray50",	3 },
766 		{ "Gray25",	4 },
767 		{ "Gray125",	5 },
768 		{ "Gray0625",	6 },
769 		{ "HorzStripe", 7 },
770 		{ "VertStripe", 8 },
771 		{ "ReverseDiagStripe", 9 },
772 		{ "DiagStripe", 10 },
773 		{ "DiagCross",	11 },
774 		{ "ThickDiagCross", 12 },
775 		{ "ThinHorzStripe", 13 },
776 		{ "ThinVertStripe", 14 },
777 		{ "ThinReverseDiagStripe", 15 },
778 		{ "ThinDiagStripe", 16 },
779 		{ "ThinHorzCross",  17 },
780 		{ "ThinDiagCross",  18 },
781 		{ NULL, 0 }
782 	};
783 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
784 	GnmColor *color;
785 	int tmp;
786 
787 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
788 		if ((color = attr_color (xin, attrs, XL_NS_SS, "Color")))
789 			gnm_style_set_back_color (state->style, color);
790 		else if (attr_enum (xin, attrs, XL_NS_SS, "Pattern", patterns, &tmp))
791 			gnm_style_set_pattern (state->style, tmp);
792 		else if ((color = attr_color (xin, attrs, XL_NS_SS, "PatternColor")))
793 			gnm_style_set_pattern_color (state->style, color);
794 		else
795 			unknown_attr (xin, attrs, "Style::Interior");
796 }
797 
798 static void
xl_xml_num_fmt(GsfXMLIn * xin,xmlChar const ** attrs)799 xl_xml_num_fmt (GsfXMLIn *xin, xmlChar const **attrs)
800 {
801 	static struct {
802 		char const *name;
803 		GOFormatMagic id;
804 	} named_magic_formats [] = {
805 		{ "General Date",        GO_FORMAT_MAGIC_SHORT_DATETIME },
806 		{ "Long Date",           GO_FORMAT_MAGIC_LONG_DATE },
807 		{ "Medium Date",         GO_FORMAT_MAGIC_MEDIUM_DATE },
808 		{ "Short Date",          GO_FORMAT_MAGIC_SHORT_DATE },
809 		{ "Long Time",           GO_FORMAT_MAGIC_LONG_TIME },
810 		{ "Medium Time",         GO_FORMAT_MAGIC_MEDIUM_TIME },
811 		{ "Short Time",          GO_FORMAT_MAGIC_SHORT_TIME },
812 		{ NULL, 0 }
813 	};
814 	static struct {
815 		char const *name;
816 		char const *format;
817 	} named_formats [] = {
818 		{ "General Number",     "General" },
819 		{ "Currency",       	"$#,##0.00_);[Red](#,##0.00)" },
820 		{ "Euro Currency",     	"[$EUR-2]#,##0.00_);[Red](#,##0.00)" },
821 		{ "Fixed",              "0.00" },
822 		{ "Standard",           "#,##0.00" },	/* number, 2dig, +sep */
823 		{ "Percent",            "0.00%" },	/* std percent */
824 		{ "Scientific",         "0.00E+00" },	/* std scientific */
825 		{ "Yes/No",		"\"Yes\";\"Yes\";\"No\"" },
826 		{ "True/False",		"\"True\";\"True\";\"False\"" },
827 		{ "On/Off",		"\"On\";\"On\";\"Off\"" },
828 		{ NULL, NULL }
829 	};
830 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
831 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
832 		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Format")) {
833 			GOFormat *fmt = NULL;
834 			int i;
835 
836 			for (i = 0 ; named_formats[i].name ; i++)
837 				if (0 == strcmp (attrs[1], named_formats[i].name))
838 					fmt = go_format_new_from_XL (named_formats[i].format);
839 
840 			if (NULL == fmt)
841 				for (i = 0 ; named_magic_formats[i].name ; i++)
842 					if (0 == strcmp (attrs[1], named_magic_formats[i].name))
843 						fmt = go_format_new_magic (named_magic_formats[i].id);
844 
845 			if (NULL == fmt)
846 				fmt = go_format_new_from_XL (attrs[1]);
847 			gnm_style_set_format (state->style, fmt);
848 			go_format_unref (fmt);
849 		} else
850 			unknown_attr (xin, attrs, "Style::NumberFormat");
851 }
852 
853 static void
xl_xml_style_start(GsfXMLIn * xin,xmlChar const ** attrs)854 xl_xml_style_start (GsfXMLIn *xin, xmlChar const **attrs)
855 {
856 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
857 	char const *id = NULL;
858 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
859 		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "ID"))
860 			id = attrs[1];
861 		else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Name"))
862 			; /* does anything use this ? */
863 		else
864 			unknown_attr (xin, attrs, "Style");
865 
866 	if (id == NULL)
867 		return;
868 
869 	g_return_if_fail (state->style == NULL);
870 
871 	state->style = (state->def_style != NULL)
872 		? gnm_style_dup (state->def_style)
873 		: gnm_style_new_default ();
874 	if (!strcmp (id, "Default"))
875 		state->def_style = state->style;
876 	g_hash_table_replace (state->style_hash, g_strdup (id), state->style);
877 }
878 
879 static void
xl_xml_style_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)880 xl_xml_style_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
881 {
882 	((ExcelXMLReadState *)xin->user_state)->style = NULL;
883 }
884 
885 static void
xl_xml_named_range(GsfXMLIn * xin,xmlChar const ** attrs)886 xl_xml_named_range (GsfXMLIn *xin, xmlChar const **attrs)
887 {
888 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
889 	char const *name = NULL;
890 	char const *expr_str = NULL;
891 
892 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
893 		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Name"))
894 			name = attrs[1];
895 		else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "RefersTo"))
896 			expr_str = attrs[1];
897 
898 	if (NULL != name && NULL != expr_str) {
899 		GnmParsePos pp;
900 		GnmExprTop const *texpr = xl_xml_parse_expr (xin, expr_str,
901 			parse_pos_init (&pp, state->wb, NULL, 0, 0));
902 		g_warning ("%s = %s", name, expr_str);
903 		if (NULL != texpr)
904 			expr_name_add (&pp, name, texpr, NULL, TRUE, NULL);
905 	}
906 }
907 
908 static void
xl_xml_sheet_start(GsfXMLIn * xin,xmlChar const ** attrs)909 xl_xml_sheet_start (GsfXMLIn *xin, xmlChar const **attrs)
910 {
911 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
912 	char const *name = NULL;
913 
914 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
915 		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Name"))
916 			name = attrs[1];
917 		else
918 			unknown_attr (xin, attrs, "Worksheet");
919 
920 	if (name != NULL){
921 		g_return_if_fail (state->sheet == NULL);
922 		state->sheet =  workbook_sheet_by_name (state->wb, name);
923 		if (state->sheet == NULL) {
924 		  state->sheet = sheet_new (state->wb, name,
925 					    16384, 1048576);  /* FIXME */
926 			workbook_sheet_attach (state->wb, state->sheet);
927 		}
928 
929 		/* Flag a respan here in case nothing else does */
930 		sheet_flag_recompute_spans (state->sheet);
931 		state->pos.col = state->pos.row = 0;
932 	}
933 }
934 
935 static void
xl_xml_sheet_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)936 xl_xml_sheet_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
937 {
938 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
939 
940 	g_return_if_fail (state->sheet != NULL);
941 
942 	state->sheet = NULL;
943 }
944 
945 static void
xl_xml_pane(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)946 xl_xml_pane (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
947 {
948 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
949 	state->pos.col = 0;
950 	state->pos.row = 0;
951 }
952 static void
xl_xml_editpos_row(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)953 xl_xml_editpos_row (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
954 {
955 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
956 	char *end;
957 	int tmp;
958 	errno = 0;
959 	tmp = strtol (xin->content->str, &end, 10);
960 	if (errno != ERANGE && *end == '\0')
961 		state->pos.row = tmp;
962 }
963 static void
xl_xml_editpos_col(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)964 xl_xml_editpos_col (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
965 {
966 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
967 	char *end;
968 	int tmp;
969 	errno = 0;
970 	tmp = strtol (xin->content->str, &end, 10);
971 	if (errno != ERANGE && *end == '\0')
972 		state->pos.col = tmp;
973 }
974 static void
xl_xml_selection(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)975 xl_xml_selection (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
976 {
977 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
978 	SheetView *sv = sheet_get_view (state->sheet, state->wb_view);
979 	char const *ptr, *end;
980 	GnmParsePos pp;
981 	GnmRangeRef rr;
982 	GnmRange    r;
983 
984 	g_return_if_fail (sv != NULL);
985 
986 	parse_pos_init_sheet (&pp, state->sheet);
987 	sv_selection_reset (sv);
988 	for (ptr = xin->content->str; ptr && *ptr ; ) {
989 		end = rangeref_parse (&rr, ptr, &pp, gnm_conventions_xls_r1c1);
990 		if (end != ptr) {
991 			range_init_rangeref (&r, &rr);
992 			sv_selection_add_full
993 				(sv,
994 				 state->pos.col, state->pos.row,
995 				 r.start.col, r.start.row,
996 				 r.end.col, r.end.row,
997 				 GNM_SELECTION_MODE_ADD);
998 
999 			if (*end != ',')
1000 				break;
1001 			ptr = end + 1;
1002 		} else
1003 			break;
1004 	}
1005 }
1006 
1007 static void
xl_xml_auto_filter_start(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)1008 xl_xml_auto_filter_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
1009 {
1010 	ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
1011 	GnmFilter *filter;
1012 	GnmParsePos pp;
1013 	GnmRangeRef rr;
1014 	GnmRange r;
1015 	char const *end, *range = NULL;
1016 
1017 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1018 		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_XL, "Range"))
1019 			range = attrs[1];
1020 		else
1021 			unknown_attr (xin, attrs, "AutoFilter");
1022 
1023 	if (range)
1024 	{
1025 		parse_pos_init_sheet (&pp, state->sheet);
1026 		end = rangeref_parse (&rr, range, &pp, gnm_conventions_xls_r1c1);
1027 		if (end != range)
1028 		{
1029 			range_init_rangeref (&r, &rr);
1030 			filter = gnm_filter_new (state->sheet, &r, TRUE);
1031 			gnm_filter_reapply (filter);
1032 		}
1033 	}
1034 }
1035 
1036 /****************************************************************************/
1037 
1038 static GsfXMLInNS content_ns[] = {
1039 	GSF_XML_IN_NS (XL_NS_SS,   "urn:schemas-microsoft-com:office:spreadsheet"),
1040 	GSF_XML_IN_NS (XL_NS_SS,   "http://schemas.microsoft.com/office/excel/2003/xml"),
1041 	GSF_XML_IN_NS (XL_NS_O,    "urn:schemas-microsoft-com:office:office"),
1042 	GSF_XML_IN_NS (XL_NS_XL,   "urn:schemas-microsoft-com:office:excel"),
1043 	GSF_XML_IN_NS (XL_NS_C,    "urn:schemas-microsoft-com:office:component:spreadsheet"),
1044 	GSF_XML_IN_NS (XL_NS_HTML, "http://www.w3.org/TR/REC-html40"),
1045 	GSF_XML_IN_NS (XL_NS_XSI,  "http://www.w3.org/2001/XMLSchema-instance"),
1046 
1047 	{ NULL, 0 }
1048 };
1049 
1050 static GsfXMLInNode const excel_xml_dtd[] = {
1051 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
1052 GSF_XML_IN_NODE_FULL (START, WORKBOOK, XL_NS_SS, "Workbook", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
1053   GSF_XML_IN_NODE (WORKBOOK, DOC_PROP, XL_NS_O, "DocumentProperties", GSF_XML_NO_CONTENT, &xl_xml_doc_prop_start, &xl_xml_doc_prop_end),
1054     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_AUTHOR,         XL_NS_O, "Author", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_INITIAL_CREATOR),
1055     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_CATEGORY,       XL_NS_O, "Category", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_CATEGORY),
1056     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_CEATED,         XL_NS_O, "Created", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop_dt, .v_str = GSF_META_NAME_DATE_CREATED),
1057     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_COMPANY,        XL_NS_O, "Company", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_COMPANY),
1058     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_DESCRIPTION,    XL_NS_O, "Description", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_DESCRIPTION),
1059     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_HYPERLINK_BASE, XL_NS_O, "HyperlinkBase", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = "xlsx:HyperlinkBase"),
1060     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_KEYWORDS,       XL_NS_O, "Keywords", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_keywords, .v_str = GSF_META_NAME_KEYWORDS),
1061 
1062     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_LAST_AUTHOR,    XL_NS_O, "LastAuthor", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_CREATOR),
1063     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_LAST_PRINTED,   XL_NS_O, "LastPrinted", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop_dt, .v_str = GSF_META_NAME_PRINT_DATE),
1064     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_LAST_SAVED,     XL_NS_O, "LastSaved", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop_dt, .v_str = GSF_META_NAME_DATE_MODIFIED),
1065     GSF_XML_IN_NODE (DOC_PROP, PROP_LINES,               XL_NS_O, "Lines", GSF_XML_CONTENT, NULL, NULL),
1066     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_MANAGER,        XL_NS_O, "Manager", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_MANAGER),
1067     GSF_XML_IN_NODE (DOC_PROP, PROP_REVISION,            XL_NS_O, "Revision", GSF_XML_CONTENT, NULL, NULL),
1068     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_SUBJECT,        XL_NS_O, "Subject", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_SUBJECT),
1069     GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_TITLE,          XL_NS_O, "Title", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_TITLE),
1070     GSF_XML_IN_NODE (DOC_PROP, PROP_TOTAL_TIME,          XL_NS_O, "TotalTime", GSF_XML_CONTENT, NULL, NULL),
1071     GSF_XML_IN_NODE (DOC_PROP, PROP_VERSION,             XL_NS_O, "Version", GSF_XML_CONTENT, NULL, NULL),
1072 
1073   GSF_XML_IN_NODE (WORKBOOK, DOC_SETTINGS, XL_NS_O, "OfficeDocumentSettings", GSF_XML_NO_CONTENT, NULL, NULL),
1074     GSF_XML_IN_NODE (DOC_SETTINGS, DOC_COLORS, XL_NS_O, "Colors", GSF_XML_NO_CONTENT, NULL, NULL),
1075       GSF_XML_IN_NODE (DOC_COLORS, DOC_COLOR,  XL_NS_O, "Color", GSF_XML_NO_CONTENT, NULL, NULL),
1076         GSF_XML_IN_NODE (DOC_COLOR,  COLOR_INDEX, XL_NS_O, "Index", GSF_XML_NO_CONTENT, NULL, NULL),
1077         GSF_XML_IN_NODE (DOC_COLOR,  COLOR_RGB, XL_NS_O, "RGB", GSF_XML_NO_CONTENT, NULL, NULL),
1078     GSF_XML_IN_NODE (DOC_SETTINGS, DOC_COMPONENTS, XL_NS_O, "DownloadComponents", GSF_XML_NO_CONTENT, NULL, NULL),
1079     GSF_XML_IN_NODE (DOC_SETTINGS, DOC_COMPONENTS_LOCATION, XL_NS_O, "LocationOfComponents", GSF_XML_NO_CONTENT, NULL, NULL),
1080   GSF_XML_IN_NODE (WORKBOOK, WB_VIEW, XL_NS_XL, "ExcelWorkbook", GSF_XML_NO_CONTENT, NULL, NULL),
1081     GSF_XML_IN_NODE (WB_VIEW, TAB_RATIO, XL_NS_XL, "TabRatio", GSF_XML_NO_CONTENT, NULL, NULL),
1082     GSF_XML_IN_NODE (WB_VIEW, SUPBOOK, XL_NS_XL, "SupBook", GSF_XML_NO_CONTENT, NULL, NULL),
1083       GSF_XML_IN_NODE (SUPBOOK, SUP_DLL, XL_NS_XL, "Dll", GSF_XML_NO_CONTENT, NULL, NULL),
1084       GSF_XML_IN_NODE (SUPBOOK, SUP_EXTERNNAME, XL_NS_XL, "ExternName", GSF_XML_NO_CONTENT, NULL, NULL),
1085         GSF_XML_IN_NODE (SUP_EXTERNNAME, EXTERNNAME_NAME, XL_NS_XL, "Name", GSF_XML_NO_CONTENT, NULL, NULL),
1086     GSF_XML_IN_NODE (WB_VIEW, VIEW_HEIGHT, XL_NS_XL, "WindowHeight", GSF_XML_CONTENT, NULL, NULL),
1087     GSF_XML_IN_NODE (WB_VIEW, VIEW_WIDTH,  XL_NS_XL, "WindowWidth",  GSF_XML_CONTENT, NULL, NULL),
1088     GSF_XML_IN_NODE (WB_VIEW, VIEW_TOP_X,  XL_NS_XL, "WindowTopX",   GSF_XML_CONTENT, NULL, NULL),
1089     GSF_XML_IN_NODE (WB_VIEW, VIEW_TOP_Y,  XL_NS_XL, "WindowTopY",   GSF_XML_CONTENT, NULL, NULL),
1090     GSF_XML_IN_NODE (WB_VIEW, PROTECT_STRUCTURE, XL_NS_XL, "ProtectStructure",   GSF_XML_CONTENT, NULL, NULL),
1091     GSF_XML_IN_NODE (WB_VIEW, PROTECT_WINDOWS,   XL_NS_XL, "ProtectWindows",     GSF_XML_CONTENT, NULL, NULL),
1092     GSF_XML_IN_NODE (WB_VIEW, NATURAL_LANGUAGE,  XL_NS_XL, "AcceptLabelsInFormulas", GSF_XML_CONTENT, NULL, NULL),
1093   GSF_XML_IN_NODE (WORKBOOK, STYLES, XL_NS_SS, "Styles", GSF_XML_NO_CONTENT, NULL, NULL),
1094     GSF_XML_IN_NODE (STYLES, STYLE, XL_NS_SS,  "Style", GSF_XML_NO_CONTENT, &xl_xml_style_start, &xl_xml_style_end),
1095       GSF_XML_IN_NODE (STYLE, ALIGNMENT,  XL_NS_SS, "Alignment", GSF_XML_NO_CONTENT, &xl_xml_alignment, NULL),
1096       GSF_XML_IN_NODE (STYLE, BORDERS,    XL_NS_SS, "Borders",   GSF_XML_NO_CONTENT, NULL, NULL),
1097         GSF_XML_IN_NODE (BORDERS, BORDER, XL_NS_SS, "Border",    GSF_XML_NO_CONTENT, &xl_xml_border, NULL),
1098       GSF_XML_IN_NODE (STYLE, FONT,       XL_NS_SS, "Font",      GSF_XML_NO_CONTENT, &xl_xml_font, NULL),
1099       GSF_XML_IN_NODE (STYLE, INTERIOR,   XL_NS_SS, "Interior",  GSF_XML_NO_CONTENT, &xl_xml_num_interior, NULL),
1100       GSF_XML_IN_NODE (STYLE, NUM_FMT,    XL_NS_SS, "NumberFormat", GSF_XML_NO_CONTENT, &xl_xml_num_fmt, NULL),
1101       GSF_XML_IN_NODE (STYLE, PROTECTION, XL_NS_SS, "Protection", GSF_XML_NO_CONTENT, NULL, NULL),
1102   GSF_XML_IN_NODE (WORKBOOK, NAMES, XL_NS_SS, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
1103     GSF_XML_IN_NODE (NAMES, NAMED_RANGE, XL_NS_SS, "NamedRange", GSF_XML_NO_CONTENT, &xl_xml_named_range, NULL),
1104 
1105   GSF_XML_IN_NODE_FULL (WORKBOOK, WORKSHEET, XL_NS_SS, "Worksheet", GSF_XML_NO_CONTENT, FALSE, TRUE, &xl_xml_sheet_start, &xl_xml_sheet_end, 0),
1106     GSF_XML_IN_NODE (WORKSHEET, TABLE, XL_NS_SS, "Table", GSF_XML_NO_CONTENT, &xl_xml_table_start, NULL),
1107       GSF_XML_IN_NODE (TABLE, COLUMN, XL_NS_SS, "Column", GSF_XML_NO_CONTENT, &xl_xml_col_start, NULL),
1108       GSF_XML_IN_NODE (TABLE, ROW, XL_NS_SS, "Row", GSF_XML_NO_CONTENT, &xl_xml_row_start, &xl_xml_row_end),
1109 	GSF_XML_IN_NODE_FULL (ROW, CELL, XL_NS_SS, "Cell", GSF_XML_NO_CONTENT, FALSE, TRUE, &xl_xml_cell_start, &xl_xml_cell_end, 0),
1110           GSF_XML_IN_NODE (CELL, NAMED_CELL, XL_NS_SS, "NamedCell", GSF_XML_NO_CONTENT, NULL, NULL),
1111           GSF_XML_IN_NODE_FULL (CELL, CELL_DATA, XL_NS_SS, "Data", GSF_XML_CONTENT, GSF_XML_NO_CONTENT, TRUE, &xl_xml_data_start, &xl_xml_data_end, 0),
1112 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_B,    XL_NS_HTML, "B",    GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 0),
1113 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_I,    XL_NS_HTML, "I",    GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 1),
1114 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_U,    XL_NS_HTML, "U",    GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 2),
1115 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_FONT, XL_NS_HTML, "Font", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 3),
1116 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_S,    XL_NS_HTML, "S",    GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 4),
1117 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_SUP,  XL_NS_HTML, "Sup",  GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 5),
1118 	    GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_SUB,  XL_NS_HTML, "Sub",  GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 6),
1119     GSF_XML_IN_NODE (WORKSHEET, OPTIONS, XL_NS_XL, "WorksheetOptions", GSF_XML_NO_CONTENT, NULL, NULL),
1120       GSF_XML_IN_NODE (OPTIONS, TOP_ROW, XL_NS_XL, "TopRowVisible", GSF_XML_NO_CONTENT, NULL, NULL),
1121       GSF_XML_IN_NODE (OPTIONS, UNSYNCED, XL_NS_XL, "Unsynced", GSF_XML_NO_CONTENT, NULL, NULL),	/* ?? */
1122       GSF_XML_IN_NODE (OPTIONS, SELECTED, XL_NS_XL, "Selected", GSF_XML_NO_CONTENT, NULL, NULL),	/* ?? */
1123       GSF_XML_IN_NODE (OPTIONS, PANES, XL_NS_XL, "Panes", GSF_XML_NO_CONTENT, NULL, NULL),
1124         GSF_XML_IN_NODE (PANES, PANE, XL_NS_XL,  "Pane", GSF_XML_NO_CONTENT, &xl_xml_pane, NULL),
1125           GSF_XML_IN_NODE (PANE, PANE_NUM, XL_NS_XL,  "Number", GSF_XML_CONTENT, NULL, NULL),
1126           GSF_XML_IN_NODE (PANE, PANE_ACTIVEROW, XL_NS_XL,  "ActiveRow", GSF_XML_CONTENT, NULL, &xl_xml_editpos_row),
1127           GSF_XML_IN_NODE (PANE, PANE_ACTIVECOL, XL_NS_XL,  "ActiveCol", GSF_XML_CONTENT, NULL, &xl_xml_editpos_col),
1128           GSF_XML_IN_NODE (PANE, PANE_SELECTION, XL_NS_XL,  "RangeSelection", GSF_XML_CONTENT, NULL, &xl_xml_selection),
1129       GSF_XML_IN_NODE (OPTIONS, PAGE_SETUP, XL_NS_XL, "PageSetup", GSF_XML_NO_CONTENT, NULL, NULL),
1130 	GSF_XML_IN_NODE (PAGE_SETUP, PAGE_LAYOUT, XL_NS_XL, "Layout", GSF_XML_NO_CONTENT, NULL, NULL),
1131 	GSF_XML_IN_NODE (PAGE_SETUP, PAGE_HEADER, XL_NS_XL, "Header", GSF_XML_NO_CONTENT, NULL, NULL),
1132 	GSF_XML_IN_NODE (PAGE_SETUP, PAGE_FOOTER, XL_NS_XL, "Footer", GSF_XML_NO_CONTENT, NULL, NULL),
1133 	GSF_XML_IN_NODE (PAGE_SETUP, PAGE_MARGINS, XL_NS_XL, "PageMargins", GSF_XML_NO_CONTENT, NULL, NULL),
1134       GSF_XML_IN_NODE (OPTIONS, PRINT, XL_NS_XL, "Print", GSF_XML_NO_CONTENT, NULL, NULL),
1135 	GSF_XML_IN_NODE (PRINT, PRINT_NUMBER_COPIES, XL_NS_XL, "NumberofCopies", GSF_XML_NO_CONTENT, NULL, NULL),
1136 	GSF_XML_IN_NODE (PRINT, PRINT_VALID_INFO,  XL_NS_XL, "ValidPrinterInfo", GSF_XML_NO_CONTENT, NULL, NULL),
1137 	GSF_XML_IN_NODE (PRINT, PRINT_PAPER_SIZE,  XL_NS_XL, "PaperSizeIndex", GSF_XML_CONTENT, NULL, NULL),
1138 	GSF_XML_IN_NODE (PRINT, PRINT_HRES,	   XL_NS_XL, "HorizontalResolution", GSF_XML_CONTENT, NULL, NULL),
1139 	GSF_XML_IN_NODE (PRINT, PRINT_VRES,	   XL_NS_XL, "VerticalResolution", GSF_XML_CONTENT, NULL, NULL),
1140 
1141       GSF_XML_IN_NODE (OPTIONS, PROT_OBJS,	 XL_NS_XL, "ProtectObjects", GSF_XML_CONTENT, NULL, NULL),
1142       GSF_XML_IN_NODE (OPTIONS, PROT_SCENARIOS,  XL_NS_XL, "ProtectScenarios", GSF_XML_CONTENT, NULL, NULL),
1143       GSF_XML_IN_NODE (OPTIONS, PAGEBREAK_ZOOM,	 XL_NS_XL, "PageBreakZoom", GSF_XML_NO_CONTENT, NULL, NULL),
1144     GSF_XML_IN_NODE (WORKSHEET, COND_FMT, XL_NS_XL, "ConditionalFormatting", GSF_XML_NO_CONTENT, NULL, NULL),
1145       GSF_XML_IN_NODE (COND_FMT, COND_RANGE,	XL_NS_XL, "Range", GSF_XML_NO_CONTENT, NULL, NULL),
1146       GSF_XML_IN_NODE (COND_FMT, COND,		XL_NS_XL, "Condition", GSF_XML_NO_CONTENT, NULL, NULL),
1147         GSF_XML_IN_NODE (COND, COND_VALUE1,	XL_NS_XL, "Value1", GSF_XML_NO_CONTENT, NULL, NULL),
1148         GSF_XML_IN_NODE (COND, COND_STYLE,	XL_NS_XL, "Format", GSF_XML_NO_CONTENT, NULL, NULL),
1149     GSF_XML_IN_NODE (WORKSHEET, AUTO_FILTER,    XL_NS_XL, "AutoFilter", GSF_XML_NO_CONTENT, &xl_xml_auto_filter_start, NULL),
1150     GSF_XML_IN_NODE (WORKSHEET, WS_NAMES,       XL_NS_SS, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
1151       GSF_XML_IN_NODE (WS_NAMES, WS_NAMED_RANGE,   XL_NS_SS, "NamedRange", GSF_XML_NO_CONTENT, NULL, NULL),
1152 
1153   GSF_XML_IN_NODE_END
1154 };
1155 
1156 G_MODULE_EXPORT void
1157 excel_xml_file_open (GOFileOpener const *fo, GOIOContext *context,
1158 		     WorkbookView *wbv, GsfInput *input);
1159 
1160 G_MODULE_EXPORT gboolean
1161 excel_xml_file_probe (GOFileOpener const *fo, GsfInput *input, GOFileProbeLevel pl);
1162 
1163 static gboolean
xl_xml_probe_start_element(const xmlChar * name,G_GNUC_UNUSED const xmlChar * prefix,const xmlChar * URI,G_GNUC_UNUSED int nb_namespaces,G_GNUC_UNUSED const xmlChar ** namespaces,G_GNUC_UNUSED int nb_attributes,G_GNUC_UNUSED int nb_defaulted,G_GNUC_UNUSED const xmlChar ** attributes)1164 xl_xml_probe_start_element (const xmlChar *name,
1165 			    G_GNUC_UNUSED const xmlChar *prefix,
1166 			    const xmlChar *URI,
1167 			    G_GNUC_UNUSED int nb_namespaces,
1168 			    G_GNUC_UNUSED const xmlChar **namespaces,
1169 			    G_GNUC_UNUSED int nb_attributes,
1170 			    G_GNUC_UNUSED int nb_defaulted,
1171 			    G_GNUC_UNUSED const xmlChar **attributes)
1172 {
1173 	/* starts with <Workbook> in namespace "schemas-microsoft-com:office:spreadsheet" */
1174 	return 0 == strcmp (name, "Workbook") &&
1175 		NULL != URI &&
1176 		NULL != strstr (URI, "schemas-microsoft-com:office:spreadsheet");
1177 }
1178 
1179 gboolean
excel_xml_file_probe(G_GNUC_UNUSED GOFileOpener const * fo,GsfInput * input,GOFileProbeLevel pl)1180 excel_xml_file_probe (G_GNUC_UNUSED GOFileOpener const *fo,
1181 		      GsfInput *input, GOFileProbeLevel pl)
1182 {
1183 	if (pl == GO_FILE_PROBE_FILE_NAME) {
1184 		char const *ext;
1185 		char const *name = gsf_input_name (input);
1186 		return  NULL != name &&
1187 			NULL != (ext = gsf_extension_pointer (name)) &&
1188 			0 == g_ascii_strcasecmp (ext, "xml");
1189 	}
1190 
1191 	return gsf_xml_probe (input, &xl_xml_probe_start_element);
1192 }
1193 
1194 void
excel_xml_file_open(G_GNUC_UNUSED GOFileOpener const * fo,GOIOContext * io_context,WorkbookView * wb_view,GsfInput * input)1195 excel_xml_file_open (G_GNUC_UNUSED GOFileOpener const *fo,
1196 		     GOIOContext *io_context,
1197 		     WorkbookView *wb_view, GsfInput *input)
1198 {
1199 	GsfXMLInDoc *doc;
1200 	ExcelXMLReadState state;
1201 	GnmLocale	*locale;
1202 
1203 	locale = gnm_push_C_locale ();
1204 
1205 	state.context	= io_context;
1206 	state.wb_view	= wb_view;
1207 	state.wb	= wb_view_get_workbook (wb_view);
1208 	state.sheet	= NULL;
1209 	state.style	= NULL;
1210 	state.def_style	= NULL;
1211 	state.texpr	= NULL;
1212 	state.style_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
1213 		(GDestroyNotify)g_free, (GDestroyNotify) gnm_style_unref);
1214 
1215 	doc = gsf_xml_in_doc_new (excel_xml_dtd, content_ns);
1216 	if (!gsf_xml_in_doc_parse (doc, input, &state))
1217 		go_io_error_string (io_context, _("XML document not well formed!"));
1218 	gsf_xml_in_doc_free (doc);
1219 
1220 	g_hash_table_destroy (state.style_hash);
1221 
1222 	gnm_pop_C_locale (locale);
1223 }
1224