1 
2 /*
3  * xml-sax-read.c : a sax based parser.
4  *
5  * Copyright (C) 2000-2007 Jody Goldberg (jody@gnome.org)
6  * Copyright (C) 2007-2009 Morten Welinder (terra@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 
24 #include <gnumeric-config.h>
25 #include <gnumeric.h>
26 #include <xml-sax.h>
27 #include <xml-io-version.h>
28 #include <gnm-plugin.h>
29 #include <sheet-view.h>
30 #include <sheet-style.h>
31 #include <sheet-merge.h>
32 #include <sheet-filter.h>
33 #include <sheet.h>
34 #include <ranges.h>
35 #include <tools/gnm-solver.h>
36 #include <tools/scenarios.h>
37 #include <style.h>
38 #include <style-border.h>
39 #include <style-color.h>
40 #include <style-conditions.h>
41 #include <validation.h>
42 #include <hlink.h>
43 #include <input-msg.h>
44 #include <cell.h>
45 #include <position.h>
46 #include <expr.h>
47 #include <expr-name.h>
48 #include <print-info.h>
49 #include <value.h>
50 #include <selection.h>
51 #include <command-context.h>
52 #include <workbook-view.h>
53 #include <workbook-control.h>
54 #include <workbook.h>
55 #include <sheet-object-impl.h>
56 #include <sheet-object-cell-comment.h>
57 #include <gnm-so-line.h>
58 #include <gnm-so-filled.h>
59 #include <gnm-so-path.h>
60 #include <gnm-format.h>
61 #include <sheet-object-graph.h>
62 #include <sheet-object-component.h>
63 #include <application.h>
64 #include <gutils.h>
65 #include <clipboard.h>
66 #include <number-match.h>
67 
68 #include <goffice/goffice.h>
69 
70 #include <gsf/gsf-libxml.h>
71 #include <gsf/gsf-input.h>
72 #include <gsf/gsf-input-memory.h>
73 #include <gsf/gsf-input-gzip.h>
74 #include <gsf/gsf-opendoc-utils.h>
75 #include <gsf/gsf-utils.h>
76 #include <glib/gi18n-lib.h>
77 #include <libxml/tree.h>
78 #include <libxml/parser.h>
79 #include <libxml/parserInternals.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <errno.h>
83 
84 /* libgsf defines OO_NS_OFFICE to be 0, so we need to take something different for GNM */
85 #define GNM		100
86 
87 static void
xml_sax_barf(const char * locus,const char * reason)88 xml_sax_barf (const char *locus, const char *reason)
89 {
90 	g_warning ("File is most likely corrupted.\n"
91 		   "The problem was detected in %s.\n"
92 		   "The failed check was: %s",
93 		   locus, reason);
94 }
95 
96 #define XML_CHECK3(_cond_,_code_,_reason_)		\
97   do {							\
98 	  if (G_UNLIKELY(!(_cond_))) {			\
99 		  xml_sax_barf (G_STRFUNC, _reason_);	\
100 		  _code_;				\
101 		  return;				\
102 	  }						\
103   } while (0)
104 
105 #define XML_CHECK(_cond_) XML_CHECK3(_cond_,{},#_cond_)
106 #define XML_CHECK2(_cond_,_code_) XML_CHECK3(_cond_,_code_,#_cond_)
107 
108 
109 #define CXML2C(s) ((char const *)(s))
110 
111 static inline gboolean
attr_eq(const xmlChar * a,const char * s)112 attr_eq (const xmlChar *a, const char *s)
113 {
114 	return !strcmp (CXML2C (a), s);
115 }
116 
117 static GOFormat *
make_format(const char * str)118 make_format (const char *str)
119 {
120 	GOFormat *res =
121 		gnm_format_import (str,
122 				   GNM_FORMAT_IMPORT_NULL_INVALID |
123 				   GNM_FORMAT_IMPORT_PATCHUP_INCOMPLETE);
124 	if (!res) {
125 		g_warning ("Ignoring invalid format [%s]", str);
126 		return NULL;
127 	}
128 
129 	return res;
130 }
131 
132 /*****************************************************************************/
133 
134 gboolean
gnm_xml_attr_double(xmlChar const * const * attrs,char const * name,double * res)135 gnm_xml_attr_double (xmlChar const * const *attrs, char const *name, double * res)
136 {
137 	char *end;
138 	double tmp;
139 
140 	g_return_val_if_fail (attrs != NULL, FALSE);
141 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
142 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
143 
144 	if (!attr_eq (attrs[0], name))
145 		return FALSE;
146 
147 	tmp = go_strtod (CXML2C (attrs[1]), &end);
148 	if (*end) {
149 		g_warning ("Invalid attribute '%s', expected double, received '%s'",
150 			   name, attrs[1]);
151 		return FALSE;
152 	}
153 	*res = tmp;
154 	return TRUE;
155 }
156 
157 static gboolean
xml_sax_double(xmlChar const * chars,double * res)158 xml_sax_double (xmlChar const *chars, double *res)
159 {
160 	char *end;
161 	*res = go_strtod (CXML2C (chars), &end);
162 	return *end == '\0';
163 }
164 
165 gboolean
gnm_xml_attr_bool(xmlChar const * const * attrs,char const * name,gboolean * res)166 gnm_xml_attr_bool (xmlChar const * const *attrs, 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 (!attr_eq (attrs[0], name))
173 		return FALSE;
174 
175 	*res = g_ascii_strcasecmp (CXML2C (attrs[1]), "false") && strcmp (CXML2C (attrs[1]), "0");
176 
177 	return TRUE;
178 }
179 
180 gboolean
gnm_xml_attr_int(xmlChar const * const * attrs,char const * name,int * res)181 gnm_xml_attr_int (xmlChar const * const *attrs, char const *name, int *res)
182 {
183 	char *end;
184 	long 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 (!attr_eq (attrs[0], name))
191 		return FALSE;
192 
193 	errno = 0;
194 	tmp = strtol (CXML2C (attrs[1]), &end, 10);
195 	if (*end || errno) {
196 		g_warning ("Invalid attribute '%s', expected integer, received '%s'",
197 			   name, attrs[1]);
198 		return FALSE;
199 	}
200 	*res = tmp;
201 	return TRUE;
202 }
203 
204 /* NOT SUITABLE FOR HIGH VOLUME VALUES
205  * Checking both name and nick gets expensive */
206 static gboolean
xml_sax_attr_enum(xmlChar const * const * attrs,char const * name,GType etype,gint * val)207 xml_sax_attr_enum (xmlChar const * const *attrs,
208 		   char const *name,
209 		   GType etype,
210 		   gint *val)
211 {
212 	GEnumClass *eclass;
213 	GEnumValue *ev;
214 	int i;
215 
216 	g_return_val_if_fail (attrs != NULL, FALSE);
217 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
218 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
219 
220 	if (!attr_eq (attrs[0], name))
221 		return FALSE;
222 
223 	eclass = G_ENUM_CLASS (g_type_class_ref (etype));
224 	ev = g_enum_get_value_by_name (eclass, CXML2C (attrs[1]));
225 	if (!ev) ev = g_enum_get_value_by_nick (eclass, CXML2C (attrs[1]));
226 	g_type_class_unref (eclass);
227 
228 	if (!ev && gnm_xml_attr_int (attrs, name, &i))
229 		/* Check that the value is valid.  */
230 		ev = g_enum_get_value (eclass, i);
231 	if (!ev) return FALSE;
232 
233 	*val = ev->value;
234 	return TRUE;
235 }
236 
237 
238 static gboolean
xml_sax_attr_cellpos(xmlChar const * const * attrs,char const * name,GnmCellPos * val,Sheet const * sheet)239 xml_sax_attr_cellpos (xmlChar const * const *attrs, char const *name, GnmCellPos *val, Sheet const *sheet)
240 {
241 	g_return_val_if_fail (attrs != NULL, FALSE);
242 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
243 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
244 
245 	if (!attr_eq (attrs[0], name))
246 		return FALSE;
247 
248 	if (cellpos_parse (CXML2C (attrs[1]), gnm_sheet_get_size (sheet), val, TRUE) == NULL) {
249 		g_warning ("Invalid attribute '%s', expected cellpos, received '%s'",
250 			   name, attrs[1]);
251 		return FALSE;
252 	}
253 	return TRUE;
254 }
255 
256 static gboolean
xml_sax_attr_color(xmlChar const * const * attrs,char const * name,GnmColor ** res)257 xml_sax_attr_color (xmlChar const * const *attrs, char const *name, GnmColor **res)
258 {
259 	unsigned int red, green, blue, alpha = 0xffff;
260 
261 	g_return_val_if_fail (attrs != NULL, FALSE);
262 	g_return_val_if_fail (attrs[0] != NULL, FALSE);
263 	g_return_val_if_fail (attrs[1] != NULL, FALSE);
264 
265 	if (!attr_eq (attrs[0], name))
266 		return FALSE;
267 
268 	if (sscanf (CXML2C (attrs[1]), "%X:%X:%X:%X", &red, &green, &blue, &alpha) < 3){
269 		g_warning ("Invalid attribute '%s', expected colour, received '%s'",
270 			   name, attrs[1]);
271 		return FALSE;
272 	}
273 	*res = gnm_color_new_rgba16 (red, green, blue, alpha);
274 	return TRUE;
275 }
276 
277 static gboolean
xml_sax_attr_range(xmlChar const * const * attrs,GnmRange * res)278 xml_sax_attr_range (xmlChar const * const *attrs, GnmRange *res)
279 {
280 	int flags = 0;
281 
282 	g_return_val_if_fail (attrs != NULL, FALSE);
283 
284 	for (; attrs[0] && attrs[1] ; attrs += 2)
285 		if (gnm_xml_attr_int (attrs, "startCol", &res->start.col))
286 			flags |= 0x1;
287 		else if (gnm_xml_attr_int (attrs, "startRow", &res->start.row))
288 			flags |= 0x2;
289 		else if (gnm_xml_attr_int (attrs, "endCol", &res->end.col))
290 			flags |= 0x4;
291 		else if (gnm_xml_attr_int (attrs, "endRow", &res->end.row))
292 			flags |= 0x8;
293 		else
294 			return FALSE;
295 
296 	return flags == 0xf;
297 }
298 
299 /*****************************************************************************/
300 
301 typedef enum {
302 	READ_FULL_FILE,
303 	READ_CLIPBOARD,
304 	READ_STYLE
305 } ReadFileWhat;
306 
307 
308 typedef struct {
309 	GsfXMLIn base;
310 
311 	GOIOContext	*context;	/* The IOcontext managing things */
312 	WorkbookView	*wb_view;	/* View for the new workbook */
313 	Workbook	*wb;		/* The new workbook */
314 	GnumericXMLVersion version;
315 	gsf_off_t last_progress_update;
316 	GnmConventions *convs;
317 	gboolean do_progress;
318 
319 	Sheet *sheet;
320 	double sheet_zoom;
321 
322 	/* Only valid while parsing attributes */
323 	struct {
324 		char *name;
325 		char *value;
326 	} attribute;
327 
328 	/* Only valid when parsing wb or sheet names */
329 	struct {
330 		char *name;
331 		char *value;
332 		char *position;
333 	} name;
334 
335 	struct {
336 		char            *title;
337 		char            *msg;
338 		GnmExprTop const *texpr[2];
339 		ValidationStyle  style;
340 		ValidationType	 type;
341 		ValidationOp	 op;
342 		gboolean	 allow_blank;
343 		gboolean	 use_dropdown;
344 	} validation;
345 
346 	GnmStyleCond *cond;
347 	GnmStyle *cond_save_style;
348 
349 	gboolean  style_range_init;
350 	GnmRange	  style_range;
351 	GnmStyle   *style;
352 
353 	GnmCellPos cell;
354 	gboolean seen_cell_contents;
355 	int expr_id, array_rows, array_cols;
356 	int value_type;
357 	GOFormat *value_fmt;
358 	char *value_result;
359 
360 	GnmScenario *scenario;
361 	GnmValue *scenario_range;
362 
363 	GnmFilter *filter;
364 
365 	int display_formulas;
366 	int hide_zero;
367 	int hide_grid;
368 	int hide_col_header;
369 	int hide_row_header;
370 	int display_outlines;
371 	int outline_symbols_below;
372 	int outline_symbols_right;
373 	int text_is_rtl;
374 	int is_protected;
375 	char *expr_conv_name;
376 	GnmSheetVisibility visibility;
377 	GnmColor *tab_color;
378 	GnmColor *tab_text_color;
379 	GnmColor *grid_color;
380 
381 	/* expressions with ref > 1 a map from index -> expr pointer */
382 	GHashTable *expr_map;
383 	GList *delayed_names;
384 	SheetObject *so;
385 
386 	int sheet_rows, sheet_cols;
387 	GnmSheetType sheet_type;
388 
389 	GnmPageBreaks *page_breaks;
390 
391 	GnmCellRegion *clipboard;
392 
393 	GnmXmlStyleHandler style_handler;
394 	gpointer style_handler_user;
395 	GsfXMLInDoc *style_handler_doc;
396 } XMLSaxParseState;
397 
398 static void
maybe_update_progress(GsfXMLIn * xin)399 maybe_update_progress (GsfXMLIn *xin)
400 {
401 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
402 	GsfInput *input = gsf_xml_in_get_input (xin);
403 	gsf_off_t pos = gsf_input_tell (input);
404 
405 	if (state->do_progress && pos >= state->last_progress_update + 10000) {
406 		go_io_value_progress_update (state->context, pos);
407 		state->last_progress_update = pos;
408 	}
409 }
410 
411 /**
412  * gnm_xml_in_cur_obj:
413  * @xin: #GsfXMLIn
414  *
415  * Returns: (transfer none): the current sheet object.
416  **/
417 SheetObject *
gnm_xml_in_cur_obj(GsfXMLIn const * xin)418 gnm_xml_in_cur_obj (GsfXMLIn const *xin)
419 {
420 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
421 	return state->so;
422 }
423 
424 /**
425  * gnm_xml_in_cur_sheet:
426  * @xin: #GsfXMLIn
427  *
428  * Returns: (transfer none): the current sheet.
429  **/
430 Sheet *
gnm_xml_in_cur_sheet(GsfXMLIn const * xin)431 gnm_xml_in_cur_sheet (GsfXMLIn const *xin)
432 {
433 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
434 	return state->sheet;
435 }
436 
437 static void
gnm_xml_finish_obj(GsfXMLIn * xin,XMLSaxParseState * state)438 gnm_xml_finish_obj (GsfXMLIn *xin, XMLSaxParseState *state)
439 {
440 	GnmCellRegion *cr = state->clipboard;
441 
442 	if (cr) {
443 		cr->objects = g_slist_prepend (cr->objects, state->so);
444 	} else {
445 		sheet_object_set_sheet (state->so, state->sheet);
446 		g_object_unref (state->so);
447 	}
448 
449 	state->so = NULL;
450 }
451 
452 /****************************************************************************/
453 
454 static void
unknown_attr(GsfXMLIn * xin,xmlChar const * const * attrs)455 unknown_attr (GsfXMLIn *xin, xmlChar const * const *attrs)
456 {
457 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
458 
459 	if (state->version == GNM_XML_LATEST)
460 		go_io_warning (state->context,
461 			_("Unexpected attribute %s::%s == '%s'."),
462 			(NULL != xin->node &&
463 			 NULL != xin->node->name) ?
464 			xin->node->name : "<unknown name>",
465 			attrs[0], attrs[1]);
466 }
467 
468 static void
xml_sax_wb(GsfXMLIn * xin,xmlChar const ** attrs)469 xml_sax_wb (GsfXMLIn *xin, xmlChar const **attrs)
470 {
471 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
472 
473 	/*
474 	 * NOTE: If we read a file with a dtd that is newer, i.e., from the
475 	 * future, then we will not get here!  For that reason we also muck
476 	 * with ->version in xml_sax_version.
477 	 */
478 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
479 		if (strcmp (CXML2C (attrs[0]), "xmlns:gmr") == 0 ||
480 		    strcmp (CXML2C (attrs[0]), "xmlns:gnm") == 0) {
481 			static struct {
482 				char const * const id;
483 				GnumericXMLVersion const version;
484 			} const GnumericVersions [] = {
485 				{ "http://www.gnumeric.org/v14.dtd", GNM_XML_V14 },	/* 1.12.21 */
486 				{ "http://www.gnumeric.org/v13.dtd", GNM_XML_V13 },	/* 1.7.7 */
487 				{ "http://www.gnumeric.org/v12.dtd", GNM_XML_V12 },	/* 1.7.3 */
488 				{ "http://www.gnumeric.org/v11.dtd", GNM_XML_V11 },	/* 1.7.0 */
489 				{ "http://www.gnumeric.org/v10.dtd", GNM_XML_V10 },	/* 1.0.3 */
490 				{ "http://www.gnumeric.org/v9.dtd", GNM_XML_V9 },	/* 0.73 */
491 				{ "http://www.gnumeric.org/v8.dtd", GNM_XML_V8 },	/* 0.71 */
492 				{ "http://www.gnome.org/gnumeric/v7", GNM_XML_V7 },	/* 0.66 */
493 				{ "http://www.gnome.org/gnumeric/v6", GNM_XML_V6 },	/* 0.62 */
494 				{ "http://www.gnome.org/gnumeric/v5", GNM_XML_V5 },
495 				{ "http://www.gnome.org/gnumeric/v4", GNM_XML_V4 },
496 				{ "http://www.gnome.org/gnumeric/v3", GNM_XML_V3 },
497 				{ "http://www.gnome.org/gnumeric/v2", GNM_XML_V2 },
498 				{ "http://www.gnome.org/gnumeric/", GNM_XML_V1 },
499 				{ NULL, 0}
500 			};
501 			int i;
502 			for (i = 0 ; GnumericVersions [i].id != NULL ; ++i )
503 				if (strcmp (CXML2C (attrs[1]), GnumericVersions [i].id) == 0) {
504 					if (state->version != GNM_XML_UNKNOWN)
505 						go_io_warning (state->context,
506 							_("Multiple version specifications.  Assuming %d"),
507 							state->version);
508 					else {
509 						state->version = GnumericVersions [i].version;
510 						break;
511 					}
512 				}
513 		} else if (attr_eq (attrs[0], "xmlns:xsi")) {
514 		} else if (attr_eq (attrs[0], "xsi:schemaLocation")) {
515 		} else
516 			unknown_attr (xin, attrs);
517 	}
518 }
519 
520 static void
xml_sax_document_meta(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)521 xml_sax_document_meta (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
522 {
523 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
524 
525 	gsf_doc_meta_data_odf_subtree (go_doc_get_meta_data (GO_DOC (state->wb)), xin);
526 }
527 
528 
529 
530 static void
xml_sax_version(GsfXMLIn * xin,xmlChar const ** attrs)531 xml_sax_version (GsfXMLIn *xin, xmlChar const **attrs)
532 {
533 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
534 	int epoch = -1;
535 	int major = -1;
536 	int minor = -1;
537 	int version;
538 
539 	state->version = GNM_XML_V11;
540 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
541 		if (gnm_xml_attr_int (attrs, "Epoch", &epoch))
542 			/* Nothing */ ;
543 		else if (gnm_xml_attr_int (attrs, "Major", &major))
544 			/* Nothing */ ;
545 		else if (gnm_xml_attr_int (attrs, "Minor", &minor))
546 			/* Nothing */ ;
547 	}
548 
549 	version = (epoch * 100 + major) * 100 + minor;
550 	if (state->version == GNM_XML_UNKNOWN && version >= 10700) {
551 		if (version >= 11221)
552 			state->version = GNM_XML_V14;
553 		else if (version >= 10707)
554 			state->version = GNM_XML_V13;
555 		else if (version >= 10705)
556 			state->version = GNM_XML_V12;
557 		else if (version >= 10700)
558 			state->version = GNM_XML_V11;
559 	}
560 }
561 
562 static void
xml_sax_wb_sheetsize(GsfXMLIn * xin,xmlChar const ** attrs)563 xml_sax_wb_sheetsize (GsfXMLIn *xin, xmlChar const **attrs)
564 {
565 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
566 
567 	/* Defaults for legacy files.  */
568 	state->sheet_cols = 256;
569 	state->sheet_rows = 65536;
570 	state->sheet_type = GNM_SHEET_DATA;
571 
572 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
573 		if (gnm_xml_attr_int (attrs, "gnm:Cols", &state->sheet_cols))
574 			; /* Nothing more */
575 		else if (gnm_xml_attr_int (attrs, "gnm:Rows", &state->sheet_rows))
576 			; /* Nothing more */
577 		else if (!strcmp (CXML2C (attrs[0]), "gnm:SheetType") &&
578 			 !strcmp (CXML2C (attrs[1]), "object"))
579 			state->sheet_type = GNM_SHEET_OBJECT;
580 		else
581 			unknown_attr (xin, attrs);
582 	}
583 }
584 
585 static void
xml_sax_wb_sheetname(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)586 xml_sax_wb_sheetname (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
587 {
588 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
589 	char const *name = xin->content->str;
590 	Workbook *wb = state->wb;
591 
592 	g_return_if_fail (name != NULL);
593 
594 	if (NULL == workbook_sheet_by_name (wb, name)) {
595 		Sheet *sheet;
596 
597 		if (!gnm_sheet_valid_size (state->sheet_cols,
598 					   state->sheet_rows)) {
599 			gnm_sheet_suggest_size (&state->sheet_cols,
600 						&state->sheet_rows);
601 		}
602 
603 		sheet = sheet_new_with_type (wb, name,
604 				   state->sheet_type,
605 				   state->sheet_cols,
606 				   state->sheet_rows);
607 		workbook_sheet_attach (wb, sheet);
608 	}
609 }
610 
611 static void
xml_sax_wb_view(GsfXMLIn * xin,xmlChar const ** attrs)612 xml_sax_wb_view (GsfXMLIn *xin, xmlChar const **attrs)
613 {
614 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
615 
616 	int sheet_index;
617 	int width = -1, height = -1;
618 
619 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
620 		if (gnm_xml_attr_int (attrs, "SelectedTab", &sheet_index)) {
621 			Sheet *sheet = workbook_sheet_by_index (state->wb,
622 								sheet_index);
623 			if (sheet)
624 				wb_view_sheet_focus (state->wb_view, sheet);
625 		}
626 		else if (gnm_xml_attr_int (attrs, "Width", &width)) ;
627 		else if (gnm_xml_attr_int (attrs, "Height", &height)) ;
628 		else
629 			unknown_attr (xin, attrs);
630 
631 	if (width > 0 && height > 0)
632 		wb_view_preferred_size (state->wb_view, width, height);
633 }
634 static void
xml_sax_calculation(GsfXMLIn * xin,xmlChar const ** attrs)635 xml_sax_calculation (GsfXMLIn *xin, xmlChar const **attrs)
636 {
637 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
638 	gboolean b;
639 	int	 i;
640 	double	 d;
641 
642 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
643 		if (gnm_xml_attr_bool (attrs, "ManualRecalc", &b))
644 			workbook_set_recalcmode (state->wb, !b);
645 		else if (gnm_xml_attr_bool (attrs, "EnableIteration", &b))
646 			workbook_iteration_enabled (state->wb, b);
647 		else if (gnm_xml_attr_int  (attrs, "MaxIterations", &i))
648 			workbook_iteration_max_number (state->wb, i);
649 		else if (gnm_xml_attr_double (attrs, "IterationTolerance", &d))
650 			workbook_iteration_tolerance (state->wb, d);
651 		else if (strcmp (CXML2C (attrs[0]), "DateConvention") == 0) {
652 			GODateConventions const *date_conv =
653 				go_date_conv_from_str (CXML2C (attrs[1]));
654 			if (date_conv)
655 				workbook_set_date_conv (state->wb, date_conv);
656 			else
657 				g_printerr ("Ignoring invalid date conventions.\n");
658 		} else
659 			unknown_attr (xin, attrs);
660 }
661 
662 static void
xml_sax_old_dateconvention(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)663 xml_sax_old_dateconvention (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
664 {
665 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
666 	workbook_set_1904 (state->wb, strcmp (xin->content->str, "1904") == 0);
667 }
668 
669 static void
xml_sax_finish_parse_wb_attr(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)670 xml_sax_finish_parse_wb_attr (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
671 {
672 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
673 
674 	if (state->attribute.name && state->attribute.value) {
675 		wb_view_set_attribute (state->wb_view,
676 				       state->attribute.name,
677 				       state->attribute.value);
678 	} else {
679 		xml_sax_barf (G_STRFUNC, _("workbook view attribute is incomplete"));
680 	}
681 
682 	g_free (state->attribute.value);	state->attribute.value = NULL;
683 	g_free (state->attribute.name);		state->attribute.name = NULL;
684 }
685 
686 static void
xml_sax_attr_elem(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)687 xml_sax_attr_elem (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
688 {
689 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
690 
691 	char const *content = xin->content->str;
692 	int const len = xin->content->len;
693 
694 	switch (xin->node->user_data.v_int) {
695 	case 0:
696 		g_return_if_fail (state->attribute.name == NULL);
697 		state->attribute.name = g_strndup (content, len);
698 		break;
699 
700 	case 1:
701 		g_return_if_fail (state->attribute.value == NULL);
702 		state->attribute.value = g_strndup (content, len);
703 		break;
704 
705 	default:
706 		g_assert_not_reached ();
707 	}
708 }
709 
710 static void
xml_sax_sheet_start(GsfXMLIn * xin,xmlChar const ** attrs)711 xml_sax_sheet_start (GsfXMLIn *xin, xmlChar const **attrs)
712 {
713 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
714 
715 	gboolean tmp;
716 	gint tmpi;
717 	GnmColor *color = NULL;
718 
719 	state->hide_col_header = state->hide_row_header =
720 		state->display_formulas = state->hide_zero =
721 		state->hide_grid = state->display_outlines =
722 		state->outline_symbols_below = state->outline_symbols_right =
723 		state->text_is_rtl = state->is_protected = -1;
724 	state->expr_conv_name = NULL;
725 	state->visibility = GNM_SHEET_VISIBILITY_VISIBLE;
726 	state->tab_color = NULL;
727 	state->tab_text_color = NULL;
728 	state->grid_color = NULL;
729 	state->sheet_zoom = 1.; /* default */
730 
731 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
732 		if (gnm_xml_attr_bool (attrs, "DisplayFormulas", &tmp))
733 			state->display_formulas = tmp;
734 		else if (gnm_xml_attr_bool (attrs, "HideZero", &tmp))
735 			state->hide_zero = tmp;
736 		else if (gnm_xml_attr_bool (attrs, "HideGrid", &tmp))
737 			state->hide_grid = tmp;
738 		else if (gnm_xml_attr_bool (attrs, "HideColHeader", &tmp))
739 			state->hide_col_header = tmp;
740 		else if (gnm_xml_attr_bool (attrs, "HideRowHeader", &tmp))
741 			state->hide_row_header = tmp;
742 		else if (gnm_xml_attr_bool (attrs, "DisplayOutlines", &tmp))
743 			state->display_outlines = tmp;
744 		else if (gnm_xml_attr_bool (attrs, "OutlineSymbolsBelow", &tmp))
745 			state->outline_symbols_below = tmp;
746 		else if (gnm_xml_attr_bool (attrs, "OutlineSymbolsRight", &tmp))
747 			state->outline_symbols_right = tmp;
748 		else if (xml_sax_attr_enum (attrs, "Visibility", GNM_SHEET_VISIBILITY_TYPE, &tmpi))
749 			state->visibility = tmpi;
750 		else if (gnm_xml_attr_bool (attrs, "RTL_Layout", &tmp))
751 			state->text_is_rtl = tmp;
752 		else if (gnm_xml_attr_bool (attrs, "Protected", &tmp))
753 			state->is_protected = tmp;
754 		else if (strcmp (CXML2C (attrs[0]), "ExprConvention") == 0)
755 			state->expr_conv_name = g_strdup (attrs[1]);
756 		else if (xml_sax_attr_color (attrs, "TabColor", &color))
757 			state->tab_color = color;
758 		else if (xml_sax_attr_color (attrs, "TabTextColor", &color))
759 			state->tab_text_color = color;
760 		else if (xml_sax_attr_color (attrs, "GridColor", &color))
761 			state->grid_color = color;
762 		else
763 			unknown_attr (xin, attrs);
764 }
765 
766 static Sheet *
xml_sax_must_have_sheet(XMLSaxParseState * state)767 xml_sax_must_have_sheet (XMLSaxParseState *state)
768 {
769 	if (!state->sheet) {
770 		int columns = 256;
771 		int rows = 65536;
772 
773 		xml_sax_barf (G_STRFUNC, "sheet should have been named");
774 
775 		state->sheet = workbook_sheet_add (state->wb, -1,
776 						   columns, rows);
777 	}
778 
779 	return state->sheet;
780 }
781 
782 static GnmStyle *
xml_sax_must_have_style(XMLSaxParseState * state)783 xml_sax_must_have_style (XMLSaxParseState *state)
784 {
785 	if (!state->style) {
786 		xml_sax_barf (G_STRFUNC, "style should have been started");
787 		state->style = (state->version >= GNM_XML_V6 ||
788 				state->version <= GNM_XML_V2)
789 			? gnm_style_new_default ()
790 			: gnm_style_new ();
791 	}
792 
793 	return state->style;
794 }
795 
796 
797 static void
xml_sax_sheet_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)798 xml_sax_sheet_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
799 {
800 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
801 
802 	xml_sax_must_have_sheet (state);
803 
804 	/* Init ColRowInfo's size_pixels and force a full respan */
805 	g_object_set (state->sheet, "zoom-factor", state->sheet_zoom, NULL);
806 	sheet_flag_recompute_spans (state->sheet);
807 	state->sheet = NULL;
808 }
809 
810 static void
xml_sax_sheet_name(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)811 xml_sax_sheet_name (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
812 {
813 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
814 	Sheet *sheet;
815 	int columns = 256;
816 	int rows = 65536;
817 
818 	char const * content = xin->content->str;
819 	g_return_if_fail (state->sheet == NULL);
820 
821 	/* * FIXME: Pull this out at some point, so we don't
822 	 * have to support < GNM_XML_V7 anymore
823 	 */
824 	if (state->version >= GNM_XML_V7) {
825 		sheet = workbook_sheet_by_name (state->wb, content);
826 		if (!sheet) {
827 			go_io_error_string (state->context,
828 				_("File has inconsistent SheetNameIndex element."));
829 			sheet = sheet_new (state->wb, content,
830 					   columns, rows);
831 			workbook_sheet_attach (state->wb, sheet);
832 		}
833 	} else {
834 		sheet = sheet_new (state->wb, content, columns, rows);
835 		workbook_sheet_attach (state->wb, sheet);
836 	}
837 	state->sheet = sheet;
838 
839 	if (state->display_formulas >= 0)
840 		g_object_set (sheet, "display-formulas", state->display_formulas, NULL);
841 	if (state->hide_zero >= 0)
842 		g_object_set (sheet, "display-zeros", !state->hide_zero, NULL);
843 	if (state->hide_grid >= 0)
844 		g_object_set (sheet, "display-grid", !state->hide_grid, NULL);
845 	if (state->hide_col_header >= 0)
846 		g_object_set (sheet, "display-column-header", !state->hide_col_header, NULL);
847 	if (state->hide_row_header >= 0)
848 		g_object_set (sheet, "display-row-header", !state->hide_row_header, NULL);
849 	if (state->display_outlines >= 0)
850 		g_object_set (sheet, "display-outlines", state->display_outlines, NULL);
851 	if (state->outline_symbols_below >= 0)
852 		g_object_set (sheet, "display-outlines-below", state->outline_symbols_below, NULL);
853 	if (state->outline_symbols_right >= 0)
854 		g_object_set (sheet, "display-outlines-right", state->outline_symbols_right, NULL);
855 	if (state->text_is_rtl >= 0)
856 		g_object_set (sheet, "text-is-rtl", state->text_is_rtl, NULL);
857 	if (state->is_protected >= 0)
858 		g_object_set (sheet, "protected", state->is_protected, NULL);
859 	if (state->expr_conv_name != NULL) {
860 		GnmConventions const *convs = gnm_conventions_default;
861 		if (0 == strcmp (state->expr_conv_name, "gnumeric:R1C1"))
862 			convs = gnm_conventions_xls_r1c1;
863 		g_object_set (sheet, "conventions", convs, NULL);
864 
865 		g_free (state->expr_conv_name);
866 		state->expr_conv_name = NULL;
867 	}
868 	g_object_set (sheet, "visibility", state->visibility, NULL);
869 	sheet->tab_color = state->tab_color;
870 	sheet->tab_text_color = state->tab_text_color;
871 	if (state->grid_color)
872 		sheet_style_set_auto_pattern_color (sheet, state->grid_color);
873 }
874 
875 static void
xml_sax_sheet_zoom(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)876 xml_sax_sheet_zoom (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
877 {
878 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
879 
880 	char const * content = xin->content->str;
881 	double zoom;
882 
883 	xml_sax_must_have_sheet (state);
884 
885 	if (xml_sax_double ((xmlChar *)content, &zoom))
886 		state->sheet_zoom = zoom;
887 }
888 
889 static void
xml_sax_print_margins_unit(GsfXMLIn * xin,xmlChar const ** attrs,double * points,GtkUnit * desired_display)890 xml_sax_print_margins_unit (GsfXMLIn *xin, xmlChar const **attrs,
891 			    double *points, GtkUnit *desired_display)
892 {
893 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
894 		double pts;
895 		if (gnm_xml_attr_double (attrs, "Points", &pts)) {
896 			*points = pts;
897 		} else if (attr_eq (attrs[0], "PrefUnit")) {
898 			*desired_display = unit_name_to_unit (CXML2C (attrs[1]));
899 		} else
900 			unknown_attr (xin, attrs);
901 	}
902 }
903 
904 static void
xml_sax_print_margins(GsfXMLIn * xin,xmlChar const ** attrs)905 xml_sax_print_margins (GsfXMLIn *xin, xmlChar const **attrs)
906 {
907 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
908 
909 	GnmPrintInformation *pi;
910 	double points = -1.;
911 
912 	xml_sax_must_have_sheet (state);
913 
914 	pi = state->sheet->print_info;
915 	switch (xin->node->user_data.v_int) {
916 	case 0:
917 		xml_sax_print_margins_unit (xin, attrs,
918 					    &points,
919 					    &pi->desired_display.header);
920 		if (points >= 0.)
921 			print_info_set_edge_to_below_header (pi, points);
922 		break;
923 	case 1:
924 		xml_sax_print_margins_unit (xin, attrs,
925 					    &points,
926 					    &pi->desired_display.footer);
927 		if (points >= 0.)
928 			print_info_set_edge_to_above_footer (pi, points);
929 		break;
930 	case 2:
931 		xml_sax_print_margins_unit (xin, attrs,
932 					    &points, &pi->desired_display.left);
933 		if (points >= 0.)
934 			print_info_set_margin_left (pi, points);
935 		break;
936 	case 3:
937 		xml_sax_print_margins_unit (xin, attrs,
938 					    &points, &pi->desired_display.right);
939 		if (points >= 0.)
940 			print_info_set_margin_right (pi, points);
941 		break;
942 	case 4:
943 		xml_sax_print_margins_unit (xin, attrs,
944 					    &points, &pi->desired_display.top);
945 		if (points >= 0.)
946 			print_info_set_margin_header (pi, points);
947 		break;
948 	case 5:
949 		xml_sax_print_margins_unit (xin, attrs,
950 					    &points, &pi->desired_display.bottom);
951 		if (points >= 0.)
952 			print_info_set_margin_footer (pi, points);
953 		break;
954 	default:
955 		return;
956 	}
957 }
958 
959 
960 static void
xml_sax_page_break(GsfXMLIn * xin,xmlChar const ** attrs)961 xml_sax_page_break (GsfXMLIn *xin, xmlChar const **attrs)
962 {
963 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
964 	GnmPageBreakType  type = GNM_PAGE_BREAK_NONE;
965 	int pos = -1;
966 
967 	if (NULL == state->page_breaks)
968 		return;
969 
970 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
971 		if (gnm_xml_attr_int (attrs, "pos", &pos)) ;
972 		else if (!strcmp (CXML2C (attrs[0]), "type"))
973 			type = gnm_page_break_type_from_str (CXML2C (attrs[1]));
974 
975 	/* drops invalid positions */
976 	gnm_page_breaks_append_break (state->page_breaks, pos, type);
977 }
978 
979 static void
xml_sax_page_breaks_begin(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)980 xml_sax_page_breaks_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
981 {
982 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
983 	xml_sax_must_have_sheet (state);
984 	g_return_if_fail (state->page_breaks == NULL);
985 	state->page_breaks = gnm_page_breaks_new (xin->node->user_data.v_int);
986 }
987 
988 static void
xml_sax_page_breaks_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)989 xml_sax_page_breaks_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
990 {
991 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
992 
993 	if (NULL != state->page_breaks) {
994 		print_info_set_breaks (state->sheet->print_info,
995 			state->page_breaks);
996 		state->page_breaks = NULL;
997 	}
998 }
999 
1000 static void
xml_sax_print_scale(GsfXMLIn * xin,xmlChar const ** attrs)1001 xml_sax_print_scale (GsfXMLIn *xin, xmlChar const **attrs)
1002 {
1003 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1004 
1005 	GnmPrintInformation *pi;
1006 	double percentage;
1007 	int cols, rows;
1008 
1009 	xml_sax_must_have_sheet (state);
1010 
1011 	pi = state->sheet->print_info;
1012 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1013 		if (attr_eq (attrs[0], "type"))
1014 			pi->scaling.type = !strcmp (CXML2C (attrs[1]), "percentage")
1015 				? PRINT_SCALE_PERCENTAGE : PRINT_SCALE_FIT_PAGES;
1016 		else if (gnm_xml_attr_double (attrs, "percentage", &percentage))
1017 			pi->scaling.percentage.x = pi->scaling.percentage.y = percentage;
1018 		else if (gnm_xml_attr_int (attrs, "cols", &cols))
1019 			pi->scaling.dim.cols = cols;
1020 		else if (gnm_xml_attr_int (attrs, "rows", &rows))
1021 			pi->scaling.dim.rows = rows;
1022 	}
1023 }
1024 
1025 static void
xml_sax_print_vcenter(GsfXMLIn * xin,xmlChar const ** attrs)1026 xml_sax_print_vcenter (GsfXMLIn *xin, xmlChar const **attrs)
1027 {
1028 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1029 	GnmPrintInformation *pi;
1030 	int val;
1031 
1032 	xml_sax_must_have_sheet (state);
1033 
1034 	pi = state->sheet->print_info;
1035 
1036 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1037 		if (gnm_xml_attr_int (attrs, "value", &val))
1038 			pi->center_vertically = val;
1039 }
1040 
1041 static void
xml_sax_print_hcenter(GsfXMLIn * xin,xmlChar const ** attrs)1042 xml_sax_print_hcenter (GsfXMLIn *xin, xmlChar const **attrs)
1043 {
1044 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1045 	GnmPrintInformation *pi;
1046 	int val;
1047 
1048 	xml_sax_must_have_sheet (state);
1049 
1050 	pi = state->sheet->print_info;
1051 
1052 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1053 		if (gnm_xml_attr_int (attrs, "value", &val))
1054 			pi->center_horizontally = val;
1055 }
1056 
1057 static void
xml_sax_print_grid(GsfXMLIn * xin,xmlChar const ** attrs)1058 xml_sax_print_grid (GsfXMLIn *xin, xmlChar const **attrs)
1059 {
1060 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1061 	GnmPrintInformation *pi;
1062 	int val;
1063 
1064 	xml_sax_must_have_sheet (state);
1065 
1066 	pi = state->sheet->print_info;
1067 
1068 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1069 		if (gnm_xml_attr_int (attrs, "value", &val))
1070 			pi->print_grid_lines = val;
1071 }
1072 
1073 static void
xml_sax_print_do_not_print(GsfXMLIn * xin,xmlChar const ** attrs)1074 xml_sax_print_do_not_print (GsfXMLIn *xin, xmlChar const **attrs)
1075 {
1076         XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1077         GnmPrintInformation *pi;
1078         int val;
1079 
1080 	xml_sax_must_have_sheet (state);
1081 
1082 	pi = state->sheet->print_info;
1083 
1084         for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1085                 if (gnm_xml_attr_int (attrs, "value", &val))
1086                         pi->do_not_print = val;
1087 }
1088 
1089 static void
xml_sax_print_print_range(GsfXMLIn * xin,xmlChar const ** attrs)1090 xml_sax_print_print_range (GsfXMLIn *xin, xmlChar const **attrs)
1091 {
1092         XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1093         GnmPrintInformation *pi;
1094         int val;
1095 
1096 	xml_sax_must_have_sheet (state);
1097 
1098 	pi = state->sheet->print_info;
1099 
1100         for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1101 		if (xml_sax_attr_enum (attrs, "value", GNM_PRINT_RANGE_TYPE,
1102 				       &val))
1103                         print_info_set_printrange (pi, val);
1104 }
1105 
1106 
1107 
1108 static void
xml_sax_monochrome(GsfXMLIn * xin,xmlChar const ** attrs)1109 xml_sax_monochrome (GsfXMLIn *xin, xmlChar const **attrs)
1110 {
1111 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1112 	GnmPrintInformation *pi;
1113 	int val;
1114 
1115 	xml_sax_must_have_sheet (state);
1116 
1117 	pi = state->sheet->print_info;
1118 
1119 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1120 		if (gnm_xml_attr_int (attrs, "value", &val))
1121 			pi->print_black_and_white = val;
1122 }
1123 
1124 static void
xml_sax_print_titles(GsfXMLIn * xin,xmlChar const ** attrs)1125 xml_sax_print_titles (GsfXMLIn *xin, xmlChar const **attrs)
1126 {
1127 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1128 	GnmPrintInformation *pi;
1129 	int val;
1130 
1131 	xml_sax_must_have_sheet (state);
1132 
1133 	pi = state->sheet->print_info;
1134 
1135 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1136 		if (gnm_xml_attr_int (attrs, "value", &val))
1137 			pi->print_titles = val;
1138 }
1139 
1140 static void
xml_sax_repeat_top(GsfXMLIn * xin,xmlChar const ** attrs)1141 xml_sax_repeat_top (GsfXMLIn *xin, xmlChar const **attrs)
1142 {
1143 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1144 	GnmPrintInformation *pi;
1145 
1146 	xml_sax_must_have_sheet (state);
1147 
1148 	pi = state->sheet->print_info;
1149 
1150 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1151 		if (!strcmp (CXML2C (attrs[0]), "value")) {
1152 			g_free (pi->repeat_top);
1153 			pi->repeat_top = g_strdup (CXML2C (attrs[1]));
1154 			break;
1155 		}
1156 }
1157 
1158 static void
xml_sax_repeat_left(GsfXMLIn * xin,xmlChar const ** attrs)1159 xml_sax_repeat_left (GsfXMLIn *xin, xmlChar const **attrs)
1160 {
1161 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1162 	GnmPrintInformation *pi;
1163 
1164 	xml_sax_must_have_sheet (state);
1165 
1166 	pi = state->sheet->print_info;
1167 
1168 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1169 		if (!strcmp (CXML2C (attrs[0]), "value")) {
1170 			g_free (pi->repeat_left);
1171 			pi->repeat_left = g_strdup (CXML2C (attrs[1]));
1172 			break;
1173 		}
1174 }
1175 
1176 static void
xml_sax_print_hf(GsfXMLIn * xin,xmlChar const ** attrs)1177 xml_sax_print_hf (GsfXMLIn *xin, xmlChar const **attrs)
1178 {
1179 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1180 	GnmPrintInformation *pi;
1181 	GnmPrintHF *hf;
1182 
1183 	xml_sax_must_have_sheet (state);
1184 
1185 	pi = state->sheet->print_info;
1186 
1187 	switch (xin->node->user_data.v_int) {
1188 	case 0:
1189 		hf = pi->footer;
1190 		break;
1191 	case 1:
1192 		hf = pi->header;
1193 		break;
1194 	default:
1195 		return;
1196 	}
1197 
1198 	g_return_if_fail (hf != NULL);
1199 
1200 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1201 		if ( attr_eq (attrs[0], "Left")) {
1202 			g_free (hf->left_format);
1203 			hf->left_format = g_strdup (CXML2C (attrs[1]));
1204 		} else if (attr_eq (attrs[0], "Middle")) {
1205 			g_free (hf->middle_format);
1206 			hf->middle_format = g_strdup (CXML2C (attrs[1]));
1207 		} else if (attr_eq (attrs[0], "Right")) {
1208 			g_free (hf->right_format);
1209 			hf->right_format = g_strdup (CXML2C (attrs[1]));
1210 		} else
1211 			unknown_attr (xin, attrs);
1212 	}
1213 }
1214 
1215 
1216 static void
xml_sax_even_if_only_styles(GsfXMLIn * xin,xmlChar const ** attrs)1217 xml_sax_even_if_only_styles (GsfXMLIn *xin, xmlChar const **attrs)
1218 {
1219 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1220 	GnmPrintInformation *pi;
1221 	int val;
1222 
1223 	xml_sax_must_have_sheet (state);
1224 
1225 	pi = state->sheet->print_info;
1226 
1227 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1228 		if (gnm_xml_attr_int (attrs, "value", &val))
1229 			pi->print_even_if_only_styles = val;
1230 }
1231 
1232 
1233 
1234 
1235 static void
xml_sax_selection_range(GsfXMLIn * xin,xmlChar const ** attrs)1236 xml_sax_selection_range (GsfXMLIn *xin, xmlChar const **attrs)
1237 {
1238 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1239 	GnmRange r;
1240 
1241 	xml_sax_must_have_sheet (state);
1242 	if (xml_sax_attr_range (attrs, &r))
1243 		sv_selection_add_range (
1244 			sheet_get_view (state->sheet, state->wb_view), &r);
1245 }
1246 
1247 static void
xml_sax_selection(GsfXMLIn * xin,xmlChar const ** attrs)1248 xml_sax_selection (GsfXMLIn *xin, xmlChar const **attrs)
1249 {
1250 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1251 	Sheet *sheet = xml_sax_must_have_sheet (state);
1252 	int col = -1, row = -1;
1253 
1254 	sv_selection_reset (sheet_get_view (sheet, state->wb_view));
1255 
1256 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1257 		if (gnm_xml_attr_int (attrs, "CursorCol", &col)) ;
1258 		else if (gnm_xml_attr_int (attrs, "CursorRow", &row)) ;
1259 		else
1260 			unknown_attr (xin, attrs);
1261 
1262 	XML_CHECK (state->cell.col < 0);
1263 	XML_CHECK (state->cell.row < 0);
1264 
1265 	/* Default in case of error.  */
1266 	state->cell.col = 0;
1267 	state->cell.row = 0;
1268 
1269 	XML_CHECK (col >= 0 && col < gnm_sheet_get_max_cols (sheet));
1270 	XML_CHECK (row >= 0 && row < gnm_sheet_get_max_rows (sheet));
1271 
1272 	state->cell.col = col;
1273 	state->cell.row = row;
1274 }
1275 
1276 static void
xml_sax_selection_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1277 xml_sax_selection_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1278 {
1279 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1280 
1281 	GnmCellPos const pos = state->cell;
1282 	state->cell.col = state->cell.row = -1;
1283 	gnm_sheet_view_set_edit_pos (sheet_get_view (state->sheet, state->wb_view), &pos);
1284 }
1285 
1286 static void
xml_sax_sheet_layout(GsfXMLIn * xin,xmlChar const ** attrs)1287 xml_sax_sheet_layout (GsfXMLIn *xin, xmlChar const **attrs)
1288 {
1289 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1290 	GnmCellPos tmp;
1291 
1292 	xml_sax_must_have_sheet (state);
1293 
1294 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1295 		if (xml_sax_attr_cellpos (attrs, "TopLeft", &tmp, state->sheet))
1296 			gnm_sheet_view_set_initial_top_left (
1297 				sheet_get_view (state->sheet, state->wb_view),
1298 				tmp.col, tmp.row);
1299 		else
1300 			unknown_attr (xin, attrs);
1301 }
1302 
1303 static void
xml_sax_sheet_freezepanes(GsfXMLIn * xin,xmlChar const ** attrs)1304 xml_sax_sheet_freezepanes (GsfXMLIn *xin, xmlChar const **attrs)
1305 {
1306 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1307 	GnmCellPos frozen_tl, unfrozen_tl;
1308 	int flags = 0;
1309 
1310 	xml_sax_must_have_sheet (state);
1311 
1312 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1313 		if (xml_sax_attr_cellpos (attrs, "FrozenTopLeft", &frozen_tl, state->sheet))
1314 			flags |= 1;
1315 		else if (xml_sax_attr_cellpos (attrs, "UnfrozenTopLeft", &unfrozen_tl, state->sheet))
1316 			flags |= 2;
1317 		else
1318 			unknown_attr (xin, attrs);
1319 
1320 	if (flags == 3)
1321 		gnm_sheet_view_freeze_panes (sheet_get_view (state->sheet, state->wb_view),
1322 			&frozen_tl, &unfrozen_tl);
1323 }
1324 
1325 static void
xml_sax_cols_rows(GsfXMLIn * xin,xmlChar const ** attrs)1326 xml_sax_cols_rows (GsfXMLIn *xin, xmlChar const **attrs)
1327 {
1328 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1329 	double def_size;
1330 	gboolean const is_col = xin->node->user_data.v_bool;
1331 
1332 	xml_sax_must_have_sheet (state);
1333 
1334 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1335 		if (gnm_xml_attr_double (attrs, "DefaultSizePts", &def_size)) {
1336 			if (is_col)
1337 				sheet_col_set_default_size_pts (state->sheet, def_size);
1338 			else
1339 				sheet_row_set_default_size_pts (state->sheet, def_size);
1340 		}
1341 }
1342 
1343 static void
xml_sax_colrow(GsfXMLIn * xin,xmlChar const ** attrs)1344 xml_sax_colrow (GsfXMLIn *xin, xmlChar const **attrs)
1345 {
1346 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1347 
1348 	ColRowInfo *cri = NULL;
1349 	double size = -1.;
1350 	int pos = -1, val;
1351 	int hidden = 0, hard_size = 0, is_collapsed = 0, outline_level = 0;
1352 	int count = 1;
1353 	gboolean const is_col = xin->node->user_data.v_bool;
1354 	Sheet *sheet = xml_sax_must_have_sheet (state);
1355 
1356 	maybe_update_progress (xin);
1357 
1358 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1359 		if (gnm_xml_attr_int (attrs, "No", &pos)) ;
1360 		else if (gnm_xml_attr_double (attrs, "Unit", &size)) ;
1361 		else if (gnm_xml_attr_int (attrs, "Count", &count)) ;
1362 		else if (gnm_xml_attr_int (attrs, "HardSize", &hard_size)) ;
1363 		else if (gnm_xml_attr_int (attrs, "Hidden", &hidden)) ;
1364 		else if (gnm_xml_attr_int (attrs, "Collapsed", &is_collapsed)) ;
1365 		else if (gnm_xml_attr_int (attrs, "OutlineLevel", &outline_level)) ;
1366 		else if (gnm_xml_attr_int (attrs, "MarginA", &val))
1367 			; /* deprecated in 1.7.1 */
1368 		else if (gnm_xml_attr_int (attrs, "MarginB", &val))
1369 			; /* deprecated in 1.7.1 */
1370 		else
1371 			unknown_attr (xin, attrs);
1372 	}
1373 
1374 	XML_CHECK (size > -1);
1375 	XML_CHECK (pos >= 0 && pos < colrow_max (is_col, sheet));
1376 	XML_CHECK (count >= 1);
1377 	XML_CHECK (count <= colrow_max (is_col, sheet) - pos);
1378 
1379 	cri = is_col
1380 		? sheet_col_fetch (state->sheet, pos)
1381 		: sheet_row_fetch (state->sheet, pos);
1382 	cri->hard_size = hard_size;
1383 	cri->visible = !hidden;
1384 	cri->is_collapsed = is_collapsed;
1385 	cri->outline_level = outline_level;
1386 
1387 	if (is_col) {
1388 		sheet_col_set_size_pts (state->sheet, pos, size, cri->hard_size);
1389 		if (state->sheet->cols.max_outline_level < cri->outline_level)
1390 			state->sheet->cols.max_outline_level = cri->outline_level;
1391 		/* resize flags are already set only need to copy the sizes */
1392 		while (--count > 0)
1393 			col_row_info_copy (sheet_col_fetch (state->sheet, ++pos), cri);
1394 	} else {
1395 		sheet_row_set_size_pts (state->sheet, pos, size, cri->hard_size);
1396 		if (state->sheet->rows.max_outline_level < cri->outline_level)
1397 			state->sheet->rows.max_outline_level = cri->outline_level;
1398 		/* resize flags are already set only need to copy the sizes */
1399 		while (--count > 0)
1400 			col_row_info_copy (sheet_row_fetch (state->sheet, ++pos), cri);
1401 	}
1402 }
1403 
1404 static void
xml_sax_style_region_start(GsfXMLIn * xin,xmlChar const ** attrs)1405 xml_sax_style_region_start (GsfXMLIn *xin, xmlChar const **attrs)
1406 {
1407 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1408 
1409 	g_return_if_fail (state->style_range_init == FALSE);
1410 	g_return_if_fail (state->style == NULL);
1411 
1412 	if (attrs == NULL) {
1413 		g_warning ("Invalid tag: gnm:StyleRegion start tag without attributes");
1414 		return;
1415 	}
1416 
1417 	state->style = (state->version >= GNM_XML_V6 ||
1418 			state->version <= GNM_XML_V2)
1419 		? gnm_style_new_default ()
1420 		: gnm_style_new ();
1421 
1422 	state->style_range_init =
1423 		xml_sax_attr_range (attrs, &state->style_range);
1424 }
1425 
1426 static void
xml_sax_style_region_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1427 xml_sax_style_region_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1428 {
1429 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1430 
1431 	if (!state->style_range_init) {
1432 		xml_sax_barf (G_STRFUNC, "style region must have range");
1433 		range_init (&state->style_range, 0, 0, 0, 0);
1434 		state->style_range_init = TRUE;
1435 	}
1436 
1437 	xml_sax_must_have_style (state);
1438 	xml_sax_must_have_sheet (state);
1439 
1440 	if (state->clipboard) {
1441 		GnmCellRegion *cr = state->clipboard;
1442 		GnmStyleRegion *sr = g_new (GnmStyleRegion, 1);
1443 
1444 		sr->range = state->style_range;
1445 		sr->style = state->style;
1446 
1447 		cr->styles = g_slist_prepend (cr->styles, sr);
1448 	} else if (state->version >= GNM_XML_V6 || state->version <= GNM_XML_V2)
1449 		sheet_style_set_range (state->sheet, &state->style_range,
1450 				       state->style);
1451 	else
1452 		sheet_style_apply_range (state->sheet, &state->style_range,
1453 					 state->style);
1454 
1455 	state->style_range_init = FALSE;
1456 	state->style = NULL;
1457 
1458 	maybe_update_progress (xin);
1459 }
1460 
1461 static void
xml_sax_style_start(GsfXMLIn * xin,xmlChar const ** attrs)1462 xml_sax_style_start (GsfXMLIn *xin, xmlChar const **attrs)
1463 {
1464 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1465 
1466 	int val;
1467 	GnmColor *colour;
1468 
1469 	xml_sax_must_have_style (state);
1470 
1471 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1472 		if (xml_sax_attr_enum (attrs, "HAlign", GNM_ALIGN_H_TYPE, &val))
1473 			gnm_style_set_align_h (state->style, val);
1474 		else if (xml_sax_attr_enum (attrs, "VAlign", GNM_ALIGN_V_TYPE, &val))
1475 			gnm_style_set_align_v (state->style, val);
1476 
1477 		/* Pre version V6 */
1478 		else if (gnm_xml_attr_int (attrs, "Fit", &val))
1479 			gnm_style_set_wrap_text (state->style, val);
1480 
1481 		else if (gnm_xml_attr_int (attrs, "WrapText", &val))
1482 			gnm_style_set_wrap_text (state->style, val);
1483 		else if (gnm_xml_attr_bool (attrs, "ShrinkToFit", &val))
1484 			gnm_style_set_shrink_to_fit (state->style, val);
1485 		else if (gnm_xml_attr_int (attrs, "Rotation", &val)) {
1486 			/* Work around a bug pre 1.5.1 that would allow
1487 			 * negative rotations.  -1 == vertical, map everything
1488 			 * else back onto 0..359 */
1489 			if (val < -1)
1490 				val += 360;
1491 			gnm_style_set_rotation (state->style, val);
1492 		} else if (gnm_xml_attr_int (attrs, "Shade", &val))
1493 			gnm_style_set_pattern (state->style, val);
1494 		else if (gnm_xml_attr_int (attrs, "Indent", &val))
1495 			gnm_style_set_indent (state->style, val);
1496 		else if (xml_sax_attr_color (attrs, "Fore", &colour))
1497 			gnm_style_set_font_color (state->style, colour);
1498 		else if (xml_sax_attr_color (attrs, "Back", &colour))
1499 			gnm_style_set_back_color (state->style, colour);
1500 		else if (xml_sax_attr_color (attrs, "PatternColor", &colour))
1501 			gnm_style_set_pattern_color (state->style, colour);
1502 		else if (attr_eq (attrs[0], "Format")) {
1503 			GOFormat *fmt = make_format (CXML2C (attrs[1]));
1504 			if (fmt) {
1505 				gnm_style_set_format (state->style, fmt);
1506 				go_format_unref (fmt);
1507 			}
1508 		}
1509 		else if (gnm_xml_attr_int (attrs, "Hidden", &val))
1510 			gnm_style_set_contents_hidden (state->style, val);
1511 		else if (gnm_xml_attr_int (attrs, "Locked", &val))
1512 			gnm_style_set_contents_locked (state->style, val);
1513 		else if (gnm_xml_attr_int (attrs, "Orient", &val))
1514 			; /* ignore old useless attribute */
1515 		else
1516 			unknown_attr (xin, attrs);
1517 	}
1518 }
1519 
1520 static void
xml_sax_style_font(GsfXMLIn * xin,xmlChar const ** attrs)1521 xml_sax_style_font (GsfXMLIn *xin, xmlChar const **attrs)
1522 {
1523 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1524 
1525 	double size_pts = 10.;
1526 	int val;
1527 
1528 	xml_sax_must_have_style (state);
1529 
1530 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1531 		if (gnm_xml_attr_double (attrs, "Unit", &size_pts)) {
1532 			if (!(size_pts >= 1.0))
1533 				xml_sax_barf (G_STRFUNC, "size_pts >= 1");
1534 			else
1535 				gnm_style_set_font_size (state->style, size_pts);
1536 		} else if (gnm_xml_attr_int (attrs, "Bold", &val))
1537 			gnm_style_set_font_bold (state->style, val);
1538 		else if (gnm_xml_attr_int (attrs, "Italic", &val))
1539 			gnm_style_set_font_italic (state->style, val);
1540 		else if (gnm_xml_attr_int (attrs, "Underline", &val))
1541 			gnm_style_set_font_uline (state->style, (GnmUnderline)val);
1542 		else if (gnm_xml_attr_int (attrs, "StrikeThrough", &val))
1543 			gnm_style_set_font_strike (state->style, val);
1544 		else if (gnm_xml_attr_int (attrs, "Script", &val)) {
1545 			if (val == 0)
1546 				gnm_style_set_font_script (state->style, GO_FONT_SCRIPT_STANDARD);
1547 			else if (val < 0)
1548 				gnm_style_set_font_script (state->style, GO_FONT_SCRIPT_SUB);
1549 			else
1550 				gnm_style_set_font_script (state->style, GO_FONT_SCRIPT_SUPER);
1551 		} else
1552 			unknown_attr (xin, attrs);
1553 	}
1554 }
1555 
1556 static char const *
font_component(char const * fontname,int idx)1557 font_component (char const *fontname, int idx)
1558 {
1559 	int i = 0;
1560 	char const *p = fontname;
1561 
1562 	for (; *p && i < idx; p++) {
1563 		if (*p == '-')
1564 			i++;
1565 	}
1566 	if (*p == '-')
1567 		p++;
1568 
1569 	return p;
1570 }
1571 
1572 /**
1573  * style_font_read_from_x11:
1574  * @mstyle: the style to setup to this font.
1575  * @fontname: an X11-like font name.
1576  *
1577  * Tries to guess the fontname, the weight and italization parameters
1578  * and setup mstyle
1579  *
1580  * Returns: A valid style font.
1581  */
1582 static void
style_font_read_from_x11(GnmStyle * mstyle,char const * fontname)1583 style_font_read_from_x11 (GnmStyle *mstyle, char const *fontname)
1584 {
1585 	char const *c;
1586 
1587 	/* FIXME: we should do something about the typeface instead
1588 	 * of hardcoding it to helvetica.
1589 	 */
1590 	c = font_component (fontname, 2);
1591 	if (strncmp (c, "bold", 4) == 0)
1592 		gnm_style_set_font_bold (mstyle, TRUE);
1593 
1594 	c = font_component (fontname, 3);
1595 	if (strncmp (c, "o", 1) == 0)
1596 		gnm_style_set_font_italic (mstyle, TRUE);
1597 
1598 	if (strncmp (c, "i", 1) == 0)
1599 		gnm_style_set_font_italic (mstyle, TRUE);
1600 }
1601 
1602 static void
xml_sax_style_font_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1603 xml_sax_style_font_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1604 {
1605 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1606 
1607 	xml_sax_must_have_style (state);
1608 
1609 	if (xin->content->len > 0) {
1610 		char const * content = xin->content->str;
1611 		if (*content == '-')
1612 			style_font_read_from_x11 (state->style, content);
1613 		else
1614 			gnm_style_set_font_name (state->style, content);
1615 	}
1616 }
1617 
1618 static void
xml_sax_validation(GsfXMLIn * xin,xmlChar const ** attrs)1619 xml_sax_validation (GsfXMLIn *xin, xmlChar const **attrs)
1620 {
1621 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1622 
1623 	int dummy;
1624 	gboolean b_dummy;
1625 
1626 	g_return_if_fail (state->validation.title == NULL);
1627 	g_return_if_fail (state->validation.msg == NULL);
1628 	g_return_if_fail (state->validation.texpr[0] == NULL);
1629 	g_return_if_fail (state->validation.texpr[1] == NULL);
1630 
1631 	state->validation.style = GNM_VALIDATION_STYLE_NONE;
1632 	state->validation.type = GNM_VALIDATION_TYPE_ANY;
1633 	state->validation.op = GNM_VALIDATION_OP_NONE;
1634 	state->validation.allow_blank = TRUE;
1635 	state->validation.use_dropdown = FALSE;
1636 
1637 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1638 		if (xml_sax_attr_enum (attrs, "Style",
1639 				       GNM_VALIDATION_STYLE_TYPE,
1640 				       &dummy)) {
1641 			state->validation.style = dummy;
1642 		} else if (xml_sax_attr_enum (attrs, "Type",
1643 					      GNM_VALIDATION_TYPE_TYPE,
1644 					      &dummy)) {
1645 			state->validation.type = dummy;
1646 		} else if (xml_sax_attr_enum (attrs, "Operator",
1647 					      GNM_VALIDATION_OP_TYPE,
1648 					      &dummy)) {
1649 			state->validation.op = dummy;
1650 		} else if (attr_eq (attrs[0], "Title")) {
1651 			state->validation.title = g_strdup (CXML2C (attrs[1]));
1652 		} else if (attr_eq (attrs[0], "Message")) {
1653 			state->validation.msg = g_strdup (CXML2C (attrs[1]));
1654 		} else if (gnm_xml_attr_bool (attrs, "AllowBlank", &b_dummy)) {
1655 			state->validation.allow_blank = b_dummy;
1656 		} else if (gnm_xml_attr_bool (attrs, "UseDropdown", &b_dummy)) {
1657 			state->validation.use_dropdown = b_dummy;
1658 		} else
1659 			unknown_attr (xin, attrs);
1660 	}
1661 }
1662 
1663 static void
xml_sax_validation_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1664 xml_sax_validation_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1665 {
1666 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1667 
1668 	xml_sax_must_have_style (state);
1669 
1670 	gnm_style_set_validation (state->style,
1671 		gnm_validation_new (state->validation.style,
1672 				state->validation.type,
1673 				state->validation.op,
1674 				state->sheet,
1675 				state->validation.title,
1676 				state->validation.msg,
1677 				state->validation.texpr[0],
1678 				state->validation.texpr[1],
1679 				state->validation.allow_blank,
1680 				state->validation.use_dropdown));
1681 
1682 	g_free (state->validation.title);
1683 	state->validation.title = NULL;
1684 	g_free (state->validation.msg);
1685 	state->validation.msg = NULL;
1686 	state->validation.texpr[0] = state->validation.texpr[1] = NULL;
1687 }
1688 
1689 static void
xml_sax_validation_expr_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1690 xml_sax_validation_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1691 {
1692 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1693 
1694 	int const i = xin->node->user_data.v_int;
1695 	GnmExprTop const *texpr;
1696 	GnmParsePos pos;
1697 
1698 	g_return_if_fail (state->validation.texpr[i] == NULL);
1699 
1700 	texpr = gnm_expr_parse_str (xin->content->str,
1701 				    parse_pos_init_sheet (&pos, state->sheet),
1702 				    GNM_EXPR_PARSE_DEFAULT,
1703 				    state->convs,
1704 				    NULL);
1705 
1706 	g_return_if_fail (texpr != NULL);
1707 
1708 	state->validation.texpr[i] = texpr;
1709 }
1710 
1711 static void
xml_sax_condition(GsfXMLIn * xin,xmlChar const ** attrs)1712 xml_sax_condition (GsfXMLIn *xin, xmlChar const **attrs)
1713 {
1714 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1715 	GnmStyleCondOp op = GNM_STYLE_COND_CUSTOM;
1716 
1717 	g_return_if_fail (state->cond == NULL);
1718 	g_return_if_fail (state->cond_save_style == NULL);
1719 
1720 	xml_sax_must_have_style (state);
1721 
1722 	state->cond_save_style = state->style;
1723 	state->style = gnm_style_new ();
1724 
1725 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1726 		int dummy;
1727 
1728 		if (gnm_xml_attr_int (attrs, "Operator", &dummy))
1729 			op = dummy;
1730 		else
1731 			unknown_attr (xin, attrs);
1732 	}
1733 
1734 	state->cond = gnm_style_cond_new (op, state->sheet);
1735 }
1736 
1737 static void
xml_sax_condition_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1738 xml_sax_condition_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1739 {
1740 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1741 	GnmStyleConditions *sc;
1742 
1743 	xml_sax_must_have_style (state);
1744 	g_return_if_fail (state->cond_save_style != NULL);
1745 	g_return_if_fail (state->cond != NULL);
1746 
1747 	gnm_style_cond_set_overlay (state->cond, state->style);
1748 	gnm_style_unref (state->style);
1749 	state->style = state->cond_save_style;
1750 	state->cond_save_style = NULL;
1751 
1752 	if (!gnm_style_is_element_set (state->style, MSTYLE_CONDITIONS) ||
1753 	    NULL == (sc = gnm_style_get_conditions (state->style)))
1754 		gnm_style_set_conditions (state->style,
1755 			(sc = gnm_style_conditions_new (state->sheet)));
1756 	gnm_style_conditions_insert (sc, state->cond, -1);
1757 
1758 	gnm_style_cond_free (state->cond);
1759 	state->cond = NULL;
1760 }
1761 
1762 /*
1763  * We have been saving expressions relative to A1.  This means that when we
1764  * read, we see a relative reference to a cell above as R[65535]C.  This
1765  * function patches that to R[-1]C.
1766  *
1767  * We ought to fix the format, but then old Gnumerics couldn't read new
1768  * files.  In fact, if we just added a "Position" attribute then we would
1769  * get silent corruption.
1770  */
1771 static GnmExpr const *
cond_patchup(GnmExpr const * expr,GnmExprWalk * data)1772 cond_patchup (GnmExpr const *expr, GnmExprWalk *data)
1773 {
1774 	XMLSaxParseState *state = data->user;
1775 	GnmCellPos const *pos = &state->style_range.start;
1776 	GnmCellRef const *oref = gnm_expr_get_cellref (expr);
1777 	GnmValue const *ocst = gnm_expr_get_constant (expr);
1778 
1779 	if (oref) {
1780 		GnmCellPos tpos;
1781 		GnmCellRef tref = *oref;
1782 		gnm_cellpos_init_cellref (&tpos, oref, pos, state->sheet);
1783 		if (tref.col_relative)
1784 			tref.col = tpos.col - pos->col;
1785 		if (tref.row_relative)
1786 			tref.row = tpos.row - pos->row;
1787 		if (gnm_cellref_equal (&tref, oref))
1788 			return NULL;
1789 		return gnm_expr_new_cellref (&tref);
1790 	}
1791 
1792 	if (ocst && VALUE_IS_CELLRANGE (ocst)) {
1793 		GnmRangeRef const *oref = value_get_rangeref (ocst);
1794 		GnmRangeRef tref = *oref;
1795 		GnmRange trange;
1796 		Sheet *start_sheet, *end_sheet;
1797 		GnmEvalPos ep;
1798 
1799 		eval_pos_init_pos (&ep, state->sheet, pos);
1800 		gnm_rangeref_normalize (oref, &ep, &start_sheet, &end_sheet,
1801 					&trange);
1802 		if (tref.a.col_relative)
1803 			tref.a.col = trange.start.col - pos->col;
1804 		if (tref.a.row_relative)
1805 			tref.a.row = trange.start.row - pos->row;
1806 		if (tref.b.col_relative)
1807 			tref.b.col = trange.end.col - pos->col;
1808 		if (tref.b.row_relative)
1809 			tref.b.row = trange.end.row - pos->row;
1810 		if (gnm_rangeref_equal (&tref, oref))
1811 			return NULL;
1812 		return gnm_expr_new_constant (value_new_cellrange_unsafe (&tref.a, &tref.b));
1813 	}
1814 
1815 	return NULL;
1816 }
1817 
1818 static void
xml_sax_condition_expr_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)1819 xml_sax_condition_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1820 {
1821 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1822 
1823 	int const i = xin->node->user_data.v_int;
1824 	GnmExprTop const *texpr;
1825 	GnmParsePos pos;
1826 	GnmExpr const *patched_expr;
1827 
1828 	g_return_if_fail (gnm_style_cond_get_expr (state->cond, i) == NULL);
1829 
1830 	parse_pos_init_sheet (&pos, state->sheet);
1831 	texpr = gnm_expr_parse_str (xin->content->str,
1832 				    &pos,
1833 				    GNM_EXPR_PARSE_DEFAULT,
1834 				    state->convs,
1835 				    NULL);
1836 	g_return_if_fail (texpr != NULL);
1837 
1838 	patched_expr = gnm_expr_walk (texpr->expr, cond_patchup, state);
1839 	if (patched_expr) {
1840 		gnm_expr_top_unref (texpr);
1841 		texpr = gnm_expr_top_new (patched_expr);
1842 	}
1843 
1844 	gnm_style_cond_set_expr (state->cond, texpr, i);
1845 	gnm_expr_top_unref (texpr);
1846 }
1847 
1848 static void
xml_sax_hlink(GsfXMLIn * xin,xmlChar const ** attrs)1849 xml_sax_hlink (GsfXMLIn *xin, xmlChar const **attrs)
1850 {
1851 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1852 	char *type = NULL;
1853 	char *target = NULL;
1854 	char *tip = NULL;
1855 
1856 	xml_sax_must_have_style (state);
1857 
1858 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1859 		if (attr_eq (attrs[0], "type"))
1860 			type = g_strdup (CXML2C (attrs[1]));
1861 		else if (attr_eq (attrs[0], "target"))
1862 			target = g_strdup (CXML2C (attrs[1]));
1863 		else if (attr_eq (attrs[0], "tip"))
1864 			tip = g_strdup (CXML2C (attrs[1]));
1865 		else
1866 			unknown_attr (xin, attrs);
1867 	}
1868 
1869 	if (NULL != type && NULL != target) {
1870 		GType typ = g_type_from_name (type);
1871 		GnmHLink *lnk = gnm_hlink_new (typ, state->sheet);
1872 		gnm_hlink_set_target (lnk, target);
1873 		gnm_hlink_set_tip (lnk, tip);
1874 		gnm_style_set_hlink (state->style, lnk);
1875 	}
1876 
1877 	g_free (type);
1878 	g_free (target);
1879 	g_free (tip);
1880 }
1881 
1882 static void
xml_sax_input_msg(GsfXMLIn * xin,xmlChar const ** attrs)1883 xml_sax_input_msg (GsfXMLIn *xin, xmlChar const **attrs)
1884 {
1885 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1886 	char *title = NULL;
1887 	char *msg = NULL;
1888 
1889 	xml_sax_must_have_style (state);
1890 
1891 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1892 		if (attr_eq (attrs[0], "Title"))
1893 			title = g_strdup (CXML2C (attrs[1]));
1894 		else if (attr_eq (attrs[0], "Message"))
1895 			msg = g_strdup (CXML2C (attrs[1]));
1896 		else
1897 			unknown_attr (xin, attrs);
1898 	}
1899 
1900 	if (NULL != title || NULL != msg)
1901 		gnm_style_set_input_msg (state->style,
1902 			gnm_input_msg_new (msg, title));
1903 	g_free (title);
1904 	g_free (msg);
1905 }
1906 
1907 static void
xml_sax_style_border(GsfXMLIn * xin,xmlChar const ** attrs)1908 xml_sax_style_border (GsfXMLIn *xin, xmlChar const **attrs)
1909 {
1910 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1911 
1912 	int pattern = -1;
1913 	GnmColor *colour = NULL;
1914 
1915 	xml_sax_must_have_style (state);
1916 
1917 	/* Colour is optional */
1918 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1919 		if (xml_sax_attr_color (attrs, "Color", &colour)) ;
1920 		else if (gnm_xml_attr_int (attrs, "Style", &pattern)) ;
1921 		else
1922 			unknown_attr (xin, attrs);
1923 	}
1924 
1925 	if (pattern >= GNM_STYLE_BORDER_NONE) {
1926 		GnmStyleElement const type = xin->node->user_data.v_int;
1927 		GnmStyleBorderLocation const loc =
1928 			GNM_STYLE_BORDER_TOP + (int)(type - MSTYLE_BORDER_TOP);
1929 		GnmBorder *border;
1930 
1931 		/*
1932 		 * Make sure we have a colour to prevent trouble further
1933 		 * down the line.
1934 		 */
1935 		if (!colour)
1936 			colour = gnm_color_new_go (GO_COLOR_BLACK);
1937 
1938 		border = gnm_style_border_fetch
1939 			((GnmStyleBorderType)pattern, colour,
1940 			 gnm_style_border_get_orientation (loc));
1941 		gnm_style_set_border (state->style, type, border);
1942 	}
1943 }
1944 
1945 static void
xml_sax_cell(GsfXMLIn * xin,xmlChar const ** attrs)1946 xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
1947 {
1948 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1949 	int row = -1, col = -1;
1950 	int rows = -1, cols = -1;
1951 	int value_type = -1;
1952 	GOFormat *value_fmt = NULL;
1953 	int expr_id = -1;
1954 	const char *value_result = NULL;
1955 
1956 	g_return_if_fail (state->cell.row == -1);
1957 	g_return_if_fail (state->cell.col == -1);
1958 	g_return_if_fail (state->array_rows == -1);
1959 	g_return_if_fail (state->array_cols == -1);
1960 	g_return_if_fail (state->expr_id == -1);
1961 	g_return_if_fail (state->value_type == -1);
1962 	g_return_if_fail (state->value_result == NULL);
1963 
1964 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1965 		if (gnm_xml_attr_int (attrs, "Col", &col)) ;
1966 		else if (gnm_xml_attr_int (attrs, "Row", &row)) ;
1967 		else if (gnm_xml_attr_int (attrs, "Cols", &cols)) ;
1968 		else if (gnm_xml_attr_int (attrs, "Rows", &rows)) ;
1969 		else if (gnm_xml_attr_int (attrs, "ExprID", &expr_id)) ;
1970 		else if (gnm_xml_attr_int (attrs, "ValueType", &value_type)) ;
1971 		else if (attr_eq (attrs[0], "Value"))
1972 			value_result = CXML2C (attrs[1]);
1973 		else if (attr_eq (attrs[0], "ValueFormat")) {
1974 			go_format_unref (value_fmt);
1975 			value_fmt = make_format (CXML2C (attrs[1]));
1976 		} else
1977 			unknown_attr (xin, attrs);
1978 	}
1979 
1980 	// Ignore value_result absent a type
1981 	if (value_type == -1)
1982 		value_result = NULL;
1983 
1984 	XML_CHECK2 (col >= 0 && col <= GNM_MAX_COLS - MAX (1, cols),
1985 		    go_format_unref (value_fmt));
1986 	XML_CHECK2 (row >= 0 && row <= GNM_MAX_ROWS - MAX (1, rows),
1987 		    go_format_unref (value_fmt));
1988 
1989 	if (cols > 0 || rows > 0) {
1990 		/* Both must be valid */
1991 		XML_CHECK2 (cols > 0 && rows > 0,
1992 			    go_format_unref (value_fmt));
1993 
1994 		state->array_cols = cols;
1995 		state->array_rows = rows;
1996 	}
1997 
1998 	state->cell.row = row;
1999 	state->cell.col = col;
2000 	state->expr_id = expr_id;
2001 	state->value_type = value_type;
2002 	state->value_fmt = value_fmt;
2003 	state->value_result = g_strdup (value_result);
2004 }
2005 
2006 /*
2007  * xml_cell_set_array_expr : Utility routine to parse an expression
2008  *     and store it as an array.
2009  *
2010  * @cell: The upper left hand corner of the array.
2011  * @text: The text to parse.
2012  * @rows: The number of rows.
2013  * @cols: The number of columns.
2014  */
2015 static void
xml_cell_set_array_expr(XMLSaxParseState * state,GnmCell * cell,GnmCellCopy * cc,char const * text,int const cols,int const rows)2016 xml_cell_set_array_expr (XMLSaxParseState *state,
2017 			 GnmCell *cell, GnmCellCopy *cc, char const *text,
2018 			 int const cols, int const rows)
2019 {
2020 	GnmParsePos pp;
2021 	GnmExprTop const *texpr =
2022 		gnm_expr_parse_str (text,
2023 				    parse_pos_init_cell (&pp, cell),
2024 				    GNM_EXPR_PARSE_DEFAULT,
2025 				    state->convs,
2026 				    NULL);
2027 	GnmRange r;
2028 
2029 	g_return_if_fail (texpr != NULL);
2030 
2031 	if (!cell) {
2032 		cc->texpr = texpr;
2033 		return;
2034 	}
2035 
2036 	r.start = r.end = cell->pos;
2037 	r.end.col += (cols - 1);
2038 	r.end.row += (rows - 1);
2039 
2040 	if (!gnm_cell_set_array (cell->base.sheet, &r, texpr)) {
2041 		xml_sax_barf (G_STRFUNC, "target area empty");
2042 	}
2043 
2044 	gnm_expr_top_unref (texpr);
2045 }
2046 
2047 /*
2048  * xml_not_used_old_array_spec : See if the string corresponds to
2049  *     a pre-0.53 style array expression.
2050  *     If it is the upper left corner	 - assign it.
2051  *     If it is a member of an array     - ignore it; the corner will assign it.
2052  *     If it is not a member of an array return TRUE.
2053  */
2054 static gboolean
xml_not_used_old_array_spec(XMLSaxParseState * state,GnmCell * cell,GnmCellCopy * cc,char const * content)2055 xml_not_used_old_array_spec (XMLSaxParseState *state,
2056 			     GnmCell *cell, GnmCellCopy *cc,
2057 			     char const *content)
2058 {
2059 	long rows, cols, row, col;
2060 	char *end, *expr_end, *ptr;
2061 
2062 	/* This is the syntax we are trying to parse: "{%s}(%d,%d)[%d][%d]" */
2063 
2064 	if (content[0] != '=' || content[1] != '{')
2065 		return TRUE;
2066 
2067 	expr_end = strrchr (content, '}');
2068 	if (expr_end == NULL || expr_end[1] != '(')
2069 		return TRUE;
2070 
2071 	rows = strtol (ptr = expr_end + 2, &end, 10);
2072 	if (end == ptr || *end != ',')
2073 		return TRUE;
2074 	cols = strtol (ptr = end + 1, &end, 10);
2075 	if (end == ptr || end[0] != ')' || end[1] != '[')
2076 		return TRUE;
2077 	row = strtol (ptr = end + 2, &end, 10);
2078 	if (end == ptr || end[0] != ']' || end[1] != '[')
2079 		return TRUE;
2080 	col = strtol (ptr = end + 2, &end, 10);
2081 	if (end == ptr || end[0] != ']' || end[1] != '\0')
2082 		return TRUE;
2083 
2084 	if (row == 0 && col == 0) {
2085 		*expr_end = '\0';
2086 		xml_cell_set_array_expr (state, cell, cc,
2087 					 content + 2, rows, cols);
2088 	}
2089 
2090 	return FALSE;
2091 }
2092 
2093 static void
xml_sax_cell_content(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2094 xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2095 {
2096 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2097 	Sheet *sheet = state->sheet;
2098 	gboolean is_new_cell = FALSE, is_post_52_array = FALSE;
2099 	int size_cols, size_rows;
2100 	GnmParsePos pos;
2101 	GnmCell *cell = NULL; /* Regular case */
2102 	GnmCellCopy *cc = NULL; /* Clipboard case */
2103 	GnmCellRegion *cr = state->clipboard;
2104 	GnmExprTop const *texpr = NULL;
2105 	GnmValue *v = NULL;
2106 	char const *content = xin->content->str;
2107 	gboolean has_contents = (xin->content->len > 0);
2108 	const char *expr_start = gnm_expr_char_start_p (content);
2109 
2110 	int const col = state->cell.col;
2111 	int const row = state->cell.row;
2112 	int const array_cols = state->array_cols;
2113 	int const array_rows = state->array_rows;
2114 	int expr_id = state->expr_id;
2115 	int const value_type = state->value_type;
2116 	gboolean const seen_contents = state->seen_cell_contents;
2117 	GOFormat *value_fmt = state->value_fmt;
2118 	char *value_result = state->value_result;
2119 
2120 	/* Clean out the state before any error checking */
2121 	state->cell.row = state->cell.col = -1;
2122 	state->array_rows = state->array_cols = -1;
2123 	state->expr_id = -1;
2124 	state->value_type = -1;
2125 	state->value_fmt = NULL;
2126 	state->value_result = NULL;
2127 	state->seen_cell_contents = strcmp (xin->node->id, "CELL_CONTENT") == 0;
2128 
2129 	if (seen_contents)
2130 		return;
2131 
2132 	is_post_52_array = (array_cols > 0) && (array_rows > 0);
2133 	size_cols = is_post_52_array ? array_cols : 1;
2134 	size_rows = is_post_52_array ? array_rows : 1;
2135 
2136 	maybe_update_progress (xin);
2137 
2138 	if (cr) {
2139 		int x = col - cr->base.col;
2140 		int y = row - cr->base.row;
2141 
2142 		XML_CHECK (x >= 0 &&
2143 			   x <= gnm_sheet_get_max_cols (sheet) - size_cols);
2144 		XML_CHECK (y >= 0 &&
2145 			   y <= gnm_sheet_get_max_rows (sheet) - size_rows);
2146 		cc = gnm_cell_copy_new (cr, x, y);
2147 		parse_pos_init (&pos, NULL, sheet, col, row);
2148 	} else {
2149 		XML_CHECK (col >= 0 &&
2150 			   col <= gnm_sheet_get_max_cols (sheet) - size_cols);
2151 		XML_CHECK (row >= 0 &&
2152 			   row <= gnm_sheet_get_max_rows (sheet) - size_rows);
2153 
2154 		cell = sheet_cell_get (sheet, col, row);
2155 		is_new_cell = (cell == NULL);
2156 		if (is_new_cell) {
2157 			cell = sheet_cell_create (sheet, col, row);
2158 			if (cell == NULL)
2159 				return;
2160 		}
2161 		parse_pos_init_cell (&pos, cell);
2162 	}
2163 
2164 	// ----------------------------------------
2165 
2166 	if (is_post_52_array && has_contents) {
2167 		// Array formula
2168 		g_return_if_fail (content[0] == '=');
2169 		xml_cell_set_array_expr (state, cell, cc, content + 1,
2170 					 array_cols, array_rows);
2171 		texpr = cell->base.texpr;
2172 		if (texpr) gnm_expr_top_ref (texpr);
2173 		goto store_shared;
2174 	}
2175 
2176 	// ----------------------------------------
2177 
2178 	if (has_contents && state->version < GNM_XML_V3 &&
2179 	    !xml_not_used_old_array_spec (state, cell, cc, content)) {
2180 		// Very old array syntax -- irrelevant
2181 		goto done;
2182 	}
2183 
2184 	// ----------------------------------------
2185 
2186 	if (!has_contents && expr_id > 0) {
2187 		// Re-use of expression id
2188 		texpr = g_hash_table_lookup (state->expr_map,
2189 					     GINT_TO_POINTER (expr_id));
2190 
2191 		if (texpr && gnm_expr_top_is_array_corner (texpr)) {
2192 			g_printerr ("Shared array formula for %s -- how did that happen?\n",
2193 				    cell ? cell_name (cell) : "clipboard");
2194 			texpr = gnm_expr_top_new (gnm_expr_copy (texpr->expr));
2195 			expr_id = -1;
2196 		} else if (texpr) {
2197 			gnm_expr_top_ref (texpr);
2198 			expr_id = -1;
2199 		} else {
2200 			char *msg = g_strdup_printf
2201 				("Looking up shared expression id %d",
2202 				 expr_id);
2203 			char *s = g_strdup_printf ("<shared expression %d>", expr_id);
2204 			xml_sax_barf (G_STRFUNC, msg);
2205 			g_free (msg);
2206 
2207 			texpr = gnm_expr_top_new_constant (value_new_string_nocopy (s));
2208 		}
2209 		goto assign_and_done;
2210 	}
2211 
2212 	// ----------------------------------------
2213 
2214 	if (value_type > 0) {
2215 		// Cell value
2216 		gboolean from_content = (value_result == NULL);
2217 		const char *txt = from_content ? content : value_result;
2218 		v = value_new_from_string (value_type, txt, value_fmt, FALSE);
2219 		if (v == NULL) {
2220 			char *msg = g_strdup_printf
2221 				("Parsing \"%s\" as type 0x%x",
2222 				 txt, value_type);
2223 			xml_sax_barf (G_STRFUNC, msg);
2224 			g_free (msg);
2225 			v = value_new_string (txt);
2226 		}
2227 
2228 		// If we consumed the contents as a value, then it's not
2229 		// an expression.
2230 		if (from_content)
2231 			expr_start = NULL;
2232 		else {
2233 			if (value_fmt)
2234 				value_set_fmt (v, value_fmt);
2235 		}
2236 	}
2237 
2238 	// ----------------------------------------
2239 
2240 	if (expr_start && *expr_start) {
2241 		GnmParseError perr;
2242 
2243 		parse_error_init (&perr);
2244 		texpr = gnm_expr_parse_str (expr_start,
2245 					    &pos,
2246 					    GNM_EXPR_PARSE_DEFAULT,
2247 					    state->convs,
2248 					    &perr);
2249 		// Don't warn in the clipboard case.
2250 		// It's probably an unknown sheet ref
2251 		if (!texpr && !cr)
2252 			g_warning ("Unparsable expression for %s: %s (%s)\n",
2253 				   cell ? cell_name (cell) : "-",
2254 				   content,
2255 				   perr.err->message);
2256 		if (!texpr)
2257 			texpr = gnm_expr_top_new_constant (value_new_string (expr_start));
2258 		parse_error_free (&perr);
2259 
2260 		if (expr_id > 0) {
2261 			gpointer id = GINT_TO_POINTER (expr_id);
2262 			GnmExprTop const *texpr0 =
2263 				g_hash_table_lookup (state->expr_map, id);
2264 			if (texpr0) {
2265 				if (!is_post_52_array)
2266 					g_warning ("XML-IO: Duplicate shared expression");
2267 				expr_id = -1;
2268 			}
2269 		}
2270 	}
2271 
2272 assign_and_done:
2273 	if (!v)
2274 		v = value_new_empty ();
2275 	// When we get here:
2276 	// 1. We own a ref to texpr (or it's NULL)
2277 	// 2. We own v.  After this section we no longer own v.
2278 	if (cell) {
2279 		// Regular case
2280 		if (texpr)
2281 			gnm_cell_set_expr_and_value (cell, texpr, v, TRUE);
2282 		else
2283 			gnm_cell_set_value (cell, v);
2284 	} else {
2285 		// Clipboard case
2286 		cc->texpr = texpr ? gnm_expr_top_ref (texpr) : NULL;
2287 		cc->val = v;
2288 	}
2289 
2290 store_shared:
2291 	if (texpr) {
2292 		// We own a ref to texpr at this point.  Store or discard.
2293 		if (expr_id > 0)
2294 			g_hash_table_insert (state->expr_map,
2295 					     GINT_TO_POINTER (expr_id),
2296 					     (gpointer)texpr);
2297 		else
2298 			gnm_expr_top_unref (texpr);
2299 	}
2300 
2301 done:
2302 	go_format_unref (value_fmt);
2303 	g_free (value_result);
2304 }
2305 
2306 static void
xml_sax_merge(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2307 xml_sax_merge (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2308 {
2309 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2310 	GnmCellRegion *cr = state->clipboard;
2311 	Sheet *sheet = state->sheet;
2312 	GnmRange r;
2313 
2314 	g_return_if_fail (xin->content->len > 0);
2315 
2316 	if (range_parse (&r, xin->content->str, gnm_sheet_get_size (sheet))) {
2317 		if (cr) {
2318 			cr->merged = g_slist_prepend (cr->merged,
2319 						      gnm_range_dup (&r));
2320 		} else {
2321 			gnm_sheet_merge_add (sheet, &r, FALSE,
2322 					     GO_CMD_CONTEXT (state->context));
2323 		}
2324 	}
2325 }
2326 
2327 static void
xml_sax_filter_operator(XMLSaxParseState * state,GnmFilterOp * op,xmlChar const * str)2328 xml_sax_filter_operator (XMLSaxParseState *state,
2329 			 GnmFilterOp *op, xmlChar const *str)
2330 {
2331 	static char const *filter_cond_name[] = { "eq", "gt", "lt", "gte", "lte", "ne" };
2332 	int i;
2333 
2334 	for (i = G_N_ELEMENTS (filter_cond_name); i-- ; )
2335 		if (0 == g_ascii_strcasecmp (CXML2C (str), filter_cond_name[i])) {
2336 			*op = i;
2337 			return;
2338 		}
2339 
2340 	go_io_warning (state->context, _("Unknown filter operator \"%s\""), str);
2341 }
2342 
2343 static void
xml_sax_filter_condition(GsfXMLIn * xin,xmlChar const ** attrs)2344 xml_sax_filter_condition (GsfXMLIn *xin, xmlChar const **attrs)
2345 {
2346 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2347 	char const *type = NULL;
2348 	char const *val0 = NULL;
2349 	char const *val1 = NULL;
2350 	GnmValueType vtype0 = VALUE_EMPTY, vtype1 = VALUE_EMPTY;
2351 	GnmFilterOp op0 = GNM_FILTER_UNUSED, op1 = GNM_FILTER_UNUSED;
2352 	GnmFilterCondition *cond = NULL;
2353 	gboolean top = TRUE, items = TRUE, is_and = FALSE;
2354 	int i, tmp, cond_num = 0;
2355 	double bucket_count = 10.;
2356 
2357 	if (NULL == state->filter) return;
2358 
2359 	for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2) {
2360 		if (attr_eq (attrs[i], "Type"))   type = CXML2C (attrs[i + 1]);
2361 		else if (gnm_xml_attr_int (attrs+i, "Index", &cond_num)) ;
2362 		else if (gnm_xml_attr_bool (attrs, "Top", &top)) ;
2363 		else if (gnm_xml_attr_bool (attrs, "Items", &items)) ;
2364 		else if (gnm_xml_attr_double  (attrs, "Count", &bucket_count)) ;
2365 		else if (gnm_xml_attr_bool (attrs, "IsAnd", &is_and)) ;
2366 		else if (attr_eq (attrs[i], "Op0")) xml_sax_filter_operator (state, &op0, attrs[i + 1]);
2367 		else if (attr_eq (attrs[i], "Op1")) xml_sax_filter_operator (state, &op1, attrs[i + 1]);
2368 		/*
2369 		 * WARNING WARNING WARING
2370 		 * Value and ValueType are _reversed_ !!!
2371 		 * An error in the DOM exporter was propogated to the SAX
2372 		 * exporter and fixing this reversal would break all old files.
2373 		 */
2374 		else if (attr_eq (attrs[i], "ValueType0")) val0 = CXML2C (attrs[i + 1]);
2375 		else if (attr_eq (attrs[i], "ValueType1")) val1 = CXML2C (attrs[i + 1]);
2376 		else if (gnm_xml_attr_int (attrs+i, "Value0", &tmp)) vtype0 = tmp;
2377 		else if (gnm_xml_attr_int (attrs+i, "Value1", &tmp)) vtype1 = tmp;
2378 	}
2379 
2380 	if (NULL == type) {
2381 		go_io_warning (state->context, _("Missing filter type"));
2382 	} else if (0 == g_ascii_strcasecmp (type, "expr")) {
2383 		GnmValue *v0 = NULL, *v1 = NULL;
2384 		if (val0 && vtype0 != VALUE_EMPTY && op0 != GNM_FILTER_UNUSED)
2385 			v0 = value_new_from_string (vtype0, val0, NULL, FALSE);
2386 		if (val1 && vtype1 != VALUE_EMPTY && op1 != GNM_FILTER_UNUSED)
2387 			v1 = value_new_from_string (vtype1, val1, NULL, FALSE);
2388 		if (v0 && v1)
2389 			cond = gnm_filter_condition_new_double (
2390 				op0, v0, is_and, op1, v1);
2391 		else if (v0)
2392 			cond = gnm_filter_condition_new_single (op0, v0);
2393 		else {
2394 			go_io_warning (state->context, _("Malformed sheet filter condition"));
2395 			value_release (v0);
2396 			value_release (v1);
2397 		}
2398 	} else if (0 == g_ascii_strcasecmp (type, "blanks")) {
2399 		cond = gnm_filter_condition_new_single (
2400 			GNM_FILTER_OP_BLANKS, NULL);
2401 	} else if (0 == g_ascii_strcasecmp (type, "noblanks")) {
2402 		cond = gnm_filter_condition_new_single (
2403 			GNM_FILTER_OP_NON_BLANKS, NULL);
2404 	} else if (0 == g_ascii_strcasecmp (type, "bucket")) {
2405 		cond = gnm_filter_condition_new_bucket
2406 			(top, items, TRUE, bucket_count);
2407 	} else {
2408 		go_io_warning (state->context, _("Unknown filter type \"%s\""), type);
2409 	}
2410 	if (cond != NULL)
2411 		gnm_filter_set_condition (state->filter, cond_num, cond, FALSE);
2412 }
2413 
2414 static void
xml_sax_filter_start(GsfXMLIn * xin,xmlChar const ** attrs)2415 xml_sax_filter_start (GsfXMLIn *xin, xmlChar const **attrs)
2416 {
2417 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2418 	GnmRange   r;
2419 	int i;
2420 
2421 	xml_sax_must_have_sheet (state);
2422 	g_return_if_fail (state->filter == NULL);
2423 
2424 	for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2)
2425 		if (attr_eq (attrs[i], "Area") &&
2426 		    range_parse (&r, CXML2C (attrs[i + 1]), gnm_sheet_get_size (state->sheet)))
2427 			state->filter = gnm_filter_new (state->sheet, &r, TRUE);
2428 	if (NULL == state->filter)
2429 		go_io_warning (state->context, _("Invalid filter, missing Area"));
2430 }
2431 
2432 static void
xml_sax_filter_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2433 xml_sax_filter_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2434 {
2435 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2436 	state->filter = NULL;
2437 }
2438 
2439 static void
xml_sax_read_obj(GsfXMLIn * xin,gboolean needs_cleanup,char const * type_name,xmlChar const ** attrs)2440 xml_sax_read_obj (GsfXMLIn *xin, gboolean needs_cleanup,
2441 		  char const *type_name, xmlChar const **attrs)
2442 {
2443 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2444 	int tmp_int, i;
2445 	SheetObject *so;
2446 	SheetObjectClass *klass;
2447 	GnmRange		anchor_r;
2448 	GODrawingAnchorDir	anchor_dir;
2449 	GnmSOAnchorMode anchor_mode;
2450 	SheetObjectAnchor	anchor;
2451 	double			f_tmp[4], *anchor_offset = NULL;
2452 
2453 	g_return_if_fail (state->so == NULL);
2454 
2455 	/* Old crufty IO */
2456 	if (!strcmp (type_name, "Rectangle"))
2457 		so = g_object_new (GNM_SO_FILLED_TYPE, NULL);
2458 	else if (!strcmp (type_name, "Ellipse"))
2459 		so = g_object_new (GNM_SO_FILLED_TYPE, "is-oval", TRUE, NULL);
2460 	else if (!strcmp (type_name, "Line"))
2461 		so = g_object_new (GNM_SO_LINE_TYPE, NULL);
2462 	else if (!strcmp (type_name, "Arrow")) {
2463 		GOArrow arrow;
2464 		go_arrow_init_kite (&arrow, 8., 10., 3.);
2465 		so = g_object_new (GNM_SO_LINE_TYPE,
2466 				   "end-arrow", &arrow,
2467 				   NULL);
2468 	}
2469 
2470 	/* Class renamed between 1.0.x and 1.2.x */
2471 	else if (!strcmp (type_name, "GnmGraph"))
2472 		so = sheet_object_graph_new (NULL);
2473 
2474 	/* Class renamed in 1.2.2 */
2475 	else if (!strcmp (type_name, "CellComment"))
2476 		so = g_object_new (cell_comment_get_type (), NULL);
2477 
2478 	/* Class renamed in 1.3.91 */
2479 	else if (!strcmp (type_name, "SheetObjectGraphic"))
2480 		so = g_object_new (GNM_SO_LINE_TYPE, NULL);
2481 	else if (!strcmp (type_name, "SheetObjectFilled"))
2482 		so = g_object_new (GNM_SO_FILLED_TYPE, NULL);
2483 	else if (!strcmp (type_name, "SheetObjectText"))
2484 		so = g_object_new (GNM_SO_FILLED_TYPE, NULL);
2485 	else if (!strcmp (type_name, "SheetObjectComponent"))
2486 		so = sheet_object_component_new (NULL);
2487 	else if (!strcmp (type_name, "SheetObjectPath"))
2488 		so = g_object_new (GNM_SO_PATH_TYPE, NULL);
2489 
2490 	else {
2491 		GType type = g_type_from_name (type_name);
2492 
2493 		if (type == 0 || !g_type_is_a (type, GNM_SO_TYPE)) {
2494 			char *str = g_strdup_printf (_("Unsupported object type '%s'"),
2495 						     type_name);
2496 			go_io_warning_unsupported_feature (state->context, str);
2497 			g_free (str);
2498 			return;
2499 		}
2500 
2501 		so = g_object_new (type, NULL);
2502 		if (so == NULL)
2503 			return;
2504 	}
2505 
2506 	g_return_if_fail (so != NULL);
2507 	klass = GNM_SO_CLASS (G_OBJECT_GET_CLASS (so));
2508 	g_return_if_fail (klass != NULL);
2509 
2510 	state->so = so;
2511 
2512 	anchor_dir = GOD_ANCHOR_DIR_UNKNOWN;
2513 	anchor_mode = GNM_SO_ANCHOR_TWO_CELLS;
2514 	/* Provide a default.  */
2515 	anchor_r = sheet_object_get_anchor (so)->cell_bound;
2516 
2517 	for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2) {
2518 		if (attr_eq (attrs[i], "Name"))
2519 			sheet_object_set_name (so, CXML2C (attrs[i + 1]));
2520 		else if (xml_sax_attr_enum (attrs + i, "AnchorMode", GNM_SHEET_OBJECT_ANCHOR_MODE_TYPE, &tmp_int))
2521 			anchor_mode = tmp_int;
2522 		else if (attr_eq (attrs[i], "ObjectBound"))
2523 			range_parse (&anchor_r, CXML2C (attrs[i + 1]), gnm_sheet_get_size (state->sheet));
2524 		else if (attr_eq (attrs[i], "ObjectOffset") &&
2525 			4 == sscanf (CXML2C (attrs[i + 1]), "%lg %lg %lg %lg",
2526 				     f_tmp + 0, f_tmp + 1, f_tmp + 2, f_tmp + 3))
2527 			anchor_offset = f_tmp;
2528 		else if (gnm_xml_attr_int (attrs+i, "Direction", &tmp_int))
2529 			anchor_dir = tmp_int;
2530 		else if (gnm_xml_attr_int (attrs+i, "Print", &tmp_int)) {
2531 			gboolean b = (tmp_int != 0);
2532 			sheet_object_set_print_flag (so, &b);
2533 		}
2534 	}
2535 
2536 	/* Patch problems introduced in some 1.7.x versions that stored
2537 	 * comments in merged cells with the full rectangle of the merged cell
2538 	 * rather than just the top left corner */
2539 	if (G_OBJECT_TYPE (so) == GNM_CELL_COMMENT_TYPE)
2540 		anchor_r.end = anchor_r.start;
2541 
2542 	sheet_object_anchor_init (&anchor, &anchor_r, anchor_offset, anchor_dir, anchor_mode);
2543 	sheet_object_set_anchor (so, &anchor);
2544 
2545 	if (NULL != klass->prep_sax_parser)
2546 		(klass->prep_sax_parser) (so, xin, attrs, state->convs);
2547 	if (needs_cleanup) {
2548 		/* Put in something to get gnm_xml_finish_obj called */
2549 		static GsfXMLInNode const dtd[] = {
2550 		  GSF_XML_IN_NODE (STYLE, STYLE, -1, "", GSF_XML_NO_CONTENT, NULL, NULL),
2551 		  GSF_XML_IN_NODE_END
2552 		};
2553 		static GsfXMLInDoc *doc = NULL;
2554 		if (NULL == doc) {
2555 			doc = gsf_xml_in_doc_new (dtd, NULL);
2556 			gnm_xml_in_doc_dispose_on_exit (&doc);
2557 		}
2558 		// We need to pass state there because xin->user_state might
2559 		// have changed, see #751217
2560 		gsf_xml_in_push_state (xin, doc, state,
2561 			(GsfXMLInExtDtor) gnm_xml_finish_obj, attrs);
2562 	}
2563 }
2564 
2565 static void
xml_sax_object_start(GsfXMLIn * xin,xmlChar const ** attrs)2566 xml_sax_object_start (GsfXMLIn *xin, xmlChar const **attrs)
2567 {
2568 	char const *type_name = xin->node->name;
2569 	maybe_update_progress (xin);
2570 	xml_sax_read_obj (xin, FALSE, type_name, attrs);
2571 }
2572 
2573 static void
xml_sax_object_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2574 xml_sax_object_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2575 {
2576 	gnm_xml_finish_obj (xin, xin->user_state);
2577 	/*
2578 	 * WARNING: the object is not completely finished at this
2579 	 * time.  Any handler installed by gog_object_sax_push_parser
2580 	 * has not yet been called.  As a consequence, we cannot
2581 	 * update the GUI here.
2582 	 */
2583 }
2584 
2585 static GnmValue *
parse_constraint_side(const char * s,const GnmParsePos * pp)2586 parse_constraint_side (const char *s, const GnmParsePos *pp)
2587 {
2588 	GODateConventions const *date_conv = sheet_date_conv (pp->sheet);
2589 	GnmValue *v = format_match_number (s, NULL, date_conv);
2590 
2591 	if (!v) {
2592 		GnmExprParseFlags flags = GNM_EXPR_PARSE_DEFAULT;
2593 		v = value_new_cellrange_parsepos_str (pp, s, flags);
2594 	}
2595 
2596 	return v;
2597 }
2598 
2599 static void
xml_sax_solver_constr_start(GsfXMLIn * xin,xmlChar const ** attrs)2600 xml_sax_solver_constr_start (GsfXMLIn *xin, xmlChar const **attrs)
2601 {
2602 	int type = 0;
2603 	GnmSolverConstraint *c;
2604 	Sheet *sheet = gnm_xml_in_cur_sheet (xin);
2605 	GnmSolverParameters *sp = sheet->solver_parameters;
2606 	int lhs_col = 0, lhs_row = 0, rhs_col = 0, rhs_row = 0;
2607 	int cols = 1, rows = 1;
2608 	gboolean old = FALSE;
2609 	GnmParsePos pp;
2610 
2611 	c = gnm_solver_constraint_new (sheet);
2612 
2613 	parse_pos_init_sheet (&pp, sheet);
2614 
2615 	for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2616 		if (gnm_xml_attr_int (attrs, "Lcol", &lhs_col) ||
2617 		    gnm_xml_attr_int (attrs, "Lrow", &lhs_row) ||
2618 		    gnm_xml_attr_int (attrs, "Rcol", &rhs_col) ||
2619 		    gnm_xml_attr_int (attrs, "Rrow", &rhs_row) ||
2620 		    gnm_xml_attr_int (attrs, "Cols", &cols) ||
2621 		    gnm_xml_attr_int (attrs, "Rows", &rows))
2622 			old = TRUE;
2623 		else if (gnm_xml_attr_int (attrs, "Type", &type))
2624 			; /* Nothing */
2625 		else if (attr_eq (attrs[0], "lhs")) {
2626 			GnmValue *v = parse_constraint_side (CXML2C (attrs[1]),
2627 							     &pp);
2628 			gnm_solver_constraint_set_lhs (c, v);
2629 		} else if (attr_eq (attrs[0], "rhs")) {
2630 			GnmValue *v = parse_constraint_side (CXML2C (attrs[1]),
2631 							     &pp);
2632 			gnm_solver_constraint_set_rhs (c, v);
2633 		}
2634 	}
2635 
2636 	switch (type) {
2637 	default:
2638 	case 1: c->type = GNM_SOLVER_LE; break;
2639 	case 2: c->type = GNM_SOLVER_GE; break;
2640 	case 4: c->type = GNM_SOLVER_EQ; break;
2641 	case 8: c->type = GNM_SOLVER_INTEGER; break;
2642 	case 16: c->type = GNM_SOLVER_BOOLEAN; break;
2643 	}
2644 
2645 	if (old)
2646 		gnm_solver_constraint_set_old (c, c->type,
2647 					       lhs_col, lhs_row,
2648 					       rhs_col, rhs_row,
2649 					       cols, rows);
2650 
2651 	sp->constraints = g_slist_append (sp->constraints, c);
2652 }
2653 
2654 static void
xml_sax_solver_start(GsfXMLIn * xin,xmlChar const ** attrs)2655 xml_sax_solver_start (GsfXMLIn *xin, xmlChar const **attrs)
2656 {
2657 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2658 	Sheet *sheet;
2659 	GnmSolverParameters *sp;
2660 	int col = -1, row = -1;
2661 	int ptype, mtype;
2662 	GnmParsePos pp;
2663 	gboolean old = FALSE;
2664 
2665 	xml_sax_must_have_sheet (state);
2666 	sheet = gnm_xml_in_cur_sheet (xin);
2667 	sp = sheet->solver_parameters;
2668 
2669 	parse_pos_init_sheet (&pp, sheet);
2670 
2671 	for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2672 		if (gnm_xml_attr_int (attrs, "ModelType", &mtype)) {
2673 			sp->options.model_type = (GnmSolverModelType)mtype;
2674 		} else if (gnm_xml_attr_int (attrs, "ProblemType", &ptype)) {
2675 				sp->problem_type = (GnmSolverProblemType)ptype;
2676 		} else if (attr_eq (attrs[0], "Inputs")) {
2677 			GnmValue *v = value_new_cellrange_parsepos_str
2678 				(&pp,
2679 				 CXML2C (attrs[1]),
2680 				 GNM_EXPR_PARSE_DEFAULT);
2681 			gnm_solver_param_set_input (sp, v);
2682 		} else if (gnm_xml_attr_int (attrs, "TargetCol", &col) ||
2683 			   gnm_xml_attr_int (attrs, "TargetRow", &row)) {
2684 			old = TRUE;
2685 		} else if (attr_eq (attrs[0], "Target")) {
2686 			GnmValue *v = value_new_cellrange_parsepos_str
2687 				(&pp,
2688 				 CXML2C (attrs[1]),
2689 				 GNM_EXPR_PARSE_DEFAULT);
2690 			GnmSheetRange sr;
2691 			GnmCellRef cr;
2692 			gboolean  bad;
2693 
2694 			bad = (!v ||
2695 			       (gnm_sheet_range_from_value (&sr, v), !range_is_singleton (&sr.range)));
2696 			value_release (v);
2697 			if (bad) {
2698 				continue;
2699 			}
2700 
2701 			gnm_cellref_init (&cr, sr.sheet,
2702 					  sr.range.start.col,
2703 					  sr.range.start.row,
2704 					  TRUE);
2705 			gnm_solver_param_set_target (sp, &cr);
2706 		} else if (gnm_xml_attr_int (attrs, "MaxTime", &(sp->options.max_time_sec)) ||
2707 			   gnm_xml_attr_int (attrs, "MaxIter", &(sp->options.max_iter)) ||
2708 			   gnm_xml_attr_bool (attrs, "NonNeg", &(sp->options.assume_non_negative)) ||
2709 			   gnm_xml_attr_bool (attrs, "Discr", &(sp->options.assume_discrete)) ||
2710 			   gnm_xml_attr_bool (attrs, "AutoScale", &(sp->options.automatic_scaling)) ||
2711 			   gnm_xml_attr_bool (attrs, "ProgramR", &(sp->options.program_report)) ||
2712 			   gnm_xml_attr_bool (attrs, "SensitivityR", &(sp->options.sensitivity_report)))
2713 			; /* Nothing */
2714 	}
2715 
2716 	if (old &&
2717 	    col >= 0 && col < gnm_sheet_get_max_cols (sheet) &&
2718 	    row >= 0 && row < gnm_sheet_get_max_rows (sheet)) {
2719 		GnmCellRef cr;
2720 		gnm_cellref_init (&cr, NULL, col, row, TRUE);
2721 		gnm_solver_param_set_target (sp, &cr);
2722 	}
2723 }
2724 
2725 static void
xml_sax_scenario_start(GsfXMLIn * xin,xmlChar const ** attrs)2726 xml_sax_scenario_start (GsfXMLIn *xin, xmlChar const **attrs)
2727 {
2728 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2729 	const char *name = "scenario";
2730 	const char *comment = NULL;
2731 
2732 	xml_sax_must_have_sheet (state);
2733 
2734 	for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2735 		if (attr_eq (attrs[0], "Name")) {
2736 			name = CXML2C (attrs[1]);
2737 		} else if (attr_eq (attrs[0], "Comment")) {
2738 			comment = CXML2C (attrs[1]);
2739 		}
2740 	}
2741 
2742 	state->scenario = gnm_sheet_scenario_new (state->sheet, name);
2743 	if (comment)
2744 		gnm_scenario_set_comment (state->scenario, comment);
2745 }
2746 
2747 static void
xml_sax_scenario_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2748 xml_sax_scenario_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2749 {
2750 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2751 	GnmScenario *sc = state->scenario;
2752 	sc->items = g_slist_reverse (sc->items);
2753 	gnm_sheet_scenario_add (state->sheet, sc);
2754 	state->scenario = NULL;
2755 }
2756 
2757 static void
xml_sax_scenario_item_start(GsfXMLIn * xin,xmlChar const ** attrs)2758 xml_sax_scenario_item_start (GsfXMLIn *xin, xmlChar const **attrs)
2759 {
2760 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2761 	const char *rtxt = NULL;
2762 	GnmParsePos pp;
2763 
2764 	for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2765 		if (attr_eq (attrs[0], "Range")) {
2766 			rtxt = CXML2C (attrs[1]);
2767 		} else if (gnm_xml_attr_int (attrs, "ValueType",
2768 					     &state->value_type))
2769 			; /* Nothing */
2770 		else if (attr_eq (attrs[0], "ValueFormat"))
2771 			state->value_fmt = make_format (CXML2C (attrs[1]));
2772 	}
2773 
2774 	parse_pos_init_sheet (&pp, state->sheet);
2775 	state->scenario_range = rtxt
2776 		? value_new_cellrange_parsepos_str (&pp, rtxt, GNM_EXPR_PARSE_DEFAULT)
2777 		: NULL;
2778 }
2779 
2780 static void
xml_sax_scenario_item_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2781 xml_sax_scenario_item_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2782 {
2783 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2784 	char const * content = xin->content->str;
2785 	int const len = xin->content->len;
2786 	GnmScenarioItem *sci = NULL;
2787 	GnmScenario *sc = state->scenario;
2788 	GnmSheetRange sr;
2789 
2790 	if (!state->scenario_range)
2791 		goto bad;
2792 
2793 	gnm_sheet_range_from_value (&sr, state->scenario_range);
2794 	sci = gnm_scenario_item_new (sc->sheet);
2795 	gnm_scenario_item_set_range (sci, &sr);
2796 
2797 	if (len > 0) {
2798 		GnmValue *v = value_new_from_string (state->value_type,
2799 						     content,
2800 						     state->value_fmt,
2801 						     FALSE);
2802 		if (!v)
2803 			goto bad;
2804 		gnm_scenario_item_set_value (sci, v);
2805 		value_release (v);
2806 	}
2807 
2808 	sc->items = g_slist_prepend (sc->items, sci);
2809 	goto out;
2810 
2811 bad:
2812 	g_warning ("Ignoring invalid scenario item");
2813 	if (sci)
2814 		gnm_scenario_item_free (sci);
2815 
2816 out:
2817 	state->value_type = -1;
2818 	go_format_unref (state->value_fmt);
2819 	state->value_fmt = NULL;
2820 	value_release (state->scenario_range);
2821 	state->scenario_range = NULL;
2822 }
2823 
2824 static void
xml_sax_named_expr_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2825 xml_sax_named_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2826 {
2827 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2828 	GnmParsePos pp;
2829 	GnmNamedExpr *nexpr;
2830 
2831 	g_return_if_fail (state->name.name != NULL);
2832 	g_return_if_fail (state->name.value != NULL);
2833 
2834 	/*For the next while we have to ignore Print_areas that look like a whole sheet */
2835 	if (0 == strcmp (state->name.name, "Print_Area")
2836 	    && g_str_has_suffix (state->name.value, "$A$1:$IV$65536")) {
2837 		g_free (state->name.value);
2838 		state->name.value = NULL;
2839 		g_free (state->name.position);
2840 		state->name.position = NULL;
2841 	} else {
2842 		parse_pos_init (&pp, state->wb, state->sheet, 0, 0);
2843 		nexpr = expr_name_add (&pp, state->name.name,
2844 				       gnm_expr_top_new_constant (value_new_empty ()),
2845 				       NULL,
2846 				       TRUE,
2847 				       NULL);
2848 		if (nexpr) {
2849 			state->delayed_names = g_list_prepend (state->delayed_names, state->sheet);
2850 			state->delayed_names = g_list_prepend (state->delayed_names, state->name.value);
2851 			state->name.value = NULL;
2852 			state->delayed_names = g_list_prepend (state->delayed_names, state->name.position);
2853 			state->name.position = NULL;
2854 			state->delayed_names = g_list_prepend (state->delayed_names, nexpr);
2855 		} else {
2856 			g_warning ("Strangeness with defined name: %s",
2857 				   state->name.name);
2858 			g_free (state->name.value);
2859 			state->name.value = NULL;
2860 			g_free (state->name.position);
2861 			state->name.position = NULL;
2862 		}
2863 	}
2864 
2865 	g_free (state->name.name);
2866 	state->name.name = NULL;
2867 }
2868 
2869 static void
xml_sax_named_expr_prop(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2870 xml_sax_named_expr_prop (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2871 {
2872 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2873 
2874 	char const * content = xin->content->str;
2875 	int const len = xin->content->len;
2876 
2877 	switch (xin->node->user_data.v_int) {
2878 	case 0:
2879 		g_return_if_fail (state->name.name == NULL);
2880 		state->name.name = g_strndup (content, len);
2881 		break;
2882 	case 1:
2883 		g_return_if_fail (state->name.value == NULL);
2884 		state->name.value = g_strndup (content, len);
2885 		break;
2886 	case 2:
2887 		g_return_if_fail (state->name.position == NULL);
2888 		state->name.position = g_strndup (content, len);
2889 		break;
2890 	default:
2891 		return;
2892 	}
2893 }
2894 
2895 static void
xml_sax_print_order(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2896 xml_sax_print_order (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2897 {
2898 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2899 
2900 	xml_sax_must_have_sheet (state);
2901 
2902 	state->sheet->print_info->print_across_then_down =
2903 		(strcmp (xin->content->str, "r_then_d") == 0);
2904 }
2905 
2906 static void
xml_sax_print_comments_start(GsfXMLIn * xin,xmlChar const ** attrs)2907 xml_sax_print_comments_start (GsfXMLIn *xin, xmlChar const **attrs)
2908 {
2909 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2910 	gint tmpi;
2911 
2912 	xml_sax_must_have_sheet (state);
2913 
2914 	/* In 1.11.x and later this is saved as an enum value */
2915 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2916 		if (xml_sax_attr_enum (attrs, "placement", GNM_PRINT_COMMENT_PLACEMENT_TYPE, &tmpi))
2917 			state->sheet->print_info->comment_placement = tmpi;
2918 }
2919 
2920 static void
xml_sax_print_comments_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2921 xml_sax_print_comments_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2922 {
2923 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2924 
2925 	if (xin->content->str == NULL || *xin->content->str == 0)
2926 		/* 1.11.x or later file */
2927 		return;
2928 
2929 	xml_sax_must_have_sheet (state);
2930 
2931 	if (strcmp (xin->content->str, "in_place") == 0)
2932 		state->sheet->print_info->comment_placement =
2933 			GNM_PRINT_COMMENTS_IN_PLACE;
2934 	else if (strcmp (xin->content->str, "at_end") == 0)
2935 		state->sheet->print_info->comment_placement =
2936 			GNM_PRINT_COMMENTS_AT_END;
2937 	else
2938 		state->sheet->print_info->comment_placement =
2939 			GNM_PRINT_COMMENTS_NONE;
2940 }
2941 
2942 static void
xml_sax_print_errors_start(GsfXMLIn * xin,xmlChar const ** attrs)2943 xml_sax_print_errors_start (GsfXMLIn *xin, xmlChar const **attrs)
2944 {
2945 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2946 	gint tmpi;
2947 
2948 	xml_sax_must_have_sheet (state);
2949 
2950 	/* In 1.11.x and later this is saved as an enum value */
2951 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2952 		if (xml_sax_attr_enum (attrs, "PrintErrorsAs", GNM_PRINT_ERRORS_TYPE, &tmpi))
2953 			state->sheet->print_info->error_display = tmpi;
2954 }
2955 
2956 
2957 static void
xml_sax_print_errors_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2958 xml_sax_print_errors_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2959 {
2960 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2961 
2962 	if (xin->content->str == NULL || *xin->content->str == 0)
2963 		/* 1.11.x or later file */
2964 		return;
2965 
2966 	xml_sax_must_have_sheet (state);
2967 
2968 	if (strcmp (xin->content->str, "as_blank") == 0)
2969 		state->sheet->print_info->error_display =
2970 			GNM_PRINT_ERRORS_AS_BLANK;
2971 	else if (strcmp (xin->content->str, "as_dashes") == 0)
2972 		state->sheet->print_info->error_display =
2973 			GNM_PRINT_ERRORS_AS_DASHES;
2974 	else if (strcmp (xin->content->str, "as_na") == 0)
2975 		state->sheet->print_info->error_display =
2976 			GNM_PRINT_ERRORS_AS_NA;
2977 	else
2978 		state->sheet->print_info->error_display =
2979 			GNM_PRINT_ERRORS_AS_DISPLAYED;
2980 }
2981 
2982 
2983 static void
xml_sax_orientation(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)2984 xml_sax_orientation (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2985 {
2986 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2987 	GnmPrintInformation *pi;
2988 	GtkPageOrientation orient = GTK_PAGE_ORIENTATION_PORTRAIT;
2989 
2990 	xml_sax_must_have_sheet (state);
2991 
2992 	pi = state->sheet->print_info;
2993 
2994 #warning TODO: we should also handle inversion
2995 	if (strcmp (xin->content->str, "portrait") == 0)
2996 			orient = GTK_PAGE_ORIENTATION_PORTRAIT;
2997 	else if (strcmp (xin->content->str, "landscape") == 0)
2998 			orient = GTK_PAGE_ORIENTATION_LANDSCAPE;
2999 
3000 	print_info_set_paper_orientation (pi, orient);
3001 }
3002 
3003 static void
xml_sax_paper(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)3004 xml_sax_paper (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3005 {
3006 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3007 
3008 	xml_sax_must_have_sheet (state);
3009 
3010 	print_info_set_paper (state->sheet->print_info, xin->content->str);
3011 }
3012 
3013 static void
xml_sax_print_to_uri(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)3014 xml_sax_print_to_uri (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3015 {
3016 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3017 
3018 	xml_sax_must_have_sheet (state);
3019 
3020 	print_info_set_printtofile_uri (state->sheet->print_info,
3021 					xin->content->str);
3022 }
3023 
3024 static void
handle_delayed_names(XMLSaxParseState * state)3025 handle_delayed_names (XMLSaxParseState *state)
3026 {
3027 	GList *l;
3028 
3029 	for (l = state->delayed_names; l; l = l->next->next->next->next) {
3030 		GnmNamedExpr *nexpr = l->data;
3031 		char *pos_str = l->next->data;
3032 		char *expr_str = l->next->next->data;
3033 		Sheet *sheet = l->next->next->next->data;
3034 		GnmParseError perr;
3035 		GnmExprTop const *texpr;
3036 		GnmParsePos pp;
3037 
3038 		parse_pos_init (&pp, state->wb, sheet, 0, 0);
3039 		if (pos_str) {
3040 			GnmCellRef tmp;
3041 			char const *rest;
3042 			GnmSheetSize const *ss =
3043 				gnm_sheet_get_size2 (sheet, state->wb);
3044 			rest = cellref_parse (&tmp, ss, pos_str, &pp.eval);
3045 			if (rest != NULL && *rest == '\0') {
3046 				pp.eval.col = tmp.col;
3047 				pp.eval.row = tmp.row;
3048 			}
3049 		}
3050 
3051 		parse_error_init (&perr);
3052 		texpr = gnm_expr_parse_str (expr_str, &pp,
3053 					    GNM_EXPR_PARSE_DEFAULT,
3054 					    state->convs,
3055 					    &perr);
3056 		if (!texpr) {
3057 			  go_io_warning (state->context, "%s", perr.err->message);
3058 		} else if (expr_name_check_for_loop (expr_name_name (nexpr), texpr)) {
3059 			g_printerr ("Ignoring would-be circular definition of %s\n",
3060 				    expr_name_name (nexpr));
3061 			gnm_expr_top_unref (texpr);
3062 		} else {
3063 			nexpr->pos.eval = pp.eval;
3064 			expr_name_set_expr (nexpr, texpr);
3065 		}
3066 
3067 		parse_error_free (&perr);
3068 		g_free (expr_str);
3069 		g_free (pos_str);
3070 	}
3071 
3072 	g_list_free (state->delayed_names);
3073 	state->delayed_names = NULL;
3074 }
3075 
3076 static void
xml_sax_go_doc(GsfXMLIn * xin,xmlChar const ** attrs)3077 xml_sax_go_doc (GsfXMLIn *xin, xmlChar const **attrs)
3078 {
3079 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3080 	go_doc_read (GO_DOC (state->wb), xin, attrs);
3081 }
3082 
3083 /****************************************************************************/
3084 
3085 static GsfXMLInNS const content_ns[] = {
3086 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v14.dtd"), /* future */
3087 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v13.dtd"),
3088 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v12.dtd"),
3089 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v11.dtd"),
3090 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v10.dtd"),
3091 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v9.dtd"),
3092 	GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v8.dtd"),
3093 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v7"),
3094 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v6"),
3095 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v5"),
3096 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v4"),
3097 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v3"),
3098 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v2"),
3099 	GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/"),
3100 /* The next items are from libgsf, there is no obvious way of adding them automatically */
3101 	GSF_XML_IN_NS (OO_NS_XSI, "http://www.w3.org/2001/XMLSchema-instance"),
3102 	GSF_XML_IN_NS (OO_NS_OFFICE, "urn:oasis:names:tc:opendocument:xmlns:office:1.0"),
3103 	GSF_XML_IN_NS (OO_NS_OOO,	"http://openoffice.org/2004/office"),
3104 	GSF_XML_IN_NS (OO_NS_DC,	"http://purl.org/dc/elements/1.1/"),
3105 	GSF_XML_IN_NS (OO_NS_XLINK,	"http://www.w3.org/1999/xlink"),
3106 	GSF_XML_IN_NS (OO_NS_META,	"urn:oasis:names:tc:opendocument:xmlns:meta:1.0"),
3107 	GSF_XML_IN_NS_END
3108 };
3109 
3110 static GsfXMLInNode gnumeric_1_0_dtd[] = {
3111 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3112 GSF_XML_IN_NODE_FULL (START, WB, GNM, "Workbook", GSF_XML_NO_CONTENT, TRUE, TRUE, &xml_sax_wb, NULL, 0),
3113   GSF_XML_IN_NODE (WB, WB_VERSION, GNM, "Version", GSF_XML_NO_CONTENT, &xml_sax_version, NULL),
3114   GSF_XML_IN_NODE (WB, WB_ATTRIBUTES, GNM, "Attributes", GSF_XML_NO_CONTENT, NULL, NULL),
3115     GSF_XML_IN_NODE (WB_ATTRIBUTES, WB_ATTRIBUTE, GNM, "Attribute", GSF_XML_NO_CONTENT, NULL, &xml_sax_finish_parse_wb_attr),
3116       GSF_XML_IN_NODE_FULL (WB_ATTRIBUTE, WB_ATTRIBUTE_NAME, GNM, "name",   GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_attr_elem, 0),
3117       GSF_XML_IN_NODE_FULL (WB_ATTRIBUTE, WB_ATTRIBUTE_VALUE, GNM, "value", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_attr_elem, 1),
3118       GSF_XML_IN_NODE (WB_ATTRIBUTE, WB_ATTRIBUTE_TYPE, GNM, "type", GSF_XML_NO_CONTENT, NULL, NULL),
3119 
3120   /* The old 'SummaryItem' Metadata.  Removed in 1.7.x */
3121   GSF_XML_IN_NODE (WB, WB_SUMMARY, GNM, "Summary", GSF_XML_NO_CONTENT, NULL, NULL),
3122       GSF_XML_IN_NODE (WB_SUMMARY, WB_SUMMARY_ITEM, GNM, "Item", GSF_XML_NO_CONTENT, NULL, NULL),
3123 	GSF_XML_IN_NODE (WB_SUMMARY_ITEM, WB_SUMMARY_ITEM_NAME, GNM, "name", GSF_XML_CONTENT, NULL, NULL),
3124 	GSF_XML_IN_NODE (WB_SUMMARY_ITEM, WB_SUMMARY_ITEM_VALUE_STR, GNM, "val-string", GSF_XML_CONTENT, NULL, NULL),
3125 	GSF_XML_IN_NODE (WB_SUMMARY_ITEM, WB_SUMMARY_ITEM_VALUE_INT, GNM, "val-int", GSF_XML_CONTENT, NULL, NULL),
3126 
3127   GSF_XML_IN_NODE (WB, WB_SHEETNAME_INDEX, GNM, "SheetNameIndex", GSF_XML_NO_CONTENT, NULL, NULL),
3128     GSF_XML_IN_NODE (WB_SHEETNAME_INDEX, WB_SHEETNAME, GNM, "SheetName", GSF_XML_CONTENT, &xml_sax_wb_sheetsize, &xml_sax_wb_sheetname),
3129 
3130   GSF_XML_IN_NODE (WB, WB_NAMED_EXPRS, GNM, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
3131     GSF_XML_IN_NODE (WB_NAMED_EXPRS, WB_NAMED_EXPR, GNM, "Name", GSF_XML_NO_CONTENT, NULL, &xml_sax_named_expr_end),
3132       GSF_XML_IN_NODE_FULL (WB_NAMED_EXPR, WB_NAMED_EXPR_NAME,	   GNM, "name",	    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 0),
3133       GSF_XML_IN_NODE_FULL (WB_NAMED_EXPR, WB_NAMED_EXPR_VALUE,	   GNM, "value",    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 1),
3134       GSF_XML_IN_NODE_FULL (WB_NAMED_EXPR, WB_NAMED_EXPR_POSITION, GNM, "position", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 2),
3135       /* sometimes not namespaced */
3136       GSF_XML_IN_NODE_FULL (WB_NAMED_EXPR, WB_NAMED_EXPR_NAME_NS,     -1, "name",     GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 0),
3137       GSF_XML_IN_NODE_FULL (WB_NAMED_EXPR, WB_NAMED_EXPR_VALUE_NS,    -1, "value",    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 1),
3138       GSF_XML_IN_NODE_FULL (WB_NAMED_EXPR, WB_NAMED_EXPR_POSITION_NS, -1, "position", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 2),
3139 
3140   GSF_XML_IN_NODE (WB, WB_SHEETS, GNM, "Sheets", GSF_XML_NO_CONTENT, NULL, NULL),
3141     GSF_XML_IN_NODE (WB_SHEETS, SHEET, GNM, "Sheet", GSF_XML_NO_CONTENT, &xml_sax_sheet_start, &xml_sax_sheet_end),
3142       GSF_XML_IN_NODE (SHEET, SHEET_NAME, GNM, "Name", GSF_XML_CONTENT, NULL, &xml_sax_sheet_name),
3143       GSF_XML_IN_NODE (SHEET, SHEET_MAXCOL, GNM, "MaxCol", GSF_XML_NO_CONTENT, NULL, NULL),
3144       GSF_XML_IN_NODE (SHEET, SHEET_MAXROW, GNM, "MaxRow", GSF_XML_NO_CONTENT, NULL, NULL),
3145       GSF_XML_IN_NODE (SHEET, SHEET_ZOOM, GNM, "Zoom", GSF_XML_CONTENT, NULL, &xml_sax_sheet_zoom),
3146       GSF_XML_IN_NODE (SHEET, SHEET_NAMED_EXPRS, GNM, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
3147 	GSF_XML_IN_NODE (SHEET_NAMED_EXPRS, SHEET_NAMED_EXPR, GNM, "Name", GSF_XML_NO_CONTENT, NULL, &xml_sax_named_expr_end),
3148 	  GSF_XML_IN_NODE_FULL (SHEET_NAMED_EXPR, SHEET_NAMED_EXPR_NAME,     GNM, "name",     GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 0),
3149 	  GSF_XML_IN_NODE_FULL (SHEET_NAMED_EXPR, SHEET_NAMED_EXPR_VALUE,    GNM, "value",    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 1),
3150 	  GSF_XML_IN_NODE_FULL (SHEET_NAMED_EXPR, SHEET_NAMED_EXPR_POSITION, GNM, "position", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_named_expr_prop, 2),
3151 
3152       GSF_XML_IN_NODE (SHEET, SHEET_PRINTINFO, GNM, "PrintInformation", GSF_XML_NO_CONTENT, NULL, NULL),
3153         GSF_XML_IN_NODE (SHEET_PRINTINFO, SHEET_PRINTUNIT, GNM, "PrintUnit", GSF_XML_NO_CONTENT, NULL, NULL),	/* ignore ancient field */
3154 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_MARGINS, GNM, "Margins", GSF_XML_NO_CONTENT, NULL, NULL),
3155 	  GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_TOP,    GNM, "top",	  GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 0),
3156 	  GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_BOTTOM, GNM, "bottom",GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 1),
3157 	  GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_LEFT,   GNM, "left",  GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 2),
3158 	  GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_RIGHT,  GNM, "right", GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 3),
3159 	  GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_HEADER, GNM, "header",GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 4),
3160 	  GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_FOOTER, GNM, "footer",GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 5),
3161 	GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, V_PAGE_BREAKS, GNM, "vPageBreaks", GSF_XML_NO_CONTENT,
3162 			      FALSE, FALSE, &xml_sax_page_breaks_begin, &xml_sax_page_breaks_end, 1),
3163 	  GSF_XML_IN_NODE (V_PAGE_BREAKS, PAGE_BREAK, GNM, "break", GSF_XML_NO_CONTENT, &xml_sax_page_break, NULL),
3164 	GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, H_PAGE_BREAKS, GNM, "hPageBreaks", GSF_XML_NO_CONTENT,
3165 			      FALSE, FALSE, &xml_sax_page_breaks_begin, &xml_sax_page_breaks_end, 0),
3166 	  GSF_XML_IN_NODE (H_PAGE_BREAKS, PAGE_BREAK, GNM, "break", GSF_XML_2ND, NULL, NULL),
3167 
3168 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_SCALE,	    GNM, "Scale",	GSF_XML_CONTENT, &xml_sax_print_scale, NULL),
3169 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_VCENTER,    GNM, "vcenter",	GSF_XML_CONTENT, &xml_sax_print_vcenter, NULL),
3170 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_HCENTER,    GNM, "hcenter",	GSF_XML_CONTENT, &xml_sax_print_hcenter, NULL),
3171 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_GRID,	    GNM, "grid",	GSF_XML_NO_CONTENT, &xml_sax_print_grid, NULL),
3172 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_DO_NOT_PRINT, GNM, "do_not_print",GSF_XML_NO_CONTENT, &xml_sax_print_do_not_print, NULL),
3173 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_PRINT_RANGE, GNM, "print_range",GSF_XML_NO_CONTENT, &xml_sax_print_print_range, NULL),
3174 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_MONO,	    GNM, "monochrome",	GSF_XML_NO_CONTENT, &xml_sax_monochrome, NULL),
3175 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_AS_DRAFT,   GNM, "draft",	GSF_XML_NO_CONTENT, NULL, NULL),
3176 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_COMMENTS,   GNM, "comments",	GSF_XML_CONTENT, &xml_sax_print_comments_start, &xml_sax_print_comments_end),
3177 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ERRORS,   GNM, "errors",	GSF_XML_CONTENT, &xml_sax_print_errors_start, &xml_sax_print_errors_end),
3178 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_TITLES,	    GNM, "titles",	GSF_XML_NO_CONTENT, &xml_sax_print_titles, NULL),
3179 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_REPEAT_TOP, GNM, "repeat_top",	GSF_XML_NO_CONTENT, &xml_sax_repeat_top, NULL),
3180 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_REPEAT_LEFT,GNM, "repeat_left",	GSF_XML_NO_CONTENT, &xml_sax_repeat_left, NULL),
3181 	GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, PRINT_FOOTER,	    GNM, "Footer",	GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_print_hf, NULL, 0),
3182 	GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, PRINT_HEADER,	    GNM, "Header",	GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_print_hf, NULL, 1),
3183 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ORDER,	    GNM, "order",	GSF_XML_CONTENT,  NULL, &xml_sax_print_order),
3184 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_PAPER,	    GNM, "paper",	GSF_XML_CONTENT,  NULL, &xml_sax_paper),
3185 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_TO_URI,	    GNM, "print-to-uri",GSF_XML_CONTENT,  NULL, &xml_sax_print_to_uri),
3186 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ORIENT,	    GNM, "orientation",	GSF_XML_CONTENT,  NULL, &xml_sax_orientation),
3187 	GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ONLY_STYLE, GNM, "even_if_only_styles", GSF_XML_CONTENT, &xml_sax_even_if_only_styles, NULL),
3188 
3189       GSF_XML_IN_NODE (SHEET, SHEET_STYLES, GNM, "Styles", GSF_XML_NO_CONTENT, NULL, NULL),
3190 	GSF_XML_IN_NODE (SHEET_STYLES, STYLE_REGION, GNM, "StyleRegion", GSF_XML_NO_CONTENT, &xml_sax_style_region_start, &xml_sax_style_region_end),
3191 	  GSF_XML_IN_NODE (STYLE_REGION, STYLE_STYLE, GNM, "Style", GSF_XML_NO_CONTENT, &xml_sax_style_start, NULL),
3192 	    GSF_XML_IN_NODE (STYLE_STYLE, STYLE_FONT, GNM, "Font", GSF_XML_CONTENT, &xml_sax_style_font, &xml_sax_style_font_end),
3193 	    GSF_XML_IN_NODE (STYLE_STYLE, STYLE_BORDER, GNM, "StyleBorder", GSF_XML_NO_CONTENT, NULL, NULL),
3194 	      GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_TOP,     GNM, "Top",
3195 				    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_TOP),
3196 	      GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_BOTTOM,  GNM, "Bottom",
3197 				    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_BOTTOM),
3198 	      GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_LEFT,    GNM, "Left",
3199 				    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_LEFT),
3200 	      GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_RIGHT,   GNM, "Right",
3201 				    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_RIGHT),
3202 	      GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_DIAG,    GNM, "Diagonal",
3203 				    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_DIAGONAL),
3204 	      GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_REV_DIAG,GNM, "Rev-Diagonal",
3205 				    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_REV_DIAGONAL),
3206 
3207 	    GSF_XML_IN_NODE (STYLE_STYLE, STYLE_VALIDATION, GNM, "Validation", GSF_XML_NO_CONTENT, &xml_sax_validation, &xml_sax_validation_end),
3208 	      GSF_XML_IN_NODE_FULL (STYLE_VALIDATION, STYLE_VALIDATION_EXPR0, GNM, "Expression0",
3209 				    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_validation_expr_end, 0),
3210 	      GSF_XML_IN_NODE_FULL (STYLE_VALIDATION, STYLE_VALIDATION_EXPR1, GNM, "Expression1",
3211 				    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_validation_expr_end, 1),
3212 	    GSF_XML_IN_NODE (STYLE_STYLE, STYLE_HYPERLINK, GNM, "HyperLink", GSF_XML_NO_CONTENT, &xml_sax_hlink, NULL),
3213 	    GSF_XML_IN_NODE (STYLE_STYLE, STYLE_INPUT_MSG, GNM, "InputMessage", GSF_XML_NO_CONTENT, &xml_sax_input_msg, NULL),
3214 	    GSF_XML_IN_NODE (STYLE_STYLE, STYLE_CONDITION, GNM, "Condition", GSF_XML_NO_CONTENT, &xml_sax_condition, &xml_sax_condition_end),
3215 	      GSF_XML_IN_NODE_FULL (STYLE_CONDITION, STYLE_CONDITION_EXPR0, GNM, "Expression0",
3216 				    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_condition_expr_end, 0),
3217 	      GSF_XML_IN_NODE_FULL (STYLE_CONDITION, STYLE_CONDITION_EXPR1, GNM, "Expression1",
3218 				    GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_condition_expr_end, 1),
3219 	      GSF_XML_IN_NODE (STYLE_CONDITION, STYLE_STYLE, GNM, "Style", GSF_XML_NO_CONTENT, NULL, NULL),
3220 
3221       GSF_XML_IN_NODE_FULL (SHEET, SHEET_COLS, GNM, "Cols",
3222 			    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_cols_rows, NULL, TRUE),
3223 	GSF_XML_IN_NODE_FULL (SHEET_COLS, COL, GNM, "ColInfo",
3224 			      GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_colrow, NULL, TRUE),
3225 
3226       GSF_XML_IN_NODE_FULL (SHEET, SHEET_ROWS, GNM, "Rows",
3227 			    GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_cols_rows, NULL, FALSE),
3228 	GSF_XML_IN_NODE_FULL (SHEET_ROWS, ROW, GNM, "RowInfo",
3229 			      GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_colrow, NULL, FALSE),
3230 
3231       GSF_XML_IN_NODE (SHEET, SHEET_SELECTIONS, GNM, "Selections", GSF_XML_NO_CONTENT, &xml_sax_selection, &xml_sax_selection_end),
3232 	GSF_XML_IN_NODE (SHEET_SELECTIONS, SELECTION, GNM, "Selection", GSF_XML_NO_CONTENT, &xml_sax_selection_range, NULL),
3233 
3234       GSF_XML_IN_NODE (SHEET, SHEET_CELLS, GNM, "Cells", GSF_XML_NO_CONTENT, NULL, NULL),
3235 	GSF_XML_IN_NODE (SHEET_CELLS, CELL, GNM, "Cell", GSF_XML_CONTENT, &xml_sax_cell, &xml_sax_cell_content),
3236 	  GSF_XML_IN_NODE (CELL, CELL_CONTENT, GNM, "Content", GSF_XML_CONTENT, NULL, &xml_sax_cell_content),
3237 
3238       GSF_XML_IN_NODE (SHEET, SHEET_MERGED_REGIONS, GNM, "MergedRegions", GSF_XML_NO_CONTENT, NULL, NULL),
3239 	GSF_XML_IN_NODE (SHEET_MERGED_REGIONS, MERGED_REGION, GNM, "Merge", GSF_XML_CONTENT, NULL, &xml_sax_merge),
3240 
3241       GSF_XML_IN_NODE (SHEET, SHEET_FILTERS, GNM, "Filters", GSF_XML_NO_CONTENT, NULL, NULL),
3242 	GSF_XML_IN_NODE (SHEET_FILTERS, FILTER, GNM, "Filter", GSF_XML_NO_CONTENT, &xml_sax_filter_start, &xml_sax_filter_end),
3243 	  GSF_XML_IN_NODE (FILTER, FILTER_FIELD, GNM, "Field", GSF_XML_NO_CONTENT, &xml_sax_filter_condition, NULL),
3244 
3245       GSF_XML_IN_NODE (SHEET, SHEET_LAYOUT, GNM, "SheetLayout", GSF_XML_NO_CONTENT, &xml_sax_sheet_layout, NULL),
3246 	GSF_XML_IN_NODE (SHEET_LAYOUT, SHEET_FREEZEPANES, GNM, "FreezePanes", GSF_XML_NO_CONTENT, &xml_sax_sheet_freezepanes, NULL),
3247 
3248       GSF_XML_IN_NODE (SHEET, SHEET_SOLVER, GNM, "Solver", GSF_XML_NO_CONTENT, xml_sax_solver_start, NULL),
3249 	GSF_XML_IN_NODE (SHEET_SOLVER, SOLVER_CONSTR, GNM, "Constr", GSF_XML_NO_CONTENT, xml_sax_solver_constr_start, NULL),
3250       GSF_XML_IN_NODE (SHEET, SHEET_SCENARIOS, GNM, "Scenarios", GSF_XML_NO_CONTENT, NULL, NULL),
3251         GSF_XML_IN_NODE (SHEET_SCENARIOS, SHEET_SCENARIO, GNM, "Scenario", GSF_XML_NO_CONTENT, xml_sax_scenario_start, xml_sax_scenario_end),
3252           GSF_XML_IN_NODE (SHEET_SCENARIO, SCENARIO_ITEM, GNM, "Item", GSF_XML_CONTENT, xml_sax_scenario_item_start, xml_sax_scenario_item_end),
3253 
3254       GSF_XML_IN_NODE (SHEET, SHEET_OBJECTS, GNM, "Objects", GSF_XML_NO_CONTENT, NULL, NULL),
3255         /* Old crufty IO */
3256 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_RECT, GNM, "Rectangle", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3257 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_ELLIPSE, GNM, "Ellipse", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3258 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_ARROW, GNM, "Arrow", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3259 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_LINE, GNM, "Line", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3260 	/* Class renamed between 1.0.x and 1.2.x */
3261 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_GRAPH, GNM,	"GnmGraph", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3262 	/* Class renamed in 1.2.2 */
3263 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_COMMENT, GNM, "CellComment", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3264 	/* Class renamed in 1.3.91 */
3265 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_LINE, GNM, "SheetObjectGraphic", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3266 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_FILLED, GNM, "SheetObjectFilled", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3267 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_TEXT, GNM, "SheetObjectText", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3268 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_GRAPH, GNM, "SheetObjectGraph", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3269 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_IMAGE, GNM, "SheetObjectImage", GSF_XML_NO_CONTENT,	&xml_sax_object_start, &xml_sax_object_end),
3270 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_COMPONENT, GNM, "SheetObjectComponent", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3271 	GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_PATH, GNM, "SheetObjectPath", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3272 
3273   GSF_XML_IN_NODE (WB, WB_GEOMETRY, GNM, "Geometry", GSF_XML_NO_CONTENT, &xml_sax_wb_view, NULL),
3274   GSF_XML_IN_NODE (WB, WB_VIEW, GNM, "UIData", GSF_XML_NO_CONTENT, &xml_sax_wb_view, NULL),
3275   GSF_XML_IN_NODE (WB, WB_CALC, GNM, "Calculation", GSF_XML_NO_CONTENT, &xml_sax_calculation, NULL),
3276   GSF_XML_IN_NODE (WB, WB_DATE, GNM, "DateConvention", GSF_XML_CONTENT, NULL, &xml_sax_old_dateconvention),
3277   GSF_XML_IN_NODE (WB, GODOC, -1, "GODoc", GSF_XML_NO_CONTENT, &xml_sax_go_doc, NULL),
3278     GSF_XML_IN_NODE (WB, DOCUMENTMETA, OO_NS_OFFICE, "document-meta", GSF_XML_NO_CONTENT, &xml_sax_document_meta, NULL),
3279   GSF_XML_IN_NODE_END
3280 };
3281 
3282 static void
xml_sax_clipboardrange_start(GsfXMLIn * xin,xmlChar const ** attrs)3283 xml_sax_clipboardrange_start (GsfXMLIn *xin, xmlChar const **attrs)
3284 {
3285 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3286 	int cols = -1, rows = -1, base_col = -1, base_row = -1;
3287 	GnmCellRegion *cr;
3288 
3289 	cr = state->clipboard = gnm_cell_region_new (state->sheet);
3290 
3291 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3292 		if (gnm_xml_attr_int (attrs, "Cols", &cols) ||
3293 		    gnm_xml_attr_int (attrs, "Rows", &rows) ||
3294 		    gnm_xml_attr_int (attrs, "BaseCol", &base_col) ||
3295 		    gnm_xml_attr_int (attrs, "BaseRow", &base_row) ||
3296 		    gnm_xml_attr_bool (attrs, "NotAsContent", &cr->not_as_contents))
3297 			; /* Nothing */
3298 		else if (attr_eq (attrs[0], "DateConvention")) {
3299 			GODateConventions const *date_conv =
3300 				go_date_conv_from_str (CXML2C (attrs[1]));
3301 			if (date_conv)
3302 				cr->date_conv = date_conv;
3303 			else
3304 				g_printerr ("Ignoring invalid date conventions.\n");
3305 		}
3306 	}
3307 
3308 	if (cols <= 0 || rows <= 0 || base_col < 0 || base_row < 0) {
3309 		g_printerr ("Invalid clipboard contents.\n");
3310 	} else {
3311 		cr->cols = cols;
3312 		cr->rows = rows;
3313 		cr->base.col = base_col;
3314 		cr->base.row = base_row;
3315 	}
3316 }
3317 
3318 static GsfXMLInNode clipboard_dtd[] = {
3319 	GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3320 	GSF_XML_IN_NODE_FULL (START, CLIPBOARDRANGE, GNM, "ClipboardRange", GSF_XML_NO_CONTENT, TRUE, TRUE, xml_sax_clipboardrange_start, NULL, 0),
3321 	  /* We insert "Styles" (etc) */
3322 	GSF_XML_IN_NODE_END
3323 };
3324 
3325 static void
gnm_xml_in_doc_add_subset(GsfXMLInDoc * doc,GsfXMLInNode * dtd,const char * id,const char * new_parent)3326 gnm_xml_in_doc_add_subset (GsfXMLInDoc *doc, GsfXMLInNode *dtd,
3327 			   const char *id, const char *new_parent)
3328 {
3329 	GHashTable *parents = g_hash_table_new (g_str_hash, g_str_equal);
3330 	GsfXMLInNode end_node = GSF_XML_IN_NODE_END;
3331 	GArray *new_dtd = g_array_new (FALSE, FALSE, sizeof (GsfXMLInNode));
3332 
3333 	for (; dtd->id; dtd++) {
3334 		GsfXMLInNode node = *dtd;
3335 
3336 		if (g_str_equal (id, dtd->id)) {
3337 			g_hash_table_insert (parents,
3338 					     (gpointer)id,
3339 					     (gpointer)id);
3340 			if (new_parent)
3341 				node.parent_id = new_parent;
3342 		} else if (g_hash_table_lookup (parents, dtd->parent_id))
3343 			g_hash_table_insert (parents,
3344 					     (gpointer)dtd->id,
3345 					     (gpointer)dtd->id);
3346 		else
3347 			continue;
3348 
3349 		g_array_append_val (new_dtd, node);
3350 	}
3351 
3352 	g_array_append_val (new_dtd, end_node);
3353 
3354 	gsf_xml_in_doc_add_nodes (doc, (GsfXMLInNode*)(new_dtd->data));
3355 
3356 	g_array_free (new_dtd, TRUE);
3357 	g_hash_table_destroy (parents);
3358 }
3359 
3360 
3361 static gboolean
xml_sax_unknown(GsfXMLIn * xin,xmlChar const * elem,xmlChar const ** attrs)3362 xml_sax_unknown (GsfXMLIn *xin, xmlChar const *elem, xmlChar const **attrs)
3363 {
3364 	g_return_val_if_fail (xin != NULL, FALSE);
3365 	g_return_val_if_fail (xin->doc != NULL, FALSE);
3366 	g_return_val_if_fail (xin->node != NULL, FALSE);
3367 
3368 	if (GNM == xin->node->ns_id &&
3369 	    0 == strcmp (xin->node->id, "SHEET_OBJECTS")) {
3370 		char const *type_name = gsf_xml_in_check_ns (xin, CXML2C (elem), GNM);
3371 		if (type_name != NULL) {
3372 			XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3373 			/* This may change xin->user_state.  */
3374 			xml_sax_read_obj (xin, TRUE, type_name, attrs);
3375 			/* xin->user_state hasn't been restored yet.  */
3376 			return state->so != NULL;
3377 		}
3378 	}
3379 	return FALSE;
3380 }
3381 
3382 static void
read_file_init_state(XMLSaxParseState * state,GOIOContext * io_context,WorkbookView * wb_view,Sheet * sheet)3383 read_file_init_state (XMLSaxParseState *state,
3384 		      GOIOContext *io_context,
3385 		      WorkbookView *wb_view, Sheet *sheet)
3386 {
3387 	state->context = io_context;
3388 	state->wb_view = wb_view;
3389 	state->wb = sheet
3390 		? sheet->workbook
3391 		: (wb_view ? wb_view_get_workbook (wb_view) : NULL);
3392 	state->sheet = sheet;
3393 	state->version = GNM_XML_UNKNOWN;
3394 	state->last_progress_update = 0;
3395 	state->convs = gnm_xml_io_conventions ();
3396 	state->attribute.name = state->attribute.value = NULL;
3397 	state->name.name = state->name.value = state->name.position = NULL;
3398 	state->style_range_init = FALSE;
3399 	state->style = NULL;
3400 	state->cell.row = state->cell.col = -1;
3401 	state->seen_cell_contents = FALSE;
3402 	state->array_rows = state->array_cols = -1;
3403 	state->expr_id = -1;
3404 	state->value_type = -1;
3405 	state->value_fmt = NULL;
3406 	state->value_result = NULL;
3407 	state->scenario = NULL;
3408 	state->scenario_range = NULL;
3409 	state->filter = NULL;
3410 	state->validation.title = state->validation.msg = NULL;
3411 	state->validation.texpr[0] = state->validation.texpr[1] = NULL;
3412 	state->cond = NULL;
3413 	state->cond_save_style = NULL;
3414 	state->expr_map = g_hash_table_new_full
3415 		(g_direct_hash, g_direct_equal,
3416 		 NULL, (GFreeFunc)gnm_expr_top_unref);
3417 	state->delayed_names = NULL;
3418 	state->so = NULL;
3419 	state->page_breaks = NULL;
3420 	state->clipboard = NULL;
3421 	state->style_handler = NULL;
3422 	state->style_handler_user = NULL;
3423 	state->style_handler_doc = NULL;
3424 }
3425 
3426 static void
read_file_free_state(XMLSaxParseState * state,gboolean self)3427 read_file_free_state (XMLSaxParseState *state, gboolean self)
3428 {
3429 	g_hash_table_destroy (state->expr_map);
3430 	state->expr_map = NULL;
3431 
3432 	gnm_conventions_unref (state->convs);
3433 	state->convs = NULL;
3434 
3435 	/*
3436 	 * Malformed documents can cause the parser to exit early.
3437 	 * This cleans up various bits that may be left.
3438 	 */
3439 
3440 	if (state->style) {
3441 		gnm_style_unref (state->style);
3442 		state->style = NULL;
3443 	}
3444 
3445 	if (state->cond_save_style) {
3446 		gnm_style_unref (state->cond_save_style);
3447 		state->cond_save_style = NULL;
3448 	}
3449 
3450 	if (state->cond) {
3451 		gnm_style_cond_free (state->cond);
3452 		state->cond = NULL;
3453 	}
3454 
3455 	if (state->style_handler_doc) {
3456 		gsf_xml_in_doc_free (state->style_handler_doc);
3457 		state->style_handler_doc = NULL;
3458 	}
3459 
3460 	if (self)
3461 		g_free (state);
3462 }
3463 
3464 static gboolean
read_file_common(ReadFileWhat what,XMLSaxParseState * state,GOIOContext * io_context,WorkbookView * wb_view,Sheet * sheet,GsfInput * input)3465 read_file_common (ReadFileWhat what, XMLSaxParseState *state,
3466 		  GOIOContext *io_context,
3467 		  WorkbookView *wb_view, Sheet *sheet,
3468 		  GsfInput *input)
3469 {
3470 	GsfXMLInDoc     *doc;
3471 	GnmLocale       *locale;
3472 	gboolean         ok;
3473 
3474 	g_return_val_if_fail (GNM_IS_WORKBOOK_VIEW (wb_view), FALSE);
3475 	g_return_val_if_fail (GSF_IS_INPUT (input), FALSE);
3476 
3477 	read_file_init_state (state, io_context, wb_view, sheet);
3478 
3479 	switch (what) {
3480 	case READ_FULL_FILE:
3481 		state->do_progress = TRUE;
3482 		doc = gsf_xml_in_doc_new (gnumeric_1_0_dtd, content_ns);
3483 		break;
3484 	case READ_CLIPBOARD:
3485 		state->do_progress = FALSE;
3486 		doc = gsf_xml_in_doc_new (clipboard_dtd, content_ns);
3487 		if (!doc)
3488 			break;
3489 		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3490 					   "SHEET_STYLES",
3491 					   "CLIPBOARDRANGE");
3492 		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3493 					   "SHEET_COLS",
3494 					   "CLIPBOARDRANGE");
3495 		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3496 					   "SHEET_ROWS",
3497 					   "CLIPBOARDRANGE");
3498 		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3499 					   "SHEET_CELLS",
3500 					   "CLIPBOARDRANGE");
3501 		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3502 					   "SHEET_MERGED_REGIONS",
3503 					   "CLIPBOARDRANGE");
3504 		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3505 					   "SHEET_OBJECTS",
3506 					   "CLIPBOARDRANGE");
3507 		break;
3508 	default:
3509 		g_assert_not_reached ();
3510 		return FALSE;
3511 	}
3512 
3513 	if (doc == NULL)
3514 		return FALSE;
3515 
3516 	gsf_xml_in_doc_set_unknown_handler (doc, &xml_sax_unknown);
3517 
3518 	go_doc_init_read (GO_DOC (state->wb), input);
3519 	gsf_input_seek (input, 0, G_SEEK_SET);
3520 
3521 	if (state->do_progress) {
3522 		go_io_progress_message (state->context,
3523 					_("Reading file..."));
3524 		go_io_value_progress_set (state->context,
3525 					  gsf_input_size (input), 0);
3526 	}
3527 
3528 	locale = gnm_push_C_locale ();
3529 	ok = gsf_xml_in_doc_parse (doc, input, state);
3530 	handle_delayed_names (state);
3531 	gnm_pop_C_locale (locale);
3532 
3533 	go_doc_end_read (GO_DOC (state->wb));
3534 
3535 	if (state->do_progress)
3536 		go_io_progress_unset (state->context);
3537 
3538 	if (!ok) {
3539 		go_io_error_string (state->context,
3540 				    _("XML document not well formed!"));
3541 	}
3542 
3543 	gsf_xml_in_doc_free (doc);
3544 
3545 	return ok;
3546 }
3547 
3548 /* ------------------------------------------------------------------------- */
3549 
3550 static GsfInput *
maybe_gunzip(GsfInput * input)3551 maybe_gunzip (GsfInput *input)
3552 {
3553 	GsfInput *gzip = gsf_input_gzip_new (input, NULL);
3554 	if (gzip) {
3555 		g_object_unref (input);
3556 		return gzip;
3557 	} else {
3558 		gsf_input_seek (input, 0, G_SEEK_SET);
3559 		return input;
3560 	}
3561 }
3562 
3563 static GsfInput *
maybe_convert(GsfInput * input,gboolean quiet)3564 maybe_convert (GsfInput *input, gboolean quiet)
3565 {
3566 	static char const *noencheader = "<?xml version=\"1.0\"?>";
3567 	static char const *encheader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3568 	const size_t nelen = strlen (noencheader);
3569 	const size_t elen = strlen (encheader);
3570 	guint8 const *buf;
3571 	gsf_off_t input_size;
3572 	GString the_buffer, *buffer = &the_buffer;
3573 	guint ui;
3574 	GString *converted = NULL;
3575 	char const *encoding;
3576 	gboolean ok;
3577 	gboolean any_numbered = FALSE;
3578 
3579 	input_size = gsf_input_remaining (input);
3580 
3581 	buf = gsf_input_read (input, nelen, NULL);
3582 	if (!buf ||
3583 	    strncmp (noencheader, (const char *)buf, nelen) != 0 ||
3584 	    input_size >= (gsf_off_t)(G_MAXINT - elen))
3585 		return input;
3586 
3587 	input_size -= nelen;
3588 
3589 	the_buffer.len = 0;
3590 	the_buffer.allocated_len = input_size + elen + 1;
3591 	the_buffer.str = g_try_malloc (the_buffer.allocated_len);
3592 	if (!the_buffer.str)
3593 		return input;
3594 
3595 	g_string_append (buffer, encheader);
3596 	ok = gsf_input_read (input, input_size, (guint8 *)buffer->str + elen) != NULL;
3597 	gsf_input_seek (input, 0, G_SEEK_SET);
3598 	if (!ok) {
3599 		g_free (buffer->str);
3600 		return input;
3601 	}
3602 	buffer->len = input_size + elen;
3603 	buffer->str[buffer->len] = 0;
3604 
3605 	for (ui = 0; ui < buffer->len; ui++) {
3606 		if (buffer->str[ui] == '&' &&
3607 		    buffer->str[ui + 1] == '#' &&
3608 		    g_ascii_isdigit (buffer->str[ui + 2])) {
3609 			guint start = ui;
3610 			guint c = 0;
3611 			ui += 2;
3612 			while (g_ascii_isdigit (buffer->str[ui])) {
3613 				c = c * 10 + (buffer->str[ui] - '0');
3614 				ui++;
3615 			}
3616 			if (buffer->str[ui] == ';' && c >= 128 && c <= 255) {
3617 				buffer->str[start] = c;
3618 				g_string_erase (buffer, start + 1, ui - start);
3619 				ui = start;
3620 			}
3621 			any_numbered = TRUE;
3622 		}
3623 	}
3624 
3625 	encoding = go_guess_encoding (buffer->str, buffer->len, NULL, &converted, NULL);
3626 	if (encoding && !any_numbered &&
3627 	    converted && buffer->len == converted->len &&
3628 	    strcmp (buffer->str, converted->str) == 0)
3629 		quiet = TRUE;
3630 
3631 	g_free (buffer->str);
3632 
3633 	if (encoding) {
3634 		gsize len = converted->len;
3635 		g_object_unref (input);
3636 		if (!quiet)
3637 			g_warning ("Converted xml document with no explicit encoding from transliterated %s to UTF-8.",
3638 				   encoding);
3639 		return gsf_input_memory_new ((void *)g_string_free (converted, FALSE), len, TRUE);
3640 	} else {
3641 		if (!quiet)
3642 			g_warning ("Failed to convert xml document with no explicit encoding to UTF-8.");
3643 		return input;
3644 	}
3645 }
3646 
3647 static void
gnm_xml_file_open(G_GNUC_UNUSED GOFileOpener const * fo,GOIOContext * io_context,GoView * view,GsfInput * input)3648 gnm_xml_file_open (G_GNUC_UNUSED GOFileOpener const *fo, GOIOContext *io_context,
3649 		   GoView *view, GsfInput *input)
3650 {
3651 	XMLSaxParseState state;
3652 	gboolean ok;
3653 
3654 	g_object_ref (input);
3655 	input = maybe_gunzip (input);
3656 	input = maybe_convert (input, FALSE);
3657 
3658 	ok = read_file_common (READ_FULL_FILE, &state,
3659 			       io_context, GNM_WORKBOOK_VIEW (view), NULL,
3660 			       input);
3661 
3662 	g_object_unref (input);
3663 
3664 	if (ok) {
3665 		workbook_queue_all_recalc (state.wb);
3666 
3667 		workbook_set_saveinfo
3668 			(state.wb,
3669 			 GO_FILE_FL_AUTO,
3670 			 go_file_saver_for_id ("Gnumeric_XmlIO:sax"));
3671 	}
3672 
3673 	read_file_free_state (&state, FALSE);
3674 }
3675 
3676 /* ------------------------------------------------------------------------- */
3677 
3678 GnmCellRegion *
gnm_xml_cellregion_read(WorkbookControl * wbc,GOIOContext * io_context,Sheet * sheet,const char * buffer,int length)3679 gnm_xml_cellregion_read (WorkbookControl *wbc, GOIOContext *io_context,
3680 			 Sheet *sheet,
3681 			 const char *buffer, int length)
3682 {
3683 	WorkbookView *wb_view;
3684 	GsfInput *input;
3685 	XMLSaxParseState state;
3686 	GnmCellRegion *result;
3687 
3688 	wb_view = wb_control_view (wbc);
3689 	input = gsf_input_memory_new (buffer, length, FALSE);
3690 	read_file_common (READ_CLIPBOARD, &state,
3691        		       io_context, wb_view, sheet,
3692        		       input);
3693 	g_object_unref (input);
3694 
3695 	result = state.clipboard;
3696 	state.clipboard = NULL;
3697 
3698 	read_file_free_state (&state, FALSE);
3699 
3700 	return result;
3701 }
3702 
3703 /* ------------------------------------------------------------------------- */
3704 
3705 static void
style_parser_done(GsfXMLIn * xin,XMLSaxParseState * old_state)3706 style_parser_done (GsfXMLIn *xin, XMLSaxParseState *old_state)
3707 {
3708 	GnmStyle *style = old_state->style;
3709 	old_state->style_handler (xin, style, old_state->style_handler_user);
3710 	read_file_free_state (old_state, TRUE);
3711 }
3712 
3713 /**
3714  * gnm_xml_prep_style_parser:
3715  * @xin:
3716  * @attrs:
3717  * @handler: (scope async):
3718  * @user: user data.
3719  *
3720  **/
3721 void
gnm_xml_prep_style_parser(GsfXMLIn * xin,xmlChar const ** attrs,GnmXmlStyleHandler handler,gpointer user)3722 gnm_xml_prep_style_parser (GsfXMLIn *xin,
3723 			   xmlChar const **attrs,
3724 			   GnmXmlStyleHandler handler,
3725 			   gpointer user)
3726 {
3727 	static GsfXMLInNode dtd[] = {
3728 		GSF_XML_IN_NODE (STYLE_STYLE, STYLE_STYLE, GNM, "Style", GSF_XML_NO_CONTENT, &xml_sax_style_start, NULL),
3729 		/* Nodes added below.  */
3730 		GSF_XML_IN_NODE_END
3731 	};
3732 	GsfXMLInDoc *doc = gsf_xml_in_doc_new (dtd, NULL);
3733 	XMLSaxParseState *state = g_new0 (XMLSaxParseState, 1);
3734 
3735 	read_file_init_state (state, NULL, NULL, NULL);
3736 	state->style_handler = handler;
3737 	state->style_handler_user = user;
3738 	state->style_handler_doc = doc;
3739 	state->style = gnm_style_new_default ();
3740 
3741 	/* Not a full style, just those parts that do not require a sheet.  */
3742 	gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3743 				   "STYLE_FONT",
3744 				   "STYLE_STYLE");
3745 	gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3746 				   "STYLE_BORDER",
3747 				   "STYLE_STYLE");
3748 
3749 	gsf_xml_in_push_state (xin, doc, state,
3750 			       (GsfXMLInExtDtor)style_parser_done, attrs);
3751 }
3752 
3753 /* ------------------------------------------------------------------------- */
3754 
3755 static gboolean
gnm_xml_probe_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)3756 gnm_xml_probe_element (const xmlChar *name,
3757 		       G_GNUC_UNUSED const xmlChar *prefix,
3758 		       const xmlChar *URI,
3759 		       G_GNUC_UNUSED int nb_namespaces,
3760 		       G_GNUC_UNUSED const xmlChar **namespaces,
3761 		       G_GNUC_UNUSED int nb_attributes,
3762 		       G_GNUC_UNUSED int nb_defaulted,
3763 		       G_GNUC_UNUSED const xmlChar **attributes)
3764 {
3765 	return 0 == strcmp (name, "Workbook") &&
3766 		NULL != URI && NULL != strstr (URI, "gnumeric");
3767 }
3768 
3769 static gboolean
xml_probe(G_GNUC_UNUSED GOFileOpener const * fo,GsfInput * input,GOFileProbeLevel pl)3770 xml_probe (G_GNUC_UNUSED GOFileOpener const *fo, GsfInput *input, GOFileProbeLevel pl)
3771 {
3772 	if (pl == GO_FILE_PROBE_FILE_NAME) {
3773 		char const *name = gsf_input_name (input);
3774 		int len;
3775 
3776 		if (name == NULL)
3777 			return FALSE;
3778 
3779 		len = strlen (name);
3780 		if (len >= 7 && !g_ascii_strcasecmp (name+len-7, ".xml.gz"))
3781 			return TRUE;
3782 
3783 		name = gsf_extension_pointer (name);
3784 
3785 		return (name != NULL &&
3786 			(g_ascii_strcasecmp (name, "gnumeric") == 0 ||
3787 			 g_ascii_strcasecmp (name, "xml") == 0));
3788 	}
3789 	/* probe by content */
3790 	return gsf_xml_probe (input, &gnm_xml_probe_element);
3791 }
3792 
3793 #define XML_SAX_ID "Gnumeric_XmlIO:sax"
3794 
3795 void
gnm_xml_sax_read_init(void)3796 gnm_xml_sax_read_init (void)
3797 {
3798 	GOFileOpener *opener;
3799 	GSList *suffixes = go_slist_create (g_strdup ("gnumeric"),
3800 					    g_strdup ("xml"),
3801 					    NULL);
3802 	GSList *mimes = go_slist_create (g_strdup ("application/x-gnumeric"),
3803 					 NULL);
3804 
3805 	opener = go_file_opener_new
3806 		(XML_SAX_ID,
3807 		 _("Gnumeric XML (*.gnumeric)"),
3808 		 suffixes, mimes,
3809 		 xml_probe, gnm_xml_file_open);
3810 	go_file_opener_register (opener, 50);
3811 	g_object_unref (opener);
3812 }
3813 
3814 void
gnm_xml_sax_read_shutdown(void)3815 gnm_xml_sax_read_shutdown (void)
3816 {
3817 	go_file_opener_unregister
3818 		(go_file_opener_for_id (XML_SAX_ID));
3819 }
3820