Introspection: fix problems with boxed type.
[gnumeric.git] / src / xml-sax-read.c
blobf0a6267013ff3ed549838d32e000f6c188f85213
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * xml-sax-read.c : a sax based parser.
6 * Copyright (C) 2000-2007 Jody Goldberg (jody@gnome.org)
7 * Copyright (C) 2007-2009 Morten Welinder (terra@gnome.org)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) version 3.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 * USA
25 #include <gnumeric-config.h>
26 #include <gnumeric.h>
27 #include "xml-sax.h"
28 #include "xml-io-version.h"
29 #include "gnm-plugin.h"
30 #include "sheet-view.h"
31 #include "sheet-style.h"
32 #include "sheet-merge.h"
33 #include "sheet-filter.h"
34 #include "sheet.h"
35 #include "ranges.h"
36 #include <tools/gnm-solver.h>
37 #include <tools/scenarios.h>
38 #include "style.h"
39 #include "style-border.h"
40 #include "style-color.h"
41 #include "style-conditions.h"
42 #include "validation.h"
43 #include "hlink.h"
44 #include "input-msg.h"
45 #include "cell.h"
46 #include "position.h"
47 #include "expr.h"
48 #include "expr-name.h"
49 #include "print-info.h"
50 #include "value.h"
51 #include "selection.h"
52 #include "command-context.h"
53 #include "workbook-view.h"
54 #include "workbook-control.h"
55 #include "workbook.h"
56 #include "sheet-object-impl.h"
57 #include "sheet-object-cell-comment.h"
58 #include "gnm-so-line.h"
59 #include "gnm-so-filled.h"
60 #include "gnm-so-path.h"
61 #include "gnm-format.h"
62 #include "sheet-object-graph.h"
63 #include "sheet-object-component.h"
64 #include "application.h"
65 #include "gutils.h"
66 #include "clipboard.h"
67 #include "number-match.h"
69 #include <goffice/goffice.h>
71 #include <gsf/gsf-libxml.h>
72 #include <gsf/gsf-input.h>
73 #include <gsf/gsf-input-memory.h>
74 #include <gsf/gsf-input-gzip.h>
75 #include <gsf/gsf-opendoc-utils.h>
76 #include <gsf/gsf-utils.h>
77 #include <glib/gi18n-lib.h>
78 #include <libxml/tree.h>
79 #include <libxml/parser.h>
80 #include <libxml/parserInternals.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <errno.h>
85 /* libgsf defines OO_NS_OFFICE to be 0, so we need to take something different for GNM */
86 #define GNM 100
88 static void
89 xml_sax_barf (const char *locus, const char *reason)
91 g_warning ("File is most likely corrupted.\n"
92 "The problem was detected in %s.\n"
93 "The failed check was: %s",
94 locus, reason);
97 #define XML_CHECK3(_cond_,_code_,_reason_) \
98 do { \
99 if (G_UNLIKELY(!(_cond_))) { \
100 xml_sax_barf (G_STRFUNC, _reason_); \
101 _code_; \
102 return; \
104 } while (0)
106 #define XML_CHECK(_cond_) XML_CHECK3(_cond_,{},#_cond_)
107 #define XML_CHECK2(_cond_,_code_) XML_CHECK3(_cond_,_code_,#_cond_)
110 #define CXML2C(s) ((char const *)(s))
112 static inline gboolean
113 attr_eq (const xmlChar *a, const char *s)
115 return !strcmp (CXML2C (a), s);
118 static GOFormat *
119 make_format (const char *str)
121 GOFormat *res =
122 gnm_format_import (str,
123 GNM_FORMAT_IMPORT_NULL_INVALID |
124 GNM_FORMAT_IMPORT_PATCHUP_INCOMPLETE);
125 if (!res) {
126 g_warning ("Ignoring invalid format [%s]", str);
127 return NULL;
130 return res;
133 /*****************************************************************************/
135 gboolean
136 gnm_xml_attr_double (xmlChar const * const *attrs, char const *name, double * res)
138 char *end;
139 double tmp;
141 g_return_val_if_fail (attrs != NULL, FALSE);
142 g_return_val_if_fail (attrs[0] != NULL, FALSE);
143 g_return_val_if_fail (attrs[1] != NULL, FALSE);
145 if (!attr_eq (attrs[0], name))
146 return FALSE;
148 tmp = go_strtod (CXML2C (attrs[1]), &end);
149 if (*end) {
150 g_warning ("Invalid attribute '%s', expected double, received '%s'",
151 name, attrs[1]);
152 return FALSE;
154 *res = tmp;
155 return TRUE;
158 static gboolean
159 xml_sax_double (xmlChar const *chars, double *res)
161 char *end;
162 *res = go_strtod (CXML2C (chars), &end);
163 return *end == '\0';
166 gboolean
167 gnm_xml_attr_bool (xmlChar const * const *attrs, char const *name, gboolean *res)
169 g_return_val_if_fail (attrs != NULL, FALSE);
170 g_return_val_if_fail (attrs[0] != NULL, FALSE);
171 g_return_val_if_fail (attrs[1] != NULL, FALSE);
173 if (!attr_eq (attrs[0], name))
174 return FALSE;
176 *res = g_ascii_strcasecmp (CXML2C (attrs[1]), "false") && strcmp (CXML2C (attrs[1]), "0");
178 return TRUE;
181 gboolean
182 gnm_xml_attr_int (xmlChar const * const *attrs, char const *name, int *res)
184 char *end;
185 long tmp;
187 g_return_val_if_fail (attrs != NULL, FALSE);
188 g_return_val_if_fail (attrs[0] != NULL, FALSE);
189 g_return_val_if_fail (attrs[1] != NULL, FALSE);
191 if (!attr_eq (attrs[0], name))
192 return FALSE;
194 errno = 0;
195 tmp = strtol (CXML2C (attrs[1]), &end, 10);
196 if (*end || errno) {
197 g_warning ("Invalid attribute '%s', expected integer, received '%s'",
198 name, attrs[1]);
199 return FALSE;
201 *res = tmp;
202 return TRUE;
205 /* NOT SUITABLE FOR HIGH VOLUME VALUES
206 * Checking both name and nick gets expensive */
207 static gboolean
208 xml_sax_attr_enum (xmlChar const * const *attrs,
209 char const *name,
210 GType etype,
211 gint *val)
213 GEnumClass *eclass;
214 GEnumValue *ev;
215 int i;
217 g_return_val_if_fail (attrs != NULL, FALSE);
218 g_return_val_if_fail (attrs[0] != NULL, FALSE);
219 g_return_val_if_fail (attrs[1] != NULL, FALSE);
221 if (!attr_eq (attrs[0], name))
222 return FALSE;
224 eclass = G_ENUM_CLASS (g_type_class_ref (etype));
225 ev = g_enum_get_value_by_name (eclass, CXML2C (attrs[1]));
226 if (!ev) ev = g_enum_get_value_by_nick (eclass, CXML2C (attrs[1]));
227 g_type_class_unref (eclass);
229 if (!ev && gnm_xml_attr_int (attrs, name, &i))
230 /* Check that the value is valid. */
231 ev = g_enum_get_value (eclass, i);
232 if (!ev) return FALSE;
234 *val = ev->value;
235 return TRUE;
239 static gboolean
240 xml_sax_attr_cellpos (xmlChar const * const *attrs, char const *name, GnmCellPos *val, Sheet const *sheet)
242 g_return_val_if_fail (attrs != NULL, FALSE);
243 g_return_val_if_fail (attrs[0] != NULL, FALSE);
244 g_return_val_if_fail (attrs[1] != NULL, FALSE);
246 if (!attr_eq (attrs[0], name))
247 return FALSE;
249 if (cellpos_parse (CXML2C (attrs[1]), gnm_sheet_get_size (sheet), val, TRUE) == NULL) {
250 g_warning ("Invalid attribute '%s', expected cellpos, received '%s'",
251 name, attrs[1]);
252 return FALSE;
254 return TRUE;
257 static gboolean
258 xml_sax_attr_color (xmlChar const * const *attrs, char const *name, GnmColor **res)
260 unsigned int red, green, blue, alpha = 0xffff;
262 g_return_val_if_fail (attrs != NULL, FALSE);
263 g_return_val_if_fail (attrs[0] != NULL, FALSE);
264 g_return_val_if_fail (attrs[1] != NULL, FALSE);
266 if (!attr_eq (attrs[0], name))
267 return FALSE;
269 if (sscanf (CXML2C (attrs[1]), "%X:%X:%X:%X", &red, &green, &blue, &alpha) < 3){
270 g_warning ("Invalid attribute '%s', expected colour, received '%s'",
271 name, attrs[1]);
272 return FALSE;
274 *res = gnm_color_new_rgba16 (red, green, blue, alpha);
275 return TRUE;
278 static gboolean
279 xml_sax_attr_range (xmlChar const * const *attrs, GnmRange *res)
281 int flags = 0;
283 g_return_val_if_fail (attrs != NULL, FALSE);
285 for (; attrs[0] && attrs[1] ; attrs += 2)
286 if (gnm_xml_attr_int (attrs, "startCol", &res->start.col))
287 flags |= 0x1;
288 else if (gnm_xml_attr_int (attrs, "startRow", &res->start.row))
289 flags |= 0x2;
290 else if (gnm_xml_attr_int (attrs, "endCol", &res->end.col))
291 flags |= 0x4;
292 else if (gnm_xml_attr_int (attrs, "endRow", &res->end.row))
293 flags |= 0x8;
294 else
295 return FALSE;
297 return flags == 0xf;
300 /*****************************************************************************/
302 typedef struct {
303 GsfXMLIn base;
305 GOIOContext *context; /* The IOcontext managing things */
306 WorkbookView *wb_view; /* View for the new workbook */
307 Workbook *wb; /* The new workbook */
308 GnumericXMLVersion version;
309 gsf_off_t last_progress_update;
310 GnmConventions *convs;
311 gboolean do_progress;
313 Sheet *sheet;
314 double sheet_zoom;
316 /* Only valid while parsing attributes */
317 struct {
318 char *name;
319 char *value;
320 } attribute;
322 /* Only valid when parsing wb or sheet names */
323 struct {
324 char *name;
325 char *value;
326 char *position;
327 } name;
329 struct {
330 char *title;
331 char *msg;
332 GnmExprTop const *texpr[2];
333 ValidationStyle style;
334 ValidationType type;
335 ValidationOp op;
336 gboolean allow_blank;
337 gboolean use_dropdown;
338 } validation;
340 GnmStyleCond *cond;
341 GnmStyle *cond_save_style;
343 gboolean style_range_init;
344 GnmRange style_range;
345 GnmStyle *style;
347 GnmCellPos cell;
348 gboolean seen_cell_contents;
349 int expr_id, array_rows, array_cols;
350 int value_type;
351 GOFormat *value_fmt;
353 GnmScenario *scenario;
354 GnmValue *scenario_range;
356 GnmFilter *filter;
358 int display_formulas;
359 int hide_zero;
360 int hide_grid;
361 int hide_col_header;
362 int hide_row_header;
363 int display_outlines;
364 int outline_symbols_below;
365 int outline_symbols_right;
366 int text_is_rtl;
367 int is_protected;
368 char *expr_conv_name;
369 GnmSheetVisibility visibility;
370 GnmColor *tab_color;
371 GnmColor *tab_text_color;
372 GnmColor *grid_color;
374 /* expressions with ref > 1 a map from index -> expr pointer */
375 GHashTable *expr_map;
376 GList *delayed_names;
377 SheetObject *so;
379 int sheet_rows, sheet_cols;
380 GnmSheetType sheet_type;
382 GnmPageBreaks *page_breaks;
384 GnmCellRegion *clipboard;
386 GnmXmlStyleHandler style_handler;
387 gpointer style_handler_user;
388 GsfXMLInDoc *style_handler_doc;
389 } XMLSaxParseState;
391 static void
392 maybe_update_progress (GsfXMLIn *xin)
394 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
395 GsfInput *input = gsf_xml_in_get_input (xin);
396 gsf_off_t pos = gsf_input_tell (input);
398 if (state->do_progress && pos >= state->last_progress_update + 10000) {
399 go_io_value_progress_update (state->context, pos);
400 state->last_progress_update = pos;
405 * gnm_xml_in_cur_obj:
406 * @xin: #GsfXMLIn
408 * Returns: (transfer none): the current sheet object.
410 SheetObject *
411 gnm_xml_in_cur_obj (GsfXMLIn const *xin)
413 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
414 return state->so;
418 * gnm_xml_in_cur_sheet:
419 * @xin: #GsfXMLIn
421 * Returns: (transfer none): the current sheet.
423 Sheet *
424 gnm_xml_in_cur_sheet (GsfXMLIn const *xin)
426 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
427 return state->sheet;
430 static void
431 gnm_xml_finish_obj (GsfXMLIn *xin, XMLSaxParseState *state)
433 GnmCellRegion *cr = state->clipboard;
435 if (cr) {
436 cr->objects = g_slist_prepend (cr->objects, state->so);
437 } else {
438 sheet_object_set_sheet (state->so, state->sheet);
439 g_object_unref (state->so);
442 state->so = NULL;
445 /****************************************************************************/
447 static void
448 unknown_attr (GsfXMLIn *xin, xmlChar const * const *attrs)
450 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
452 if (state->version == GNM_XML_LATEST)
453 go_io_warning (state->context,
454 _("Unexpected attribute %s::%s == '%s'."),
455 (NULL != xin->node &&
456 NULL != xin->node->name) ?
457 xin->node->name : "<unknown name>",
458 attrs[0], attrs[1]);
461 static void
462 xml_sax_wb (GsfXMLIn *xin, xmlChar const **attrs)
464 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
467 * NOTE: If we read a file with a dtd that is newer, i.e., from the
468 * future, then we will not get here! For that reason we also muck
469 * with ->version in xml_sax_version.
471 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
472 if (strcmp (CXML2C (attrs[0]), "xmlns:gmr") == 0 ||
473 strcmp (CXML2C (attrs[0]), "xmlns:gnm") == 0) {
474 static struct {
475 char const * const id;
476 GnumericXMLVersion const version;
477 } const GnumericVersions [] = {
478 { "http://www.gnumeric.org/v14.dtd", GNM_XML_V14 }, /* 1.12.21 */
479 { "http://www.gnumeric.org/v13.dtd", GNM_XML_V13 }, /* 1.7.7 */
480 { "http://www.gnumeric.org/v12.dtd", GNM_XML_V12 }, /* 1.7.3 */
481 { "http://www.gnumeric.org/v11.dtd", GNM_XML_V11 }, /* 1.7.0 */
482 { "http://www.gnumeric.org/v10.dtd", GNM_XML_V10 }, /* 1.0.3 */
483 { "http://www.gnumeric.org/v9.dtd", GNM_XML_V9 }, /* 0.73 */
484 { "http://www.gnumeric.org/v8.dtd", GNM_XML_V8 }, /* 0.71 */
485 { "http://www.gnome.org/gnumeric/v7", GNM_XML_V7 }, /* 0.66 */
486 { "http://www.gnome.org/gnumeric/v6", GNM_XML_V6 }, /* 0.62 */
487 { "http://www.gnome.org/gnumeric/v5", GNM_XML_V5 },
488 { "http://www.gnome.org/gnumeric/v4", GNM_XML_V4 },
489 { "http://www.gnome.org/gnumeric/v3", GNM_XML_V3 },
490 { "http://www.gnome.org/gnumeric/v2", GNM_XML_V2 },
491 { "http://www.gnome.org/gnumeric/", GNM_XML_V1 },
492 { NULL, 0}
494 int i;
495 for (i = 0 ; GnumericVersions [i].id != NULL ; ++i )
496 if (strcmp (CXML2C (attrs[1]), GnumericVersions [i].id) == 0) {
497 if (state->version != GNM_XML_UNKNOWN)
498 go_io_warning (state->context,
499 _("Multiple version specifications. Assuming %d"),
500 state->version);
501 else {
502 state->version = GnumericVersions [i].version;
503 break;
506 } else if (attr_eq (attrs[0], "xmlns:xsi")) {
507 } else if (attr_eq (attrs[0], "xsi:schemaLocation")) {
508 } else
509 unknown_attr (xin, attrs);
513 static void
514 xml_sax_document_meta (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
516 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
518 gsf_doc_meta_data_odf_subtree (go_doc_get_meta_data (GO_DOC (state->wb)), xin);
523 static void
524 xml_sax_version (GsfXMLIn *xin, xmlChar const **attrs)
526 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
527 int epoch = -1;
528 int major = -1;
529 int minor = -1;
530 int version;
532 state->version = GNM_XML_V11;
533 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
534 if (gnm_xml_attr_int (attrs, "Epoch", &epoch))
535 /* Nothing */ ;
536 else if (gnm_xml_attr_int (attrs, "Major", &major))
537 /* Nothing */ ;
538 else if (gnm_xml_attr_int (attrs, "Minor", &minor))
539 /* Nothing */ ;
542 version = (epoch * 100 + major) * 100 + minor;
543 if (state->version == GNM_XML_UNKNOWN && version >= 10700) {
544 if (version >= 11221)
545 state->version = GNM_XML_V14;
546 else if (version >= 10707)
547 state->version = GNM_XML_V13;
548 else if (version >= 10705)
549 state->version = GNM_XML_V12;
550 else if (version >= 10700)
551 state->version = GNM_XML_V11;
555 static void
556 xml_sax_wb_sheetsize (GsfXMLIn *xin, xmlChar const **attrs)
558 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
560 /* Defaults for legacy files. */
561 state->sheet_cols = 256;
562 state->sheet_rows = 65536;
563 state->sheet_type = GNM_SHEET_DATA;
565 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
566 if (gnm_xml_attr_int (attrs, "gnm:Cols", &state->sheet_cols))
567 ; /* Nothing more */
568 else if (gnm_xml_attr_int (attrs, "gnm:Rows", &state->sheet_rows))
569 ; /* Nothing more */
570 else if (!strcmp (CXML2C (attrs[0]), "gnm:SheetType") &&
571 !strcmp (CXML2C (attrs[1]), "object"))
572 state->sheet_type = GNM_SHEET_OBJECT;
573 else
574 unknown_attr (xin, attrs);
578 static void
579 xml_sax_wb_sheetname (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
581 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
582 char const *name = xin->content->str;
583 Workbook *wb = state->wb;
585 g_return_if_fail (name != NULL);
587 if (NULL == workbook_sheet_by_name (wb, name)) {
588 Sheet *sheet;
590 if (!gnm_sheet_valid_size (state->sheet_cols,
591 state->sheet_rows)) {
592 gnm_sheet_suggest_size (&state->sheet_cols,
593 &state->sheet_rows);
596 sheet = sheet_new_with_type (wb, name,
597 state->sheet_type,
598 state->sheet_cols,
599 state->sheet_rows);
600 workbook_sheet_attach (wb, sheet);
604 static void
605 xml_sax_wb_view (GsfXMLIn *xin, xmlChar const **attrs)
607 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
609 int sheet_index;
610 int width = -1, height = -1;
612 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
613 if (gnm_xml_attr_int (attrs, "SelectedTab", &sheet_index)) {
614 Sheet *sheet = workbook_sheet_by_index (state->wb,
615 sheet_index);
616 if (sheet)
617 wb_view_sheet_focus (state->wb_view, sheet);
619 else if (gnm_xml_attr_int (attrs, "Width", &width)) ;
620 else if (gnm_xml_attr_int (attrs, "Height", &height)) ;
621 else
622 unknown_attr (xin, attrs);
624 if (width > 0 && height > 0)
625 wb_view_preferred_size (state->wb_view, width, height);
627 static void
628 xml_sax_calculation (GsfXMLIn *xin, xmlChar const **attrs)
630 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
631 gboolean b;
632 int i;
633 double d;
635 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
636 if (gnm_xml_attr_bool (attrs, "ManualRecalc", &b))
637 workbook_set_recalcmode (state->wb, !b);
638 else if (gnm_xml_attr_bool (attrs, "EnableIteration", &b))
639 workbook_iteration_enabled (state->wb, b);
640 else if (gnm_xml_attr_int (attrs, "MaxIterations", &i))
641 workbook_iteration_max_number (state->wb, i);
642 else if (gnm_xml_attr_double (attrs, "IterationTolerance", &d))
643 workbook_iteration_tolerance (state->wb, d);
644 else if (strcmp (CXML2C (attrs[0]), "DateConvention") == 0) {
645 GODateConventions const *date_conv =
646 go_date_conv_from_str (CXML2C (attrs[1]));
647 if (date_conv)
648 workbook_set_date_conv (state->wb, date_conv);
649 else
650 g_printerr ("Ignoring invalid date conventions.\n");
651 } else
652 unknown_attr (xin, attrs);
655 static void
656 xml_sax_old_dateconvention (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
658 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
659 workbook_set_1904 (state->wb, strcmp (xin->content->str, "1904") == 0);
662 static void
663 xml_sax_finish_parse_wb_attr (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
665 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
667 if (state->attribute.name && state->attribute.value) {
668 wb_view_set_attribute (state->wb_view,
669 state->attribute.name,
670 state->attribute.value);
671 } else {
672 xml_sax_barf (G_STRFUNC, _("workbook view attribute is incomplete"));
675 g_free (state->attribute.value); state->attribute.value = NULL;
676 g_free (state->attribute.name); state->attribute.name = NULL;
679 static void
680 xml_sax_attr_elem (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
682 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
684 char const *content = xin->content->str;
685 int const len = xin->content->len;
687 switch (xin->node->user_data.v_int) {
688 case 0 :
689 g_return_if_fail (state->attribute.name == NULL);
690 state->attribute.name = g_strndup (content, len);
691 break;
693 case 1 :
694 g_return_if_fail (state->attribute.value == NULL);
695 state->attribute.value = g_strndup (content, len);
696 break;
698 default :
699 g_assert_not_reached ();
703 static void
704 xml_sax_sheet_start (GsfXMLIn *xin, xmlChar const **attrs)
706 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
708 gboolean tmp;
709 gint tmpi;
710 GnmColor *color = NULL;
712 state->hide_col_header = state->hide_row_header =
713 state->display_formulas = state->hide_zero =
714 state->hide_grid = state->display_outlines =
715 state->outline_symbols_below = state->outline_symbols_right =
716 state->text_is_rtl = state->is_protected = -1;
717 state->expr_conv_name = NULL;
718 state->visibility = GNM_SHEET_VISIBILITY_VISIBLE;
719 state->tab_color = NULL;
720 state->tab_text_color = NULL;
721 state->grid_color = NULL;
722 state->sheet_zoom = 1.; /* default */
724 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
725 if (gnm_xml_attr_bool (attrs, "DisplayFormulas", &tmp))
726 state->display_formulas = tmp;
727 else if (gnm_xml_attr_bool (attrs, "HideZero", &tmp))
728 state->hide_zero = tmp;
729 else if (gnm_xml_attr_bool (attrs, "HideGrid", &tmp))
730 state->hide_grid = tmp;
731 else if (gnm_xml_attr_bool (attrs, "HideColHeader", &tmp))
732 state->hide_col_header = tmp;
733 else if (gnm_xml_attr_bool (attrs, "HideRowHeader", &tmp))
734 state->hide_row_header = tmp;
735 else if (gnm_xml_attr_bool (attrs, "DisplayOutlines", &tmp))
736 state->display_outlines = tmp;
737 else if (gnm_xml_attr_bool (attrs, "OutlineSymbolsBelow", &tmp))
738 state->outline_symbols_below = tmp;
739 else if (gnm_xml_attr_bool (attrs, "OutlineSymbolsRight", &tmp))
740 state->outline_symbols_right = tmp;
741 else if (xml_sax_attr_enum (attrs, "Visibility", GNM_SHEET_VISIBILITY_TYPE, &tmpi))
742 state->visibility = tmpi;
743 else if (gnm_xml_attr_bool (attrs, "RTL_Layout", &tmp))
744 state->text_is_rtl = tmp;
745 else if (gnm_xml_attr_bool (attrs, "Protected", &tmp))
746 state->is_protected = tmp;
747 else if (strcmp (CXML2C (attrs[0]), "ExprConvention") == 0)
748 state->expr_conv_name = g_strdup (attrs[1]);
749 else if (xml_sax_attr_color (attrs, "TabColor", &color))
750 state->tab_color = color;
751 else if (xml_sax_attr_color (attrs, "TabTextColor", &color))
752 state->tab_text_color = color;
753 else if (xml_sax_attr_color (attrs, "GridColor", &color))
754 state->grid_color = color;
755 else
756 unknown_attr (xin, attrs);
759 static Sheet *
760 xml_sax_must_have_sheet (XMLSaxParseState *state)
762 if (!state->sheet) {
763 int columns = 256;
764 int rows = 65536;
766 xml_sax_barf (G_STRFUNC, "sheet should have been named");
768 state->sheet = workbook_sheet_add (state->wb, -1,
769 columns, rows);
772 return state->sheet;
775 static GnmStyle *
776 xml_sax_must_have_style (XMLSaxParseState *state)
778 if (!state->style) {
779 xml_sax_barf (G_STRFUNC, "style should have been started");
780 state->style = (state->version >= GNM_XML_V6 ||
781 state->version <= GNM_XML_V2)
782 ? gnm_style_new_default ()
783 : gnm_style_new ();
786 return state->style;
790 static void
791 xml_sax_sheet_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
793 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
795 xml_sax_must_have_sheet (state);
797 /* Init ColRowInfo's size_pixels and force a full respan */
798 g_object_set (state->sheet, "zoom-factor", state->sheet_zoom, NULL);
799 sheet_flag_recompute_spans (state->sheet);
800 state->sheet = NULL;
803 static void
804 xml_sax_sheet_name (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
806 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
807 Sheet *sheet;
808 int columns = 256;
809 int rows = 65536;
811 char const * content = xin->content->str;
812 g_return_if_fail (state->sheet == NULL);
814 /* * FIXME: Pull this out at some point, so we don't
815 * have to support < GNM_XML_V7 anymore
817 if (state->version >= GNM_XML_V7) {
818 sheet = workbook_sheet_by_name (state->wb, content);
819 if (!sheet) {
820 go_io_error_string (state->context,
821 _("File has inconsistent SheetNameIndex element."));
822 sheet = sheet_new (state->wb, content,
823 columns, rows);
824 workbook_sheet_attach (state->wb, sheet);
826 } else {
827 sheet = sheet_new (state->wb, content, columns, rows);
828 workbook_sheet_attach (state->wb, sheet);
830 state->sheet = sheet;
832 if (state->display_formulas >= 0)
833 g_object_set (sheet, "display-formulas", state->display_formulas, NULL);
834 if (state->hide_zero >= 0)
835 g_object_set (sheet, "display-zeros", !state->hide_zero, NULL);
836 if (state->hide_grid >= 0)
837 g_object_set (sheet, "display-grid", !state->hide_grid, NULL);
838 if (state->hide_col_header >= 0)
839 g_object_set (sheet, "display-column-header", !state->hide_col_header, NULL);
840 if (state->hide_row_header >= 0)
841 g_object_set (sheet, "display-row-header", !state->hide_row_header, NULL);
842 if (state->display_outlines >= 0)
843 g_object_set (sheet, "display-outlines", state->display_outlines, NULL);
844 if (state->outline_symbols_below >= 0)
845 g_object_set (sheet, "display-outlines-below", state->outline_symbols_below, NULL);
846 if (state->outline_symbols_right >= 0)
847 g_object_set (sheet, "display-outlines-right", state->outline_symbols_right, NULL);
848 if (state->text_is_rtl >= 0)
849 g_object_set (sheet, "text-is-rtl", state->text_is_rtl, NULL);
850 if (state->is_protected >= 0)
851 g_object_set (sheet, "protected", state->is_protected, NULL);
852 if (state->expr_conv_name != NULL) {
853 GnmConventions const *convs = gnm_conventions_default;
854 if (0 == strcmp (state->expr_conv_name, "gnumeric:R1C1"))
855 convs = gnm_conventions_xls_r1c1;
856 g_object_set (sheet, "conventions", convs, NULL);
858 g_free (state->expr_conv_name);
859 state->expr_conv_name = NULL;
861 g_object_set (sheet, "visibility", state->visibility, NULL);
862 sheet->tab_color = state->tab_color;
863 sheet->tab_text_color = state->tab_text_color;
864 if (state->grid_color)
865 sheet_style_set_auto_pattern_color (sheet, state->grid_color);
868 static void
869 xml_sax_sheet_zoom (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
871 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
873 char const * content = xin->content->str;
874 double zoom;
876 xml_sax_must_have_sheet (state);
878 if (xml_sax_double ((xmlChar *)content, &zoom))
879 state->sheet_zoom = zoom;
882 static void
883 xml_sax_print_margins_unit (GsfXMLIn *xin, xmlChar const **attrs,
884 double *points, GtkUnit *desired_display)
886 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
887 double pts;
888 if (gnm_xml_attr_double (attrs, "Points", &pts)) {
889 *points = pts;
890 } else if (attr_eq (attrs[0], "PrefUnit")) {
891 *desired_display = unit_name_to_unit (CXML2C (attrs[1]));
892 } else
893 unknown_attr (xin, attrs);
897 static void
898 xml_sax_print_margins (GsfXMLIn *xin, xmlChar const **attrs)
900 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
902 GnmPrintInformation *pi;
903 double points = -1.;
905 xml_sax_must_have_sheet (state);
907 pi = state->sheet->print_info;
908 switch (xin->node->user_data.v_int) {
909 case 0:
910 xml_sax_print_margins_unit (xin, attrs,
911 &points,
912 &pi->desired_display.header);
913 if (points >= 0.)
914 print_info_set_edge_to_below_header (pi, points);
915 break;
916 case 1:
917 xml_sax_print_margins_unit (xin, attrs,
918 &points,
919 &pi->desired_display.footer);
920 if (points >= 0.)
921 print_info_set_edge_to_above_footer (pi, points);
922 break;
923 case 2:
924 xml_sax_print_margins_unit (xin, attrs,
925 &points, &pi->desired_display.left);
926 if (points >= 0.)
927 print_info_set_margin_left (pi, points);
928 break;
929 case 3:
930 xml_sax_print_margins_unit (xin, attrs,
931 &points, &pi->desired_display.right);
932 if (points >= 0.)
933 print_info_set_margin_right (pi, points);
934 break;
935 case 4:
936 xml_sax_print_margins_unit (xin, attrs,
937 &points, &pi->desired_display.top);
938 if (points >= 0.)
939 print_info_set_margin_header (pi, points);
940 break;
941 case 5:
942 xml_sax_print_margins_unit (xin, attrs,
943 &points, &pi->desired_display.bottom);
944 if (points >= 0.)
945 print_info_set_margin_footer (pi, points);
946 break;
947 default:
948 return;
953 static void
954 xml_sax_page_break (GsfXMLIn *xin, xmlChar const **attrs)
956 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
957 GnmPageBreakType type = GNM_PAGE_BREAK_NONE;
958 int pos = -1;
960 if (NULL == state->page_breaks)
961 return;
963 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
964 if (gnm_xml_attr_int (attrs, "pos", &pos)) ;
965 else if (!strcmp (CXML2C (attrs[0]), "type"))
966 type = gnm_page_break_type_from_str (CXML2C (attrs[1]));
968 /* drops invalid positions */
969 gnm_page_breaks_append_break (state->page_breaks, pos, type);
972 static void
973 xml_sax_page_breaks_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
975 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
976 xml_sax_must_have_sheet (state);
977 g_return_if_fail (state->page_breaks == NULL);
978 state->page_breaks = gnm_page_breaks_new (xin->node->user_data.v_int);
981 static void
982 xml_sax_page_breaks_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
984 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
986 if (NULL != state->page_breaks) {
987 print_info_set_breaks (state->sheet->print_info,
988 state->page_breaks);
989 state->page_breaks = NULL;
993 static void
994 xml_sax_print_scale (GsfXMLIn *xin, xmlChar const **attrs)
996 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
998 GnmPrintInformation *pi;
999 double percentage;
1000 int cols, rows;
1002 xml_sax_must_have_sheet (state);
1004 pi = state->sheet->print_info;
1005 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1006 if (attr_eq (attrs[0], "type"))
1007 pi->scaling.type = !strcmp (CXML2C (attrs[1]), "percentage")
1008 ? PRINT_SCALE_PERCENTAGE : PRINT_SCALE_FIT_PAGES;
1009 else if (gnm_xml_attr_double (attrs, "percentage", &percentage))
1010 pi->scaling.percentage.x = pi->scaling.percentage.y = percentage;
1011 else if (gnm_xml_attr_int (attrs, "cols", &cols))
1012 pi->scaling.dim.cols = cols;
1013 else if (gnm_xml_attr_int (attrs, "rows", &rows))
1014 pi->scaling.dim.rows = rows;
1018 static void
1019 xml_sax_print_vcenter (GsfXMLIn *xin, xmlChar const **attrs)
1021 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1022 GnmPrintInformation *pi;
1023 int val;
1025 xml_sax_must_have_sheet (state);
1027 pi = state->sheet->print_info;
1029 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1030 if (gnm_xml_attr_int (attrs, "value", &val))
1031 pi->center_vertically = val;
1034 static void
1035 xml_sax_print_hcenter (GsfXMLIn *xin, xmlChar const **attrs)
1037 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1038 GnmPrintInformation *pi;
1039 int val;
1041 xml_sax_must_have_sheet (state);
1043 pi = state->sheet->print_info;
1045 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1046 if (gnm_xml_attr_int (attrs, "value", &val))
1047 pi->center_horizontally = val;
1050 static void
1051 xml_sax_print_grid (GsfXMLIn *xin, xmlChar const **attrs)
1053 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1054 GnmPrintInformation *pi;
1055 int val;
1057 xml_sax_must_have_sheet (state);
1059 pi = state->sheet->print_info;
1061 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1062 if (gnm_xml_attr_int (attrs, "value", &val))
1063 pi->print_grid_lines = val;
1066 static void
1067 xml_sax_print_do_not_print (GsfXMLIn *xin, xmlChar const **attrs)
1069 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1070 GnmPrintInformation *pi;
1071 int val;
1073 xml_sax_must_have_sheet (state);
1075 pi = state->sheet->print_info;
1077 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1078 if (gnm_xml_attr_int (attrs, "value", &val))
1079 pi->do_not_print = val;
1082 static void
1083 xml_sax_print_print_range (GsfXMLIn *xin, xmlChar const **attrs)
1085 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1086 GnmPrintInformation *pi;
1087 int val;
1089 xml_sax_must_have_sheet (state);
1091 pi = state->sheet->print_info;
1093 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1094 if (xml_sax_attr_enum (attrs, "value", GNM_PRINT_RANGE_TYPE,
1095 &val))
1096 print_info_set_printrange (pi, val);
1101 static void
1102 xml_sax_monochrome (GsfXMLIn *xin, xmlChar const **attrs)
1104 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1105 GnmPrintInformation *pi;
1106 int val;
1108 xml_sax_must_have_sheet (state);
1110 pi = state->sheet->print_info;
1112 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1113 if (gnm_xml_attr_int (attrs, "value", &val))
1114 pi->print_black_and_white = val;
1117 static void
1118 xml_sax_print_titles (GsfXMLIn *xin, xmlChar const **attrs)
1120 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1121 GnmPrintInformation *pi;
1122 int val;
1124 xml_sax_must_have_sheet (state);
1126 pi = state->sheet->print_info;
1128 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1129 if (gnm_xml_attr_int (attrs, "value", &val))
1130 pi->print_titles = val;
1133 static void
1134 xml_sax_repeat_top (GsfXMLIn *xin, xmlChar const **attrs)
1136 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1137 GnmPrintInformation *pi;
1139 xml_sax_must_have_sheet (state);
1141 pi = state->sheet->print_info;
1143 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1144 if (!strcmp (CXML2C (attrs[0]), "value")) {
1145 g_free (pi->repeat_top);
1146 pi->repeat_top = g_strdup (CXML2C (attrs[1]));
1147 break;
1151 static void
1152 xml_sax_repeat_left (GsfXMLIn *xin, xmlChar const **attrs)
1154 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1155 GnmPrintInformation *pi;
1157 xml_sax_must_have_sheet (state);
1159 pi = state->sheet->print_info;
1161 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1162 if (!strcmp (CXML2C (attrs[0]), "value")) {
1163 g_free (pi->repeat_left);
1164 pi->repeat_left = g_strdup (CXML2C (attrs[1]));
1165 break;
1169 static void
1170 xml_sax_print_hf (GsfXMLIn *xin, xmlChar const **attrs)
1172 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1173 GnmPrintInformation *pi;
1174 GnmPrintHF *hf;
1176 xml_sax_must_have_sheet (state);
1178 pi = state->sheet->print_info;
1180 switch (xin->node->user_data.v_int) {
1181 case 0:
1182 hf = pi->footer;
1183 break;
1184 case 1:
1185 hf = pi->header;
1186 break;
1187 default:
1188 return;
1191 g_return_if_fail (hf != NULL);
1193 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1194 if ( attr_eq (attrs[0], "Left")) {
1195 g_free (hf->left_format);
1196 hf->left_format = g_strdup (CXML2C (attrs[1]));
1197 } else if (attr_eq (attrs[0], "Middle")) {
1198 g_free (hf->middle_format);
1199 hf->middle_format = g_strdup (CXML2C (attrs[1]));
1200 } else if (attr_eq (attrs[0], "Right")) {
1201 g_free (hf->right_format);
1202 hf->right_format = g_strdup (CXML2C (attrs[1]));
1203 } else
1204 unknown_attr (xin, attrs);
1209 static void
1210 xml_sax_even_if_only_styles (GsfXMLIn *xin, xmlChar const **attrs)
1212 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1213 GnmPrintInformation *pi;
1214 int val;
1216 xml_sax_must_have_sheet (state);
1218 pi = state->sheet->print_info;
1220 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1221 if (gnm_xml_attr_int (attrs, "value", &val))
1222 pi->print_even_if_only_styles = val;
1228 static void
1229 xml_sax_selection_range (GsfXMLIn *xin, xmlChar const **attrs)
1231 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1232 GnmRange r;
1234 xml_sax_must_have_sheet (state);
1235 if (xml_sax_attr_range (attrs, &r))
1236 sv_selection_add_range (
1237 sheet_get_view (state->sheet, state->wb_view), &r);
1240 static void
1241 xml_sax_selection (GsfXMLIn *xin, xmlChar const **attrs)
1243 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1244 Sheet *sheet = xml_sax_must_have_sheet (state);
1245 int col = -1, row = -1;
1247 sv_selection_reset (sheet_get_view (sheet, state->wb_view));
1249 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1250 if (gnm_xml_attr_int (attrs, "CursorCol", &col)) ;
1251 else if (gnm_xml_attr_int (attrs, "CursorRow", &row)) ;
1252 else
1253 unknown_attr (xin, attrs);
1255 XML_CHECK (state->cell.col < 0);
1256 XML_CHECK (state->cell.row < 0);
1258 /* Default in case of error. */
1259 state->cell.col = 0;
1260 state->cell.row = 0;
1262 XML_CHECK (col >= 0 && col < gnm_sheet_get_max_cols (sheet));
1263 XML_CHECK (row >= 0 && row < gnm_sheet_get_max_rows (sheet));
1265 state->cell.col = col;
1266 state->cell.row = row;
1269 static void
1270 xml_sax_selection_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1272 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1274 GnmCellPos const pos = state->cell;
1275 state->cell.col = state->cell.row = -1;
1276 sv_set_edit_pos (sheet_get_view (state->sheet, state->wb_view), &pos);
1279 static void
1280 xml_sax_sheet_layout (GsfXMLIn *xin, xmlChar const **attrs)
1282 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1283 GnmCellPos tmp;
1285 xml_sax_must_have_sheet (state);
1287 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1288 if (xml_sax_attr_cellpos (attrs, "TopLeft", &tmp, state->sheet))
1289 sv_set_initial_top_left (
1290 sheet_get_view (state->sheet, state->wb_view),
1291 tmp.col, tmp.row);
1292 else
1293 unknown_attr (xin, attrs);
1296 static void
1297 xml_sax_sheet_freezepanes (GsfXMLIn *xin, xmlChar const **attrs)
1299 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1300 GnmCellPos frozen_tl, unfrozen_tl;
1301 int flags = 0;
1303 xml_sax_must_have_sheet (state);
1305 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1306 if (xml_sax_attr_cellpos (attrs, "FrozenTopLeft", &frozen_tl, state->sheet))
1307 flags |= 1;
1308 else if (xml_sax_attr_cellpos (attrs, "UnfrozenTopLeft", &unfrozen_tl, state->sheet))
1309 flags |= 2;
1310 else
1311 unknown_attr (xin, attrs);
1313 if (flags == 3)
1314 sv_freeze_panes (sheet_get_view (state->sheet, state->wb_view),
1315 &frozen_tl, &unfrozen_tl);
1318 static void
1319 xml_sax_cols_rows (GsfXMLIn *xin, xmlChar const **attrs)
1321 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1322 double def_size;
1323 gboolean const is_col = xin->node->user_data.v_bool;
1325 xml_sax_must_have_sheet (state);
1327 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1328 if (gnm_xml_attr_double (attrs, "DefaultSizePts", &def_size)) {
1329 if (is_col)
1330 sheet_col_set_default_size_pts (state->sheet, def_size);
1331 else
1332 sheet_row_set_default_size_pts (state->sheet, def_size);
1336 static void
1337 xml_sax_colrow (GsfXMLIn *xin, xmlChar const **attrs)
1339 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1341 ColRowInfo *cri = NULL;
1342 double size = -1.;
1343 int pos = -1, val;
1344 int hidden = 0, hard_size = 0, is_collapsed = 0, outline_level = 0;
1345 int count = 1;
1346 gboolean const is_col = xin->node->user_data.v_bool;
1347 Sheet *sheet = xml_sax_must_have_sheet (state);
1349 maybe_update_progress (xin);
1351 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1352 if (gnm_xml_attr_int (attrs, "No", &pos)) ;
1353 else if (gnm_xml_attr_double (attrs, "Unit", &size)) ;
1354 else if (gnm_xml_attr_int (attrs, "Count", &count)) ;
1355 else if (gnm_xml_attr_int (attrs, "HardSize", &hard_size)) ;
1356 else if (gnm_xml_attr_int (attrs, "Hidden", &hidden)) ;
1357 else if (gnm_xml_attr_int (attrs, "Collapsed", &is_collapsed)) ;
1358 else if (gnm_xml_attr_int (attrs, "OutlineLevel", &outline_level)) ;
1359 else if (gnm_xml_attr_int (attrs, "MarginA", &val))
1360 ; /* deprecated in 1.7.1 */
1361 else if (gnm_xml_attr_int (attrs, "MarginB", &val))
1362 ; /* deprecated in 1.7.1 */
1363 else
1364 unknown_attr (xin, attrs);
1367 XML_CHECK (size > -1);
1368 XML_CHECK (pos >= 0 && pos < colrow_max (is_col, sheet));
1369 XML_CHECK (count >= 1);
1370 XML_CHECK (count <= colrow_max (is_col, sheet) - pos);
1372 cri = is_col
1373 ? sheet_col_fetch (state->sheet, pos)
1374 : sheet_row_fetch (state->sheet, pos);
1375 cri->hard_size = hard_size;
1376 cri->visible = !hidden;
1377 cri->is_collapsed = is_collapsed;
1378 cri->outline_level = outline_level;
1380 if (is_col) {
1381 sheet_col_set_size_pts (state->sheet, pos, size, cri->hard_size);
1382 if (state->sheet->cols.max_outline_level < cri->outline_level)
1383 state->sheet->cols.max_outline_level = cri->outline_level;
1384 /* resize flags are already set only need to copy the sizes */
1385 while (--count > 0)
1386 colrow_copy (sheet_col_fetch (state->sheet, ++pos), cri);
1387 } else {
1388 sheet_row_set_size_pts (state->sheet, pos, size, cri->hard_size);
1389 if (state->sheet->rows.max_outline_level < cri->outline_level)
1390 state->sheet->rows.max_outline_level = cri->outline_level;
1391 /* resize flags are already set only need to copy the sizes */
1392 while (--count > 0)
1393 colrow_copy (sheet_row_fetch (state->sheet, ++pos), cri);
1397 static void
1398 xml_sax_style_region_start (GsfXMLIn *xin, xmlChar const **attrs)
1400 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1402 g_return_if_fail (state->style_range_init == FALSE);
1403 g_return_if_fail (state->style == NULL);
1405 if (attrs == NULL) {
1406 g_warning ("Invalid tag: gnm:StyleRegion start tag without attributes");
1407 return;
1410 state->style = (state->version >= GNM_XML_V6 ||
1411 state->version <= GNM_XML_V2)
1412 ? gnm_style_new_default ()
1413 : gnm_style_new ();
1415 state->style_range_init =
1416 xml_sax_attr_range (attrs, &state->style_range);
1419 static void
1420 xml_sax_style_region_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1422 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1424 if (!state->style_range_init) {
1425 xml_sax_barf (G_STRFUNC, "style region must have range");
1426 range_init (&state->style_range, 0, 0, 0, 0);
1427 state->style_range_init = TRUE;
1430 xml_sax_must_have_style (state);
1431 xml_sax_must_have_sheet (state);
1433 if (state->clipboard) {
1434 GnmCellRegion *cr = state->clipboard;
1435 GnmStyleRegion *sr = g_new (GnmStyleRegion, 1);
1437 sr->range = state->style_range;
1438 sr->style = state->style;
1440 cr->styles = g_slist_prepend (cr->styles, sr);
1441 } else if (state->version >= GNM_XML_V6 || state->version <= GNM_XML_V2)
1442 sheet_style_set_range (state->sheet, &state->style_range,
1443 state->style);
1444 else
1445 sheet_style_apply_range (state->sheet, &state->style_range,
1446 state->style);
1448 state->style_range_init = FALSE;
1449 state->style = NULL;
1451 maybe_update_progress (xin);
1454 static void
1455 xml_sax_style_start (GsfXMLIn *xin, xmlChar const **attrs)
1457 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1459 int val;
1460 GnmColor *colour;
1462 xml_sax_must_have_style (state);
1464 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1465 if (xml_sax_attr_enum (attrs, "HAlign", GNM_ALIGN_H_TYPE, &val))
1466 gnm_style_set_align_h (state->style, val);
1467 else if (xml_sax_attr_enum (attrs, "VAlign", GNM_ALIGN_V_TYPE, &val))
1468 gnm_style_set_align_v (state->style, val);
1470 /* Pre version V6 */
1471 else if (gnm_xml_attr_int (attrs, "Fit", &val))
1472 gnm_style_set_wrap_text (state->style, val);
1474 else if (gnm_xml_attr_int (attrs, "WrapText", &val))
1475 gnm_style_set_wrap_text (state->style, val);
1476 else if (gnm_xml_attr_bool (attrs, "ShrinkToFit", &val))
1477 gnm_style_set_shrink_to_fit (state->style, val);
1478 else if (gnm_xml_attr_int (attrs, "Rotation", &val)) {
1479 /* Work around a bug pre 1.5.1 that would allow
1480 * negative rotations. -1 == vertical, map everything
1481 * else back onto 0..359 */
1482 if (val < -1)
1483 val += 360;
1484 gnm_style_set_rotation (state->style, val);
1485 } else if (gnm_xml_attr_int (attrs, "Shade", &val))
1486 gnm_style_set_pattern (state->style, val);
1487 else if (gnm_xml_attr_int (attrs, "Indent", &val))
1488 gnm_style_set_indent (state->style, val);
1489 else if (xml_sax_attr_color (attrs, "Fore", &colour))
1490 gnm_style_set_font_color (state->style, colour);
1491 else if (xml_sax_attr_color (attrs, "Back", &colour))
1492 gnm_style_set_back_color (state->style, colour);
1493 else if (xml_sax_attr_color (attrs, "PatternColor", &colour))
1494 gnm_style_set_pattern_color (state->style, colour);
1495 else if (attr_eq (attrs[0], "Format")) {
1496 GOFormat *fmt = make_format (CXML2C (attrs[1]));
1497 if (fmt) {
1498 gnm_style_set_format (state->style, fmt);
1499 go_format_unref (fmt);
1502 else if (gnm_xml_attr_int (attrs, "Hidden", &val))
1503 gnm_style_set_contents_hidden (state->style, val);
1504 else if (gnm_xml_attr_int (attrs, "Locked", &val))
1505 gnm_style_set_contents_locked (state->style, val);
1506 else if (gnm_xml_attr_int (attrs, "Orient", &val))
1507 ; /* ignore old useless attribute */
1508 else
1509 unknown_attr (xin, attrs);
1513 static void
1514 xml_sax_style_font (GsfXMLIn *xin, xmlChar const **attrs)
1516 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1518 double size_pts = 10.;
1519 int val;
1521 xml_sax_must_have_style (state);
1523 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1524 if (gnm_xml_attr_double (attrs, "Unit", &size_pts)) {
1525 if (!(size_pts >= 1.0))
1526 xml_sax_barf (G_STRFUNC, "size_pts >= 1");
1527 else
1528 gnm_style_set_font_size (state->style, size_pts);
1529 } else if (gnm_xml_attr_int (attrs, "Bold", &val))
1530 gnm_style_set_font_bold (state->style, val);
1531 else if (gnm_xml_attr_int (attrs, "Italic", &val))
1532 gnm_style_set_font_italic (state->style, val);
1533 else if (gnm_xml_attr_int (attrs, "Underline", &val))
1534 gnm_style_set_font_uline (state->style, (GnmUnderline)val);
1535 else if (gnm_xml_attr_int (attrs, "StrikeThrough", &val))
1536 gnm_style_set_font_strike (state->style, val);
1537 else if (gnm_xml_attr_int (attrs, "Script", &val)) {
1538 if (val == 0)
1539 gnm_style_set_font_script (state->style, GO_FONT_SCRIPT_STANDARD);
1540 else if (val < 0)
1541 gnm_style_set_font_script (state->style, GO_FONT_SCRIPT_SUB);
1542 else
1543 gnm_style_set_font_script (state->style, GO_FONT_SCRIPT_SUPER);
1544 } else
1545 unknown_attr (xin, attrs);
1549 static char const *
1550 font_component (char const *fontname, int idx)
1552 int i = 0;
1553 char const *p = fontname;
1555 for (; *p && i < idx; p++) {
1556 if (*p == '-')
1557 i++;
1559 if (*p == '-')
1560 p++;
1562 return p;
1566 * style_font_read_from_x11:
1567 * @mstyle: the style to setup to this font.
1568 * @fontname: an X11-like font name.
1570 * Tries to guess the fontname, the weight and italization parameters
1571 * and setup mstyle
1573 * Returns: A valid style font.
1575 static void
1576 style_font_read_from_x11 (GnmStyle *mstyle, char const *fontname)
1578 char const *c;
1580 /* FIXME: we should do something about the typeface instead
1581 * of hardcoding it to helvetica.
1583 c = font_component (fontname, 2);
1584 if (strncmp (c, "bold", 4) == 0)
1585 gnm_style_set_font_bold (mstyle, TRUE);
1587 c = font_component (fontname, 3);
1588 if (strncmp (c, "o", 1) == 0)
1589 gnm_style_set_font_italic (mstyle, TRUE);
1591 if (strncmp (c, "i", 1) == 0)
1592 gnm_style_set_font_italic (mstyle, TRUE);
1595 static void
1596 xml_sax_style_font_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1598 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1600 xml_sax_must_have_style (state);
1602 if (xin->content->len > 0) {
1603 char const * content = xin->content->str;
1604 if (*content == '-')
1605 style_font_read_from_x11 (state->style, content);
1606 else
1607 gnm_style_set_font_name (state->style, content);
1611 static void
1612 xml_sax_validation (GsfXMLIn *xin, xmlChar const **attrs)
1614 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1616 int dummy;
1617 gboolean b_dummy;
1619 g_return_if_fail (state->validation.title == NULL);
1620 g_return_if_fail (state->validation.msg == NULL);
1621 g_return_if_fail (state->validation.texpr[0] == NULL);
1622 g_return_if_fail (state->validation.texpr[1] == NULL);
1624 state->validation.style = GNM_VALIDATION_STYLE_NONE;
1625 state->validation.type = GNM_VALIDATION_TYPE_ANY;
1626 state->validation.op = GNM_VALIDATION_OP_NONE;
1627 state->validation.allow_blank = TRUE;
1628 state->validation.use_dropdown = FALSE;
1630 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1631 if (xml_sax_attr_enum (attrs, "Style",
1632 GNM_VALIDATION_STYLE_TYPE,
1633 &dummy)) {
1634 state->validation.style = dummy;
1635 } else if (xml_sax_attr_enum (attrs, "Type",
1636 GNM_VALIDATION_TYPE_TYPE,
1637 &dummy)) {
1638 state->validation.type = dummy;
1639 } else if (xml_sax_attr_enum (attrs, "Operator",
1640 GNM_VALIDATION_OP_TYPE,
1641 &dummy)) {
1642 state->validation.op = dummy;
1643 } else if (attr_eq (attrs[0], "Title")) {
1644 state->validation.title = g_strdup (CXML2C (attrs[1]));
1645 } else if (attr_eq (attrs[0], "Message")) {
1646 state->validation.msg = g_strdup (CXML2C (attrs[1]));
1647 } else if (gnm_xml_attr_bool (attrs, "AllowBlank", &b_dummy)) {
1648 state->validation.allow_blank = b_dummy;
1649 } else if (gnm_xml_attr_bool (attrs, "UseDropdown", &b_dummy)) {
1650 state->validation.use_dropdown = b_dummy;
1651 } else
1652 unknown_attr (xin, attrs);
1656 static void
1657 xml_sax_validation_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1659 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1661 xml_sax_must_have_style (state);
1663 gnm_style_set_validation (state->style,
1664 gnm_validation_new (state->validation.style,
1665 state->validation.type,
1666 state->validation.op,
1667 state->sheet,
1668 state->validation.title,
1669 state->validation.msg,
1670 state->validation.texpr[0],
1671 state->validation.texpr[1],
1672 state->validation.allow_blank,
1673 state->validation.use_dropdown));
1675 g_free (state->validation.title);
1676 state->validation.title = NULL;
1677 g_free (state->validation.msg);
1678 state->validation.msg = NULL;
1679 state->validation.texpr[0] = state->validation.texpr[1] = NULL;
1682 static void
1683 xml_sax_validation_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1685 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1687 int const i = xin->node->user_data.v_int;
1688 GnmExprTop const *texpr;
1689 GnmParsePos pos;
1691 g_return_if_fail (state->validation.texpr[i] == NULL);
1693 texpr = gnm_expr_parse_str (xin->content->str,
1694 parse_pos_init_sheet (&pos, state->sheet),
1695 GNM_EXPR_PARSE_DEFAULT,
1696 state->convs,
1697 NULL);
1699 g_return_if_fail (texpr != NULL);
1701 state->validation.texpr[i] = texpr;
1704 static void
1705 xml_sax_condition (GsfXMLIn *xin, xmlChar const **attrs)
1707 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1708 GnmStyleCondOp op = GNM_STYLE_COND_CUSTOM;
1710 g_return_if_fail (state->cond == NULL);
1711 g_return_if_fail (state->cond_save_style == NULL);
1713 xml_sax_must_have_style (state);
1715 state->cond_save_style = state->style;
1716 state->style = gnm_style_new ();
1718 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1719 int dummy;
1721 if (gnm_xml_attr_int (attrs, "Operator", &dummy))
1722 op = dummy;
1723 else
1724 unknown_attr (xin, attrs);
1727 state->cond = gnm_style_cond_new (op, state->sheet);
1730 static void
1731 xml_sax_condition_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1733 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1734 GnmStyleConditions *sc;
1736 xml_sax_must_have_style (state);
1737 g_return_if_fail (state->cond_save_style != NULL);
1738 g_return_if_fail (state->cond != NULL);
1740 gnm_style_cond_set_overlay (state->cond, state->style);
1741 gnm_style_unref (state->style);
1742 state->style = state->cond_save_style;
1743 state->cond_save_style = NULL;
1745 if (!gnm_style_is_element_set (state->style, MSTYLE_CONDITIONS) ||
1746 NULL == (sc = gnm_style_get_conditions (state->style)))
1747 gnm_style_set_conditions (state->style,
1748 (sc = gnm_style_conditions_new (state->sheet)));
1749 gnm_style_conditions_insert (sc, state->cond, -1);
1751 gnm_style_cond_free (state->cond);
1752 state->cond = NULL;
1756 * We have been saving expressions relative to A1. This means that when we
1757 * read, we see a relative reference to a cell above as R[65535]C. This
1758 * function patches that to R[-1]C.
1760 * We ought to fix the format, but then old Gnumerics couldn't read new
1761 * files. In fact, if we just added a "Position" attribute then we would
1762 * get silent corruption.
1764 static GnmExpr const *
1765 cond_patchup (GnmExpr const *expr, GnmExprWalk *data)
1767 XMLSaxParseState *state = data->user;
1768 GnmCellPos const *pos = &state->style_range.start;
1769 GnmCellRef const *oref = gnm_expr_get_cellref (expr);
1770 GnmValue const *ocst = gnm_expr_get_constant (expr);
1772 if (oref) {
1773 GnmCellPos tpos;
1774 GnmCellRef tref = *oref;
1775 gnm_cellpos_init_cellref (&tpos, oref, pos, state->sheet);
1776 if (tref.col_relative)
1777 tref.col = tpos.col - pos->col;
1778 if (tref.row_relative)
1779 tref.row = tpos.row - pos->row;
1780 if (gnm_cellref_equal (&tref, oref))
1781 return NULL;
1782 return gnm_expr_new_cellref (&tref);
1785 if (ocst && VALUE_IS_CELLRANGE (ocst)) {
1786 GnmRangeRef const *oref = value_get_rangeref (ocst);
1787 GnmRangeRef tref = *oref;
1788 GnmRange trange;
1789 Sheet *start_sheet, *end_sheet;
1790 GnmEvalPos ep;
1792 eval_pos_init_pos (&ep, state->sheet, pos);
1793 gnm_rangeref_normalize (oref, &ep, &start_sheet, &end_sheet,
1794 &trange);
1795 if (tref.a.col_relative)
1796 tref.a.col = trange.start.col - pos->col;
1797 if (tref.a.row_relative)
1798 tref.a.row = trange.start.row - pos->row;
1799 if (tref.b.col_relative)
1800 tref.b.col = trange.end.col - pos->col;
1801 if (tref.b.row_relative)
1802 tref.b.row = trange.end.row - pos->row;
1803 if (gnm_rangeref_equal (&tref, oref))
1804 return NULL;
1805 return gnm_expr_new_constant (value_new_cellrange_unsafe (&tref.a, &tref.b));
1808 return NULL;
1811 static void
1812 xml_sax_condition_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1814 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1816 int const i = xin->node->user_data.v_int;
1817 GnmExprTop const *texpr;
1818 GnmParsePos pos;
1819 GnmExpr const *patched_expr;
1821 g_return_if_fail (gnm_style_cond_get_expr (state->cond, i) == NULL);
1823 parse_pos_init_sheet (&pos, state->sheet);
1824 texpr = gnm_expr_parse_str (xin->content->str,
1825 &pos,
1826 GNM_EXPR_PARSE_DEFAULT,
1827 state->convs,
1828 NULL);
1829 g_return_if_fail (texpr != NULL);
1831 patched_expr = gnm_expr_walk (texpr->expr, cond_patchup, state);
1832 if (patched_expr) {
1833 gnm_expr_top_unref (texpr);
1834 texpr = gnm_expr_top_new (patched_expr);
1837 gnm_style_cond_set_expr (state->cond, texpr, i);
1838 gnm_expr_top_unref (texpr);
1841 static void
1842 xml_sax_hlink (GsfXMLIn *xin, xmlChar const **attrs)
1844 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1845 char *type = NULL;
1846 char *target = NULL;
1847 char *tip = NULL;
1849 xml_sax_must_have_style (state);
1851 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1852 if (attr_eq (attrs[0], "type"))
1853 type = g_strdup (CXML2C (attrs[1]));
1854 else if (attr_eq (attrs[0], "target"))
1855 target = g_strdup (CXML2C (attrs[1]));
1856 else if (attr_eq (attrs[0], "tip"))
1857 tip = g_strdup (CXML2C (attrs[1]));
1858 else
1859 unknown_attr (xin, attrs);
1862 if (NULL != type && NULL != target) {
1863 GType typ = g_type_from_name (type);
1864 GnmHLink *lnk = gnm_hlink_new (typ, state->sheet);
1865 gnm_hlink_set_target (lnk, target);
1866 gnm_hlink_set_tip (lnk, tip);
1867 gnm_style_set_hlink (state->style, lnk);
1870 g_free (type);
1871 g_free (target);
1872 g_free (tip);
1875 static void
1876 xml_sax_input_msg (GsfXMLIn *xin, xmlChar const **attrs)
1878 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1879 char *title = NULL;
1880 char *msg = NULL;
1882 xml_sax_must_have_style (state);
1884 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1885 if (attr_eq (attrs[0], "Title"))
1886 title = g_strdup (CXML2C (attrs[1]));
1887 else if (attr_eq (attrs[0], "Message"))
1888 msg = g_strdup (CXML2C (attrs[1]));
1889 else
1890 unknown_attr (xin, attrs);
1893 if (NULL != title || NULL != msg)
1894 gnm_style_set_input_msg (state->style,
1895 gnm_input_msg_new (msg, title));
1896 g_free (title);
1897 g_free (msg);
1900 static void
1901 xml_sax_style_border (GsfXMLIn *xin, xmlChar const **attrs)
1903 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1905 int pattern = -1;
1906 GnmColor *colour = NULL;
1908 xml_sax_must_have_style (state);
1910 /* Colour is optional */
1911 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1912 if (xml_sax_attr_color (attrs, "Color", &colour)) ;
1913 else if (gnm_xml_attr_int (attrs, "Style", &pattern)) ;
1914 else
1915 unknown_attr (xin, attrs);
1918 if (pattern >= GNM_STYLE_BORDER_NONE) {
1919 GnmStyleElement const type = xin->node->user_data.v_int;
1920 GnmStyleBorderLocation const loc =
1921 GNM_STYLE_BORDER_TOP + (int)(type - MSTYLE_BORDER_TOP);
1922 GnmBorder *border;
1925 * Make sure we have a colour to prevent trouble further
1926 * down the line.
1928 if (!colour)
1929 colour = gnm_color_new_go (GO_COLOR_BLACK);
1931 border = gnm_style_border_fetch
1932 ((GnmStyleBorderType)pattern, colour,
1933 gnm_style_border_get_orientation (loc));
1934 gnm_style_set_border (state->style, type, border);
1938 static void
1939 xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
1941 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
1942 Sheet *sheet = state->sheet;
1944 int row = -1, col = -1;
1945 int rows = -1, cols = -1;
1946 int value_type = -1;
1947 GOFormat *value_fmt = NULL;
1948 int expr_id = -1;
1950 g_return_if_fail (state->cell.row == -1);
1951 g_return_if_fail (state->cell.col == -1);
1952 g_return_if_fail (state->array_rows == -1);
1953 g_return_if_fail (state->array_cols == -1);
1954 g_return_if_fail (state->expr_id == -1);
1955 g_return_if_fail (state->value_type == -1);
1957 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1958 if (gnm_xml_attr_int (attrs, "Col", &col)) ;
1959 else if (gnm_xml_attr_int (attrs, "Row", &row)) ;
1960 else if (gnm_xml_attr_int (attrs, "Cols", &cols)) ;
1961 else if (gnm_xml_attr_int (attrs, "Rows", &rows)) ;
1962 else if (gnm_xml_attr_int (attrs, "ExprID", &expr_id)) ;
1963 else if (gnm_xml_attr_int (attrs, "ValueType", &value_type)) ;
1964 else if (attr_eq (attrs[0], "ValueFormat"))
1965 value_fmt = make_format (CXML2C (attrs[1]));
1966 else
1967 unknown_attr (xin, attrs);
1970 XML_CHECK2 (col >= 0 && col < gnm_sheet_get_max_cols (sheet),
1971 go_format_unref (value_fmt));
1972 XML_CHECK2 (row >= 0 && row < gnm_sheet_get_max_rows (sheet),
1973 go_format_unref (value_fmt));
1975 if (cols > 0 || rows > 0) {
1976 /* Both must be valid */
1977 XML_CHECK2 (cols > 0 && rows > 0,
1978 go_format_unref (value_fmt));
1980 state->array_cols = cols;
1981 state->array_rows = rows;
1984 state->cell.row = row;
1985 state->cell.col = col;
1986 state->expr_id = expr_id;
1987 state->value_type = value_type;
1988 state->value_fmt = value_fmt;
1992 * xml_cell_set_array_expr : Utility routine to parse an expression
1993 * and store it as an array.
1995 * @cell: The upper left hand corner of the array.
1996 * @text: The text to parse.
1997 * @rows: The number of rows.
1998 * @cols: The number of columns.
2000 static void
2001 xml_cell_set_array_expr (XMLSaxParseState *state,
2002 GnmCell *cell, GnmCellCopy *cc, char const *text,
2003 int const cols, int const rows)
2005 GnmParsePos pp;
2006 GnmExprTop const *texpr =
2007 gnm_expr_parse_str (text,
2008 parse_pos_init_cell (&pp, cell),
2009 GNM_EXPR_PARSE_DEFAULT,
2010 state->convs,
2011 NULL);
2012 GnmRange r;
2014 g_return_if_fail (texpr != NULL);
2016 if (!cell) {
2017 cc->texpr = texpr;
2018 return;
2021 r.start = r.end = cell->pos;
2022 r.end.col += (cols - 1);
2023 r.end.row += (rows - 1);
2025 if (!gnm_cell_set_array (cell->base.sheet, &r, texpr)) {
2026 xml_sax_barf (G_STRFUNC, "target area empty");
2029 gnm_expr_top_unref (texpr);
2033 * xml_not_used_old_array_spec : See if the string corresponds to
2034 * a pre-0.53 style array expression.
2035 * If it is the upper left corner - assign it.
2036 * If it is a member of an array - ignore it; the corner will assign it.
2037 * If it is not a member of an array return TRUE.
2039 static gboolean
2040 xml_not_used_old_array_spec (XMLSaxParseState *state,
2041 GnmCell *cell, GnmCellCopy *cc,
2042 char const *content)
2044 long rows, cols, row, col;
2045 char *end, *expr_end, *ptr;
2047 /* This is the syntax we are trying to parse: "{%s}(%d,%d)[%d][%d]" */
2049 if (content[0] != '=' || content[1] != '{')
2050 return TRUE;
2052 expr_end = strrchr (content, '}');
2053 if (expr_end == NULL || expr_end[1] != '(')
2054 return TRUE;
2056 rows = strtol (ptr = expr_end + 2, &end, 10);
2057 if (end == ptr || *end != ',')
2058 return TRUE;
2059 cols = strtol (ptr = end + 1, &end, 10);
2060 if (end == ptr || end[0] != ')' || end[1] != '[')
2061 return TRUE;
2062 row = strtol (ptr = end + 2, &end, 10);
2063 if (end == ptr || end[0] != ']' || end[1] != '[')
2064 return TRUE;
2065 col = strtol (ptr = end + 2, &end, 10);
2066 if (end == ptr || end[0] != ']' || end[1] != '\0')
2067 return TRUE;
2069 if (row == 0 && col == 0) {
2070 *expr_end = '\0';
2071 xml_cell_set_array_expr (state, cell, cc,
2072 content + 2, rows, cols);
2075 return FALSE;
2078 static void
2079 xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2081 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2082 Sheet *sheet = state->sheet;
2084 gboolean is_new_cell = FALSE, is_post_52_array = FALSE;
2086 GnmParsePos pos;
2087 GnmCell *cell = NULL; /* Regular case */
2088 GnmCellCopy *cc = NULL; /* Clipboard case */
2089 GnmCellRegion *cr = state->clipboard;
2091 int const col = state->cell.col;
2092 int const row = state->cell.row;
2093 int const array_cols = state->array_cols;
2094 int const array_rows = state->array_rows;
2095 int const expr_id = state->expr_id;
2096 int const value_type = state->value_type;
2097 gboolean const seen_contents = state->seen_cell_contents;
2098 GOFormat *value_fmt = state->value_fmt;
2100 /* Clean out the state before any error checking */
2101 state->cell.row = state->cell.col = -1;
2102 state->array_rows = state->array_cols = -1;
2103 state->expr_id = -1;
2104 state->value_type = -1;
2105 state->value_fmt = NULL;
2106 state->seen_cell_contents = strcmp (xin->node->id, "CELL_CONTENT") == 0;
2108 if (seen_contents)
2109 return;
2111 XML_CHECK (col >= 0 && col < gnm_sheet_get_max_cols (sheet));
2112 XML_CHECK (row >= 0 && row < gnm_sheet_get_max_rows (sheet));
2114 maybe_update_progress (xin);
2116 if (cr) {
2117 cc = gnm_cell_copy_new (cr,
2118 col - cr->base.col,
2119 row - cr->base.row);
2120 parse_pos_init (&pos, NULL, sheet, col, row);
2121 } else {
2122 cell = sheet_cell_get (sheet, col, row);
2123 is_new_cell = (cell == NULL);
2124 if (is_new_cell) {
2125 cell = sheet_cell_create (sheet, col, row);
2126 if (cell == NULL)
2127 return;
2129 parse_pos_init_cell (&pos, cell);
2132 is_post_52_array = (array_cols > 0) && (array_rows > 0);
2134 if (xin->content->len > 0) {
2135 char const * content = xin->content->str;
2137 if (is_post_52_array) {
2138 g_return_if_fail (content[0] == '=');
2140 xml_cell_set_array_expr (state, cell, cc, content+1,
2141 array_cols, array_rows);
2142 } else if (state->version >= GNM_XML_V3 ||
2143 xml_not_used_old_array_spec (state, cell, cc, content)) {
2144 if (value_type > 0) {
2145 GnmValue *v = value_new_from_string (value_type, content, value_fmt, FALSE);
2146 if (v == NULL) {
2147 char *msg = g_strdup_printf
2148 ("Parsing \"%s\" as type 0x%x",
2149 content, value_type);
2150 xml_sax_barf (G_STRFUNC, msg);
2151 g_free (msg);
2152 v = value_new_string (content);
2154 if (cell)
2155 gnm_cell_set_value (cell, v);
2156 else
2157 cc->val = v;
2158 } else {
2159 const char *expr_start = gnm_expr_char_start_p (content);
2160 if (expr_start && *expr_start) {
2161 GnmParseError perr;
2162 GnmExprTop const *texpr;
2164 parse_error_init (&perr);
2165 texpr = gnm_expr_parse_str (expr_start,
2166 &pos,
2167 GNM_EXPR_PARSE_DEFAULT,
2168 state->convs,
2169 &perr);
2170 if (!texpr) {
2171 g_warning ("Unparsable expression for %s: %s (%s)\n",
2172 cell ? cell_name (cell) : "-",
2173 content,
2174 perr.err->message);
2175 texpr = gnm_expr_top_new_constant (value_new_string (expr_start));
2177 if (cell) {
2178 gnm_cell_set_expr (cell, texpr);
2179 gnm_expr_top_unref (texpr);
2180 } else if (texpr)
2181 cc->texpr = texpr;
2182 parse_error_free (&perr);
2183 } else if (cell)
2184 gnm_cell_set_text (cell, content);
2185 else
2186 cc->val = value_new_string (content);
2190 if (expr_id > 0) {
2191 gpointer id = GINT_TO_POINTER (expr_id);
2192 GnmExprTop const *texpr =
2193 g_hash_table_lookup (state->expr_map, id);
2194 if (texpr == NULL) {
2195 if (cc)
2196 texpr = cc->texpr;
2197 else if (gnm_cell_has_expr (cell)) {
2198 texpr = cell->base.texpr;
2199 } else
2200 g_warning ("XML-IO : Shared expression with no expression ??");
2201 if (texpr) {
2202 gnm_expr_top_ref (texpr);
2203 g_hash_table_insert (state->expr_map,
2205 (gpointer)texpr);
2207 } else if (!is_post_52_array)
2208 g_warning ("XML-IO : Duplicate shared expression");
2210 } else if (expr_id > 0) {
2211 GnmExprTop const *texpr = g_hash_table_lookup (state->expr_map,
2212 GINT_TO_POINTER (expr_id));
2214 if (!texpr) {
2215 char *msg = g_strdup_printf
2216 ("Looking up shared expression id %d",
2217 expr_id);
2218 char *s = g_strdup_printf ("<shared expression %d>", expr_id);
2219 xml_sax_barf (G_STRFUNC, msg);
2220 g_free (msg);
2222 texpr = gnm_expr_top_new_constant (value_new_string_nocopy (s));
2223 g_hash_table_insert (state->expr_map,
2224 GINT_TO_POINTER (expr_id),
2225 (gpointer)texpr);
2228 if (cell)
2229 gnm_cell_set_expr (cell, texpr);
2230 else {
2231 cc->texpr = texpr;
2232 gnm_expr_top_ref (texpr);
2234 } else if (is_new_cell) {
2235 GnmValue *v;
2238 * Only set to empty if this is a new cell.
2239 * If it was created by a previous array
2240 * we do not want to erase it.
2242 v = value_new_from_string (value_type, "", NULL, FALSE);
2243 if (!v) {
2244 xml_sax_barf (G_STRFUNC, "v != NULL");
2245 v = value_new_empty ();
2248 gnm_cell_set_value (cell, v);
2249 } else if (cr) {
2250 cc->val = value_new_empty ();
2253 go_format_unref (value_fmt);
2256 static void
2257 xml_sax_merge (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2259 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2260 GnmCellRegion *cr = state->clipboard;
2261 Sheet *sheet = state->sheet;
2262 GnmRange r;
2264 g_return_if_fail (xin->content->len > 0);
2266 if (range_parse (&r, xin->content->str, gnm_sheet_get_size (sheet))) {
2267 if (cr) {
2268 cr->merged = g_slist_prepend (cr->merged,
2269 gnm_range_dup (&r));
2270 } else {
2271 gnm_sheet_merge_add (sheet, &r, FALSE,
2272 GO_CMD_CONTEXT (state->context));
2277 static void
2278 xml_sax_filter_operator (XMLSaxParseState *state,
2279 GnmFilterOp *op, xmlChar const *str)
2281 static char const *filter_cond_name[] = { "eq", "gt", "lt", "gte", "lte", "ne" };
2282 int i;
2284 for (i = G_N_ELEMENTS (filter_cond_name); i-- ; )
2285 if (0 == g_ascii_strcasecmp (CXML2C (str), filter_cond_name[i])) {
2286 *op = i;
2287 return;
2290 go_io_warning (state->context, _("Unknown filter operator \"%s\""), str);
2293 static void
2294 xml_sax_filter_condition (GsfXMLIn *xin, xmlChar const **attrs)
2296 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2297 char const *type = NULL;
2298 char const *val0 = NULL;
2299 char const *val1 = NULL;
2300 GnmValueType vtype0 = VALUE_EMPTY, vtype1 = VALUE_EMPTY;
2301 GnmFilterOp op0 = GNM_FILTER_UNUSED, op1 = GNM_FILTER_UNUSED;
2302 GnmFilterCondition *cond = NULL;
2303 gboolean top = TRUE, items = TRUE, is_and = FALSE;
2304 int i, tmp, cond_num = 0;
2305 double bucket_count = 10.;
2307 if (NULL == state->filter) return;
2309 for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2) {
2310 if (attr_eq (attrs[i], "Type")) type = CXML2C (attrs[i + 1]);
2311 else if (gnm_xml_attr_int (attrs+i, "Index", &cond_num)) ;
2312 else if (gnm_xml_attr_bool (attrs, "Top", &top)) ;
2313 else if (gnm_xml_attr_bool (attrs, "Items", &items)) ;
2314 else if (gnm_xml_attr_double (attrs, "Count", &bucket_count)) ;
2315 else if (gnm_xml_attr_bool (attrs, "IsAnd", &is_and)) ;
2316 else if (attr_eq (attrs[i], "Op0")) xml_sax_filter_operator (state, &op0, attrs[i + 1]);
2317 else if (attr_eq (attrs[i], "Op1")) xml_sax_filter_operator (state, &op1, attrs[i + 1]);
2319 * WARNING WARNING WARING
2320 * Value and ValueType are _reversed_ !!!
2321 * An error in the DOM exporter was propogated to the SAX
2322 * exporter and fixing this reversal would break all old files.
2324 else if (attr_eq (attrs[i], "ValueType0")) val0 = CXML2C (attrs[i + 1]);
2325 else if (attr_eq (attrs[i], "ValueType1")) val1 = CXML2C (attrs[i + 1]);
2326 else if (gnm_xml_attr_int (attrs+i, "Value0", &tmp)) vtype0 = tmp;
2327 else if (gnm_xml_attr_int (attrs+i, "Value1", &tmp)) vtype1 = tmp;
2330 if (NULL == type) {
2331 go_io_warning (state->context, _("Missing filter type"));
2332 } else if (0 == g_ascii_strcasecmp (type, "expr")) {
2333 GnmValue *v0 = NULL, *v1 = NULL;
2334 if (val0 && vtype0 != VALUE_EMPTY && op0 != GNM_FILTER_UNUSED)
2335 v0 = value_new_from_string (vtype0, val0, NULL, FALSE);
2336 if (val1 && vtype1 != VALUE_EMPTY && op1 != GNM_FILTER_UNUSED)
2337 v1 = value_new_from_string (vtype1, val1, NULL, FALSE);
2338 if (v0 && v1)
2339 cond = gnm_filter_condition_new_double (
2340 op0, v0, is_and, op1, v1);
2341 else if (v0)
2342 cond = gnm_filter_condition_new_single (op0, v0);
2343 else {
2344 go_io_warning (state->context, _("Malformed sheet filter condition"));
2345 value_release (v0);
2346 value_release (v1);
2348 } else if (0 == g_ascii_strcasecmp (type, "blanks")) {
2349 cond = gnm_filter_condition_new_single (
2350 GNM_FILTER_OP_BLANKS, NULL);
2351 } else if (0 == g_ascii_strcasecmp (type, "noblanks")) {
2352 cond = gnm_filter_condition_new_single (
2353 GNM_FILTER_OP_NON_BLANKS, NULL);
2354 } else if (0 == g_ascii_strcasecmp (type, "bucket")) {
2355 cond = gnm_filter_condition_new_bucket
2356 (top, items, TRUE, bucket_count);
2357 } else {
2358 go_io_warning (state->context, _("Unknown filter type \"%s\""), type);
2360 if (cond != NULL)
2361 gnm_filter_set_condition (state->filter, cond_num, cond, FALSE);
2364 static void
2365 xml_sax_filter_start (GsfXMLIn *xin, xmlChar const **attrs)
2367 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2368 GnmRange r;
2369 int i;
2371 xml_sax_must_have_sheet (state);
2372 g_return_if_fail (state->filter == NULL);
2374 for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2)
2375 if (attr_eq (attrs[i], "Area") &&
2376 range_parse (&r, CXML2C (attrs[i + 1]), gnm_sheet_get_size (state->sheet)))
2377 state->filter = gnm_filter_new (state->sheet, &r);
2378 if (NULL == state->filter)
2379 go_io_warning (state->context, _("Invalid filter, missing Area"));
2382 static void
2383 xml_sax_filter_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2385 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2386 state->filter = NULL;
2389 static void
2390 xml_sax_read_obj (GsfXMLIn *xin, gboolean needs_cleanup,
2391 char const *type_name, xmlChar const **attrs)
2393 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2394 int tmp_int, i;
2395 SheetObject *so;
2396 SheetObjectClass *klass;
2397 GnmRange anchor_r;
2398 GODrawingAnchorDir anchor_dir;
2399 GnmSOAnchorMode anchor_mode;
2400 SheetObjectAnchor anchor;
2401 double f_tmp[4], *anchor_offset = NULL;
2403 g_return_if_fail (state->so == NULL);
2405 /* Old crufty IO */
2406 if (!strcmp (type_name, "Rectangle"))
2407 so = g_object_new (GNM_SO_FILLED_TYPE, NULL);
2408 else if (!strcmp (type_name, "Ellipse"))
2409 so = g_object_new (GNM_SO_FILLED_TYPE, "is-oval", TRUE, NULL);
2410 else if (!strcmp (type_name, "Line"))
2411 so = g_object_new (GNM_SO_LINE_TYPE, NULL);
2412 else if (!strcmp (type_name, "Arrow")) {
2413 GOArrow arrow;
2414 go_arrow_init_kite (&arrow, 8., 10., 3.);
2415 so = g_object_new (GNM_SO_LINE_TYPE,
2416 "end-arrow", &arrow,
2417 NULL);
2420 /* Class renamed between 1.0.x and 1.2.x */
2421 else if (!strcmp (type_name, "GnmGraph"))
2422 so = sheet_object_graph_new (NULL);
2424 /* Class renamed in 1.2.2 */
2425 else if (!strcmp (type_name, "CellComment"))
2426 so = g_object_new (cell_comment_get_type (), NULL);
2428 /* Class renamed in 1.3.91 */
2429 else if (!strcmp (type_name, "SheetObjectGraphic"))
2430 so = g_object_new (GNM_SO_LINE_TYPE, NULL);
2431 else if (!strcmp (type_name, "SheetObjectFilled"))
2432 so = g_object_new (GNM_SO_FILLED_TYPE, NULL);
2433 else if (!strcmp (type_name, "SheetObjectText"))
2434 so = g_object_new (GNM_SO_FILLED_TYPE, NULL);
2435 else if (!strcmp (type_name, "SheetObjectComponent"))
2436 so = sheet_object_component_new (NULL);
2437 else if (!strcmp (type_name, "SheetObjectPath"))
2438 so = g_object_new (GNM_SO_PATH_TYPE, NULL);
2440 else {
2441 GType type = g_type_from_name (type_name);
2443 if (type == 0 || !g_type_is_a (type, GNM_SO_TYPE)) {
2444 char *str = g_strdup_printf (_("Unsupported object type '%s'"),
2445 type_name);
2446 go_io_warning_unsupported_feature (state->context, str);
2447 g_free (str);
2448 return;
2451 so = g_object_new (type, NULL);
2452 if (so == NULL)
2453 return;
2456 g_return_if_fail (so != NULL);
2457 klass = GNM_SO_CLASS (G_OBJECT_GET_CLASS (so));
2458 g_return_if_fail (klass != NULL);
2460 state->so = so;
2462 anchor_dir = GOD_ANCHOR_DIR_UNKNOWN;
2463 anchor_mode = GNM_SO_ANCHOR_TWO_CELLS;
2464 /* Provide a default. */
2465 anchor_r = sheet_object_get_anchor (so)->cell_bound;
2467 for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2) {
2468 if (attr_eq (attrs[i], "Name"))
2469 sheet_object_set_name (so, CXML2C (attrs[i + 1]));
2470 else if (xml_sax_attr_enum (attrs + i, "AnchorMode", GNM_SHEET_OBJECT_ANCHOR_MODE_TYPE, &tmp_int))
2471 anchor_mode = tmp_int;
2472 else if (attr_eq (attrs[i], "ObjectBound"))
2473 range_parse (&anchor_r, CXML2C (attrs[i + 1]), gnm_sheet_get_size (state->sheet));
2474 else if (attr_eq (attrs[i], "ObjectOffset") &&
2475 4 == sscanf (CXML2C (attrs[i + 1]), "%lg %lg %lg %lg",
2476 f_tmp + 0, f_tmp + 1, f_tmp + 2, f_tmp + 3))
2477 anchor_offset = f_tmp;
2478 else if (gnm_xml_attr_int (attrs+i, "Direction", &tmp_int))
2479 anchor_dir = tmp_int;
2480 else if (gnm_xml_attr_int (attrs+i, "Print", &tmp_int)) {
2481 gboolean b = (tmp_int != 0);
2482 sheet_object_set_print_flag (so, &b);
2486 /* Patch problems introduced in some 1.7.x versions that stored
2487 * comments in merged cells with the full rectangle of the merged cell
2488 * rather than just the top left corner */
2489 if (G_OBJECT_TYPE (so) == GNM_CELL_COMMENT_TYPE)
2490 anchor_r.end = anchor_r.start;
2492 sheet_object_anchor_init (&anchor, &anchor_r, anchor_offset, anchor_dir, anchor_mode);
2493 sheet_object_set_anchor (so, &anchor);
2495 if (NULL != klass->prep_sax_parser)
2496 (klass->prep_sax_parser) (so, xin, attrs, state->convs);
2497 if (needs_cleanup) {
2498 /* Put in something to get gnm_xml_finish_obj called */
2499 static GsfXMLInNode const dtd[] = {
2500 GSF_XML_IN_NODE (STYLE, STYLE, -1, "", GSF_XML_NO_CONTENT, NULL, NULL),
2501 GSF_XML_IN_NODE_END
2503 static GsfXMLInDoc *doc = NULL;
2504 if (NULL == doc) {
2505 doc = gsf_xml_in_doc_new (dtd, NULL);
2506 gnm_xml_in_doc_dispose_on_exit (&doc);
2508 /* we need to pas state there because xin->user_state might have
2509 changed, see #751217 */
2510 gsf_xml_in_push_state (xin, doc, state,
2511 (GsfXMLInExtDtor) gnm_xml_finish_obj, attrs);
2515 static void
2516 xml_sax_object_start (GsfXMLIn *xin, xmlChar const **attrs)
2518 char const *type_name = xin->node->name;
2519 maybe_update_progress (xin);
2520 xml_sax_read_obj (xin, FALSE, type_name, attrs);
2523 static void
2524 xml_sax_object_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2526 gnm_xml_finish_obj (xin, xin->user_state);
2528 * WARNING: the object is not completely finished at this
2529 * time. Any handler installed by gog_object_sax_push_parser
2530 * has not yet been called. As a consequence, we cannot
2531 * update the GUI here.
2535 static GnmValue *
2536 parse_constraint_side (const char *s, const GnmParsePos *pp)
2538 GODateConventions const *date_conv =
2539 workbook_date_conv (pp->sheet->workbook);
2540 GnmValue *v = format_match_number (s, NULL, date_conv);
2542 if (!v) {
2543 GnmExprParseFlags flags = GNM_EXPR_PARSE_DEFAULT;
2544 v = value_new_cellrange_parsepos_str (pp, s, flags);
2547 return v;
2550 static void
2551 xml_sax_solver_constr_start (GsfXMLIn *xin, xmlChar const **attrs)
2553 int type = 0;
2554 GnmSolverConstraint *c;
2555 Sheet *sheet = gnm_xml_in_cur_sheet (xin);
2556 GnmSolverParameters *sp = sheet->solver_parameters;
2557 int lhs_col = 0, lhs_row = 0, rhs_col = 0, rhs_row = 0;
2558 int cols = 1, rows = 1;
2559 gboolean old = FALSE;
2560 GnmParsePos pp;
2562 c = gnm_solver_constraint_new (sheet);
2564 parse_pos_init_sheet (&pp, sheet);
2566 for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2567 if (gnm_xml_attr_int (attrs, "Lcol", &lhs_col) ||
2568 gnm_xml_attr_int (attrs, "Lrow", &lhs_row) ||
2569 gnm_xml_attr_int (attrs, "Rcol", &rhs_col) ||
2570 gnm_xml_attr_int (attrs, "Rrow", &rhs_row) ||
2571 gnm_xml_attr_int (attrs, "Cols", &cols) ||
2572 gnm_xml_attr_int (attrs, "Rows", &rows))
2573 old = TRUE;
2574 else if (gnm_xml_attr_int (attrs, "Type", &type))
2575 ; /* Nothing */
2576 else if (attr_eq (attrs[0], "lhs")) {
2577 GnmValue *v = parse_constraint_side (CXML2C (attrs[1]),
2578 &pp);
2579 gnm_solver_constraint_set_lhs (c, v);
2580 } else if (attr_eq (attrs[0], "rhs")) {
2581 GnmValue *v = parse_constraint_side (CXML2C (attrs[1]),
2582 &pp);
2583 gnm_solver_constraint_set_rhs (c, v);
2587 switch (type) {
2588 default:
2589 case 1: c->type = GNM_SOLVER_LE; break;
2590 case 2: c->type = GNM_SOLVER_GE; break;
2591 case 4: c->type = GNM_SOLVER_EQ; break;
2592 case 8: c->type = GNM_SOLVER_INTEGER; break;
2593 case 16: c->type = GNM_SOLVER_BOOLEAN; break;
2596 if (old)
2597 gnm_solver_constraint_set_old (c, c->type,
2598 lhs_col, lhs_row,
2599 rhs_col, rhs_row,
2600 cols, rows);
2602 sp->constraints = g_slist_append (sp->constraints, c);
2605 static void
2606 xml_sax_solver_start (GsfXMLIn *xin, xmlChar const **attrs)
2608 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2609 Sheet *sheet;
2610 GnmSolverParameters *sp;
2611 int col = -1, row = -1;
2612 int ptype, mtype;
2613 GnmParsePos pp;
2614 gboolean old = FALSE;
2616 xml_sax_must_have_sheet (state);
2617 sheet = gnm_xml_in_cur_sheet (xin);
2618 sp = sheet->solver_parameters;
2620 parse_pos_init_sheet (&pp, sheet);
2622 for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2623 if (gnm_xml_attr_int (attrs, "ModelType", &mtype)) {
2624 sp->options.model_type = (GnmSolverModelType)mtype;
2625 } else if (gnm_xml_attr_int (attrs, "ProblemType", &ptype)) {
2626 sp->problem_type = (GnmSolverProblemType)ptype;
2627 } else if (attr_eq (attrs[0], "Inputs")) {
2628 GnmValue *v = value_new_cellrange_parsepos_str
2629 (&pp,
2630 CXML2C (attrs[1]),
2631 GNM_EXPR_PARSE_DEFAULT);
2632 gnm_solver_param_set_input (sp, v);
2633 } else if (gnm_xml_attr_int (attrs, "TargetCol", &col) ||
2634 gnm_xml_attr_int (attrs, "TargetRow", &row)) {
2635 old = TRUE;
2636 } else if (attr_eq (attrs[0], "Target")) {
2637 GnmValue *v = value_new_cellrange_parsepos_str
2638 (&pp,
2639 CXML2C (attrs[1]),
2640 GNM_EXPR_PARSE_DEFAULT);
2641 GnmSheetRange sr;
2642 GnmCellRef cr;
2643 gboolean bad;
2645 bad = (!v ||
2646 (gnm_sheet_range_from_value (&sr, v), !range_is_singleton (&sr.range)));
2647 value_release (v);
2648 if (bad) {
2649 continue;
2652 gnm_cellref_init (&cr, sr.sheet,
2653 sr.range.start.col,
2654 sr.range.start.row,
2655 TRUE);
2656 gnm_solver_param_set_target (sp, &cr);
2657 } else if (gnm_xml_attr_int (attrs, "MaxTime", &(sp->options.max_time_sec)) ||
2658 gnm_xml_attr_int (attrs, "MaxIter", &(sp->options.max_iter)) ||
2659 gnm_xml_attr_bool (attrs, "NonNeg", &(sp->options.assume_non_negative)) ||
2660 gnm_xml_attr_bool (attrs, "Discr", &(sp->options.assume_discrete)) ||
2661 gnm_xml_attr_bool (attrs, "AutoScale", &(sp->options.automatic_scaling)) ||
2662 gnm_xml_attr_bool (attrs, "ProgramR", &(sp->options.program_report)) ||
2663 gnm_xml_attr_bool (attrs, "SensitivityR", &(sp->options.sensitivity_report)))
2664 ; /* Nothing */
2667 if (old &&
2668 col >= 0 && col < gnm_sheet_get_max_cols (sheet) &&
2669 row >= 0 && row < gnm_sheet_get_max_rows (sheet)) {
2670 GnmCellRef cr;
2671 gnm_cellref_init (&cr, NULL, col, row, TRUE);
2672 gnm_solver_param_set_target (sp, &cr);
2676 static void
2677 xml_sax_scenario_start (GsfXMLIn *xin, xmlChar const **attrs)
2679 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2680 const char *name = "scenario";
2681 const char *comment = NULL;
2683 xml_sax_must_have_sheet (state);
2685 for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2686 if (attr_eq (attrs[0], "Name")) {
2687 name = CXML2C (attrs[1]);
2688 } else if (attr_eq (attrs[0], "Comment")) {
2689 comment = CXML2C (attrs[1]);
2693 state->scenario = gnm_sheet_scenario_new (state->sheet, name);
2694 if (comment)
2695 gnm_scenario_set_comment (state->scenario, comment);
2698 static void
2699 xml_sax_scenario_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2701 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2702 GnmScenario *sc = state->scenario;
2703 sc->items = g_slist_reverse (sc->items);
2704 gnm_sheet_scenario_add (state->sheet, sc);
2705 state->scenario = NULL;
2708 static void
2709 xml_sax_scenario_item_start (GsfXMLIn *xin, xmlChar const **attrs)
2711 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2712 const char *rtxt = NULL;
2713 GnmParsePos pp;
2715 for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
2716 if (attr_eq (attrs[0], "Range")) {
2717 rtxt = CXML2C (attrs[1]);
2718 } else if (gnm_xml_attr_int (attrs, "ValueType",
2719 &state->value_type))
2720 ; /* Nothing */
2721 else if (attr_eq (attrs[0], "ValueFormat"))
2722 state->value_fmt = make_format (CXML2C (attrs[1]));
2725 parse_pos_init_sheet (&pp, state->sheet);
2726 state->scenario_range = rtxt
2727 ? value_new_cellrange_parsepos_str (&pp, rtxt, GNM_EXPR_PARSE_DEFAULT)
2728 : NULL;
2731 static void
2732 xml_sax_scenario_item_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2734 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2735 char const * content = xin->content->str;
2736 int const len = xin->content->len;
2737 GnmScenarioItem *sci = NULL;
2738 GnmScenario *sc = state->scenario;
2739 GnmSheetRange sr;
2741 if (!state->scenario_range)
2742 goto bad;
2744 gnm_sheet_range_from_value (&sr, state->scenario_range);
2745 sci = gnm_scenario_item_new (sc->sheet);
2746 gnm_scenario_item_set_range (sci, &sr);
2748 if (len > 0) {
2749 GnmValue *v = value_new_from_string (state->value_type,
2750 content,
2751 state->value_fmt,
2752 FALSE);
2753 if (!v)
2754 goto bad;
2755 gnm_scenario_item_set_value (sci, v);
2756 value_release (v);
2759 sc->items = g_slist_prepend (sc->items, sci);
2760 goto out;
2762 bad:
2763 g_warning ("Ignoring invalid scenario item");
2764 if (sci)
2765 gnm_scenario_item_free (sci);
2767 out:
2768 state->value_type = -1;
2769 go_format_unref (state->value_fmt);
2770 state->value_fmt = NULL;
2771 value_release (state->scenario_range);
2772 state->scenario_range = NULL;
2775 static void
2776 xml_sax_named_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2778 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2779 GnmParsePos pp;
2780 GnmNamedExpr *nexpr;
2782 g_return_if_fail (state->name.name != NULL);
2783 g_return_if_fail (state->name.value != NULL);
2785 /*For the next while we have to ignore Print_areas that look like a whole sheet */
2786 if (0 == strcmp (state->name.name, "Print_Area")
2787 && g_str_has_suffix (state->name.value, "$A$1:$IV$65536")) {
2788 g_free (state->name.value);
2789 state->name.value = NULL;
2790 g_free (state->name.position);
2791 state->name.position = NULL;
2792 } else {
2793 parse_pos_init (&pp, state->wb, state->sheet, 0, 0);
2794 nexpr = expr_name_add (&pp, state->name.name,
2795 gnm_expr_top_new_constant (value_new_empty ()),
2796 NULL,
2797 TRUE,
2798 NULL);
2799 if (nexpr) {
2800 state->delayed_names = g_list_prepend (state->delayed_names, state->sheet);
2801 state->delayed_names = g_list_prepend (state->delayed_names, state->name.value);
2802 state->name.value = NULL;
2803 state->delayed_names = g_list_prepend (state->delayed_names, state->name.position);
2804 state->name.position = NULL;
2805 state->delayed_names = g_list_prepend (state->delayed_names, nexpr);
2806 } else {
2807 g_warning ("Strangeness with defined name: %s",
2808 state->name.name);
2809 g_free (state->name.value);
2810 state->name.value = NULL;
2811 g_free (state->name.position);
2812 state->name.position = NULL;
2816 g_free (state->name.name);
2817 state->name.name = NULL;
2820 static void
2821 xml_sax_named_expr_prop (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2823 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2825 char const * content = xin->content->str;
2826 int const len = xin->content->len;
2828 switch (xin->node->user_data.v_int) {
2829 case 0:
2830 g_return_if_fail (state->name.name == NULL);
2831 state->name.name = g_strndup (content, len);
2832 break;
2833 case 1:
2834 g_return_if_fail (state->name.value == NULL);
2835 state->name.value = g_strndup (content, len);
2836 break;
2837 case 2:
2838 g_return_if_fail (state->name.position == NULL);
2839 state->name.position = g_strndup (content, len);
2840 break;
2841 default:
2842 return;
2846 static void
2847 xml_sax_print_order (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2849 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2851 xml_sax_must_have_sheet (state);
2853 state->sheet->print_info->print_across_then_down =
2854 (strcmp (xin->content->str, "r_then_d") == 0);
2857 static void
2858 xml_sax_print_comments_start (GsfXMLIn *xin, xmlChar const **attrs)
2860 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2861 gint tmpi;
2863 xml_sax_must_have_sheet (state);
2865 /* In 1.11.x and later this is saved as an enum value */
2866 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2867 if (xml_sax_attr_enum (attrs, "placement", GNM_PRINT_COMMENT_PLACEMENT_TYPE, &tmpi))
2868 state->sheet->print_info->comment_placement = tmpi;
2871 static void
2872 xml_sax_print_comments_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2874 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2876 if (xin->content->str == NULL || *xin->content->str == 0)
2877 /* 1.11.x or later file */
2878 return;
2880 xml_sax_must_have_sheet (state);
2882 if (strcmp (xin->content->str, "in_place") == 0)
2883 state->sheet->print_info->comment_placement =
2884 GNM_PRINT_COMMENTS_IN_PLACE;
2885 else if (strcmp (xin->content->str, "at_end") == 0)
2886 state->sheet->print_info->comment_placement =
2887 GNM_PRINT_COMMENTS_AT_END;
2888 else
2889 state->sheet->print_info->comment_placement =
2890 GNM_PRINT_COMMENTS_NONE;
2893 static void
2894 xml_sax_print_errors_start (GsfXMLIn *xin, xmlChar const **attrs)
2896 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2897 gint tmpi;
2899 xml_sax_must_have_sheet (state);
2901 /* In 1.11.x and later this is saved as an enum value */
2902 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2903 if (xml_sax_attr_enum (attrs, "PrintErrorsAs", GNM_PRINT_ERRORS_TYPE, &tmpi))
2904 state->sheet->print_info->error_display = tmpi;
2908 static void
2909 xml_sax_print_errors_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2911 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2913 if (xin->content->str == NULL || *xin->content->str == 0)
2914 /* 1.11.x or later file */
2915 return;
2917 xml_sax_must_have_sheet (state);
2919 if (strcmp (xin->content->str, "as_blank") == 0)
2920 state->sheet->print_info->error_display =
2921 GNM_PRINT_ERRORS_AS_BLANK;
2922 else if (strcmp (xin->content->str, "as_dashes") == 0)
2923 state->sheet->print_info->error_display =
2924 GNM_PRINT_ERRORS_AS_DASHES;
2925 else if (strcmp (xin->content->str, "as_na") == 0)
2926 state->sheet->print_info->error_display =
2927 GNM_PRINT_ERRORS_AS_NA;
2928 else
2929 state->sheet->print_info->error_display =
2930 GNM_PRINT_ERRORS_AS_DISPLAYED;
2934 static void
2935 xml_sax_orientation (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2937 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2938 GnmPrintInformation *pi;
2939 GtkPageOrientation orient = GTK_PAGE_ORIENTATION_PORTRAIT;
2941 xml_sax_must_have_sheet (state);
2943 pi = state->sheet->print_info;
2945 #warning TODO: we should also handle inversion
2946 if (strcmp (xin->content->str, "portrait") == 0)
2947 orient = GTK_PAGE_ORIENTATION_PORTRAIT;
2948 else if (strcmp (xin->content->str, "landscape") == 0)
2949 orient = GTK_PAGE_ORIENTATION_LANDSCAPE;
2951 print_info_set_paper_orientation (pi, orient);
2954 static void
2955 xml_sax_paper (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2957 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2959 xml_sax_must_have_sheet (state);
2961 print_info_set_paper (state->sheet->print_info, xin->content->str);
2964 static void
2965 xml_sax_print_to_uri (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2967 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
2969 xml_sax_must_have_sheet (state);
2971 print_info_set_printtofile_uri (state->sheet->print_info,
2972 xin->content->str);
2975 static void
2976 handle_delayed_names (XMLSaxParseState *state)
2978 GList *l;
2980 for (l = state->delayed_names; l; l = l->next->next->next->next) {
2981 GnmNamedExpr *nexpr = l->data;
2982 char *pos_str = l->next->data;
2983 char *expr_str = l->next->next->data;
2984 Sheet *sheet = l->next->next->next->data;
2985 GnmParseError perr;
2986 GnmExprTop const *texpr;
2987 GnmParsePos pp;
2989 parse_pos_init (&pp, state->wb, sheet, 0, 0);
2990 if (pos_str) {
2991 GnmCellRef tmp;
2992 char const *rest;
2993 GnmSheetSize const *ss =
2994 gnm_sheet_get_size2 (sheet, state->wb);
2995 rest = cellref_parse (&tmp, ss, pos_str, &pp.eval);
2996 if (rest != NULL && *rest == '\0') {
2997 pp.eval.col = tmp.col;
2998 pp.eval.row = tmp.row;
3002 parse_error_init (&perr);
3003 texpr = gnm_expr_parse_str (expr_str, &pp,
3004 GNM_EXPR_PARSE_DEFAULT,
3005 state->convs,
3006 &perr);
3007 if (!texpr) {
3008 go_io_warning (state->context, "%s", perr.err->message);
3009 } else if (expr_name_check_for_loop (expr_name_name (nexpr), texpr)) {
3010 g_printerr ("Ignoring would-be circular definition of %s\n",
3011 expr_name_name (nexpr));
3012 gnm_expr_top_unref (texpr);
3013 } else {
3014 nexpr->pos.eval = pp.eval;
3015 expr_name_set_expr (nexpr, texpr);
3018 parse_error_free (&perr);
3019 g_free (expr_str);
3020 g_free (pos_str);
3023 g_list_free (state->delayed_names);
3024 state->delayed_names = NULL;
3027 static void
3028 xml_sax_go_doc (GsfXMLIn *xin, xmlChar const **attrs)
3030 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3031 go_doc_read (GO_DOC (state->wb), xin, attrs);
3034 /****************************************************************************/
3036 static GsfXMLInNS const content_ns[] = {
3037 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v14.dtd"), /* future */
3038 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v13.dtd"),
3039 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v12.dtd"),
3040 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v11.dtd"),
3041 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v10.dtd"),
3042 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v9.dtd"),
3043 GSF_XML_IN_NS (GNM, "http://www.gnumeric.org/v8.dtd"),
3044 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v7"),
3045 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v6"),
3046 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v5"),
3047 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v4"),
3048 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v3"),
3049 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/v2"),
3050 GSF_XML_IN_NS (GNM, "http://www.gnome.org/gnumeric/"),
3051 /* The next items are from libgsf, there is no obvious way of adding them automatically */
3052 GSF_XML_IN_NS (OO_NS_XSI, "http://www.w3.org/2001/XMLSchema-instance"),
3053 GSF_XML_IN_NS (OO_NS_OFFICE, "urn:oasis:names:tc:opendocument:xmlns:office:1.0"),
3054 GSF_XML_IN_NS (OO_NS_OOO, "http://openoffice.org/2004/office"),
3055 GSF_XML_IN_NS (OO_NS_DC, "http://purl.org/dc/elements/1.1/"),
3056 GSF_XML_IN_NS (OO_NS_XLINK, "http://www.w3.org/1999/xlink"),
3057 GSF_XML_IN_NS (OO_NS_META, "urn:oasis:names:tc:opendocument:xmlns:meta:1.0"),
3058 GSF_XML_IN_NS_END
3061 static GsfXMLInNode gnumeric_1_0_dtd[] = {
3062 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3063 GSF_XML_IN_NODE_FULL (START, WB, GNM, "Workbook", GSF_XML_NO_CONTENT, TRUE, TRUE, &xml_sax_wb, NULL, 0),
3064 GSF_XML_IN_NODE (WB, WB_VERSION, GNM, "Version", GSF_XML_NO_CONTENT, &xml_sax_version, NULL),
3065 GSF_XML_IN_NODE (WB, WB_ATTRIBUTES, GNM, "Attributes", GSF_XML_NO_CONTENT, NULL, NULL),
3066 GSF_XML_IN_NODE (WB_ATTRIBUTES, WB_ATTRIBUTE, GNM, "Attribute", GSF_XML_NO_CONTENT, NULL, &xml_sax_finish_parse_wb_attr),
3067 GSF_XML_IN_NODE_FULL (WB_ATTRIBUTE, WB_ATTRIBUTE_NAME, GNM, "name", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_attr_elem, 0),
3068 GSF_XML_IN_NODE_FULL (WB_ATTRIBUTE, WB_ATTRIBUTE_VALUE, GNM, "value", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_attr_elem, 1),
3069 GSF_XML_IN_NODE (WB_ATTRIBUTE, WB_ATTRIBUTE_TYPE, GNM, "type", GSF_XML_NO_CONTENT, NULL, NULL),
3071 /* The old 'SummaryItem' Metadata. Removed in 1.7.x */
3072 GSF_XML_IN_NODE (WB, WB_SUMMARY, GNM, "Summary", GSF_XML_NO_CONTENT, NULL, NULL),
3073 GSF_XML_IN_NODE (WB_SUMMARY, WB_SUMMARY_ITEM, GNM, "Item", GSF_XML_NO_CONTENT, NULL, NULL),
3074 GSF_XML_IN_NODE (WB_SUMMARY_ITEM, WB_SUMMARY_ITEM_NAME, GNM, "name", GSF_XML_CONTENT, NULL, NULL),
3075 GSF_XML_IN_NODE (WB_SUMMARY_ITEM, WB_SUMMARY_ITEM_VALUE_STR, GNM, "val-string", GSF_XML_CONTENT, NULL, NULL),
3076 GSF_XML_IN_NODE (WB_SUMMARY_ITEM, WB_SUMMARY_ITEM_VALUE_INT, GNM, "val-int", GSF_XML_CONTENT, NULL, NULL),
3078 GSF_XML_IN_NODE (WB, WB_SHEETNAME_INDEX, GNM, "SheetNameIndex", GSF_XML_NO_CONTENT, NULL, NULL),
3079 GSF_XML_IN_NODE (WB_SHEETNAME_INDEX, WB_SHEETNAME, GNM, "SheetName", GSF_XML_CONTENT, &xml_sax_wb_sheetsize, &xml_sax_wb_sheetname),
3081 GSF_XML_IN_NODE (WB, WB_NAMED_EXPRS, GNM, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
3082 GSF_XML_IN_NODE (WB_NAMED_EXPRS, WB_NAMED_EXPR, GNM, "Name", GSF_XML_NO_CONTENT, NULL, &xml_sax_named_expr_end),
3083 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),
3084 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),
3085 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),
3086 /* sometimes not namespaced */
3087 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),
3088 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),
3089 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),
3091 GSF_XML_IN_NODE (WB, WB_SHEETS, GNM, "Sheets", GSF_XML_NO_CONTENT, NULL, NULL),
3092 GSF_XML_IN_NODE (WB_SHEETS, SHEET, GNM, "Sheet", GSF_XML_NO_CONTENT, &xml_sax_sheet_start, &xml_sax_sheet_end),
3093 GSF_XML_IN_NODE (SHEET, SHEET_NAME, GNM, "Name", GSF_XML_CONTENT, NULL, &xml_sax_sheet_name),
3094 GSF_XML_IN_NODE (SHEET, SHEET_MAXCOL, GNM, "MaxCol", GSF_XML_NO_CONTENT, NULL, NULL),
3095 GSF_XML_IN_NODE (SHEET, SHEET_MAXROW, GNM, "MaxRow", GSF_XML_NO_CONTENT, NULL, NULL),
3096 GSF_XML_IN_NODE (SHEET, SHEET_ZOOM, GNM, "Zoom", GSF_XML_CONTENT, NULL, &xml_sax_sheet_zoom),
3097 GSF_XML_IN_NODE (SHEET, SHEET_NAMED_EXPRS, GNM, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
3098 GSF_XML_IN_NODE (SHEET_NAMED_EXPRS, SHEET_NAMED_EXPR, GNM, "Name", GSF_XML_NO_CONTENT, NULL, &xml_sax_named_expr_end),
3099 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),
3100 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),
3101 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),
3103 GSF_XML_IN_NODE (SHEET, SHEET_PRINTINFO, GNM, "PrintInformation", GSF_XML_NO_CONTENT, NULL, NULL),
3104 GSF_XML_IN_NODE (SHEET_PRINTINFO, SHEET_PRINTUNIT, GNM, "PrintUnit", GSF_XML_NO_CONTENT, NULL, NULL), /* ignore ancient field */
3105 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_MARGINS, GNM, "Margins", GSF_XML_NO_CONTENT, NULL, NULL),
3106 GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_TOP, GNM, "top", GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 0),
3107 GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_BOTTOM, GNM, "bottom",GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 1),
3108 GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_LEFT, GNM, "left", GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 2),
3109 GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_RIGHT, GNM, "right", GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 3),
3110 GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_HEADER, GNM, "header",GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 4),
3111 GSF_XML_IN_NODE_FULL (PRINT_MARGINS, PRINT_MARGIN_FOOTER, GNM, "footer",GSF_XML_CONTENT, FALSE, FALSE, &xml_sax_print_margins, NULL, 5),
3112 GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, V_PAGE_BREAKS, GNM, "vPageBreaks", GSF_XML_NO_CONTENT,
3113 FALSE, FALSE, &xml_sax_page_breaks_begin, &xml_sax_page_breaks_end, 1),
3114 GSF_XML_IN_NODE (V_PAGE_BREAKS, PAGE_BREAK, GNM, "break", GSF_XML_NO_CONTENT, &xml_sax_page_break, NULL),
3115 GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, H_PAGE_BREAKS, GNM, "hPageBreaks", GSF_XML_NO_CONTENT,
3116 FALSE, FALSE, &xml_sax_page_breaks_begin, &xml_sax_page_breaks_end, 0),
3117 GSF_XML_IN_NODE (H_PAGE_BREAKS, PAGE_BREAK, GNM, "break", GSF_XML_2ND, NULL, NULL),
3119 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_SCALE, GNM, "Scale", GSF_XML_CONTENT, &xml_sax_print_scale, NULL),
3120 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_VCENTER, GNM, "vcenter", GSF_XML_CONTENT, &xml_sax_print_vcenter, NULL),
3121 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_HCENTER, GNM, "hcenter", GSF_XML_CONTENT, &xml_sax_print_hcenter, NULL),
3122 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_GRID, GNM, "grid", GSF_XML_NO_CONTENT, &xml_sax_print_grid, NULL),
3123 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),
3124 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_PRINT_RANGE, GNM, "print_range",GSF_XML_NO_CONTENT, &xml_sax_print_print_range, NULL),
3125 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_MONO, GNM, "monochrome", GSF_XML_NO_CONTENT, &xml_sax_monochrome, NULL),
3126 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_AS_DRAFT, GNM, "draft", GSF_XML_NO_CONTENT, NULL, NULL),
3127 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_COMMENTS, GNM, "comments", GSF_XML_CONTENT, &xml_sax_print_comments_start, &xml_sax_print_comments_end),
3128 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ERRORS, GNM, "errors", GSF_XML_CONTENT, &xml_sax_print_errors_start, &xml_sax_print_errors_end),
3129 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_TITLES, GNM, "titles", GSF_XML_NO_CONTENT, &xml_sax_print_titles, NULL),
3130 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_REPEAT_TOP, GNM, "repeat_top", GSF_XML_NO_CONTENT, &xml_sax_repeat_top, NULL),
3131 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_REPEAT_LEFT,GNM, "repeat_left", GSF_XML_NO_CONTENT, &xml_sax_repeat_left, NULL),
3132 GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, PRINT_FOOTER, GNM, "Footer", GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_print_hf, NULL, 0),
3133 GSF_XML_IN_NODE_FULL (SHEET_PRINTINFO, PRINT_HEADER, GNM, "Header", GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_print_hf, NULL, 1),
3134 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ORDER, GNM, "order", GSF_XML_CONTENT, NULL, &xml_sax_print_order),
3135 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_PAPER, GNM, "paper", GSF_XML_CONTENT, NULL, &xml_sax_paper),
3136 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_TO_URI, GNM, "print-to-uri",GSF_XML_CONTENT, NULL, &xml_sax_print_to_uri),
3137 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ORIENT, GNM, "orientation", GSF_XML_CONTENT, NULL, &xml_sax_orientation),
3138 GSF_XML_IN_NODE (SHEET_PRINTINFO, PRINT_ONLY_STYLE, GNM, "even_if_only_styles", GSF_XML_CONTENT, &xml_sax_even_if_only_styles, NULL),
3140 GSF_XML_IN_NODE (SHEET, SHEET_STYLES, GNM, "Styles", GSF_XML_NO_CONTENT, NULL, NULL),
3141 GSF_XML_IN_NODE (SHEET_STYLES, STYLE_REGION, GNM, "StyleRegion", GSF_XML_NO_CONTENT, &xml_sax_style_region_start, &xml_sax_style_region_end),
3142 GSF_XML_IN_NODE (STYLE_REGION, STYLE_STYLE, GNM, "Style", GSF_XML_NO_CONTENT, &xml_sax_style_start, NULL),
3143 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_FONT, GNM, "Font", GSF_XML_CONTENT, &xml_sax_style_font, &xml_sax_style_font_end),
3144 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_BORDER, GNM, "StyleBorder", GSF_XML_NO_CONTENT, NULL, NULL),
3145 GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_TOP, GNM, "Top",
3146 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_TOP),
3147 GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_BOTTOM, GNM, "Bottom",
3148 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_BOTTOM),
3149 GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_LEFT, GNM, "Left",
3150 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_LEFT),
3151 GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_RIGHT, GNM, "Right",
3152 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_RIGHT),
3153 GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_DIAG, GNM, "Diagonal",
3154 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_DIAGONAL),
3155 GSF_XML_IN_NODE_FULL (STYLE_BORDER, BORDER_REV_DIAG,GNM, "Rev-Diagonal",
3156 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_style_border, NULL, MSTYLE_BORDER_REV_DIAGONAL),
3158 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_VALIDATION, GNM, "Validation", GSF_XML_NO_CONTENT, &xml_sax_validation, &xml_sax_validation_end),
3159 GSF_XML_IN_NODE_FULL (STYLE_VALIDATION, STYLE_VALIDATION_EXPR0, GNM, "Expression0",
3160 GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_validation_expr_end, 0),
3161 GSF_XML_IN_NODE_FULL (STYLE_VALIDATION, STYLE_VALIDATION_EXPR1, GNM, "Expression1",
3162 GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_validation_expr_end, 1),
3163 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_HYPERLINK, GNM, "HyperLink", GSF_XML_NO_CONTENT, &xml_sax_hlink, NULL),
3164 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_INPUT_MSG, GNM, "InputMessage", GSF_XML_NO_CONTENT, &xml_sax_input_msg, NULL),
3165 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_CONDITION, GNM, "Condition", GSF_XML_NO_CONTENT, &xml_sax_condition, &xml_sax_condition_end),
3166 GSF_XML_IN_NODE_FULL (STYLE_CONDITION, STYLE_CONDITION_EXPR0, GNM, "Expression0",
3167 GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_condition_expr_end, 0),
3168 GSF_XML_IN_NODE_FULL (STYLE_CONDITION, STYLE_CONDITION_EXPR1, GNM, "Expression1",
3169 GSF_XML_CONTENT, FALSE, FALSE, NULL, &xml_sax_condition_expr_end, 1),
3170 GSF_XML_IN_NODE (STYLE_CONDITION, STYLE_STYLE, GNM, "Style", GSF_XML_NO_CONTENT, NULL, NULL),
3172 GSF_XML_IN_NODE_FULL (SHEET, SHEET_COLS, GNM, "Cols",
3173 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_cols_rows, NULL, TRUE),
3174 GSF_XML_IN_NODE_FULL (SHEET_COLS, COL, GNM, "ColInfo",
3175 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_colrow, NULL, TRUE),
3177 GSF_XML_IN_NODE_FULL (SHEET, SHEET_ROWS, GNM, "Rows",
3178 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_cols_rows, NULL, FALSE),
3179 GSF_XML_IN_NODE_FULL (SHEET_ROWS, ROW, GNM, "RowInfo",
3180 GSF_XML_NO_CONTENT, FALSE, FALSE, &xml_sax_colrow, NULL, FALSE),
3182 GSF_XML_IN_NODE (SHEET, SHEET_SELECTIONS, GNM, "Selections", GSF_XML_NO_CONTENT, &xml_sax_selection, &xml_sax_selection_end),
3183 GSF_XML_IN_NODE (SHEET_SELECTIONS, SELECTION, GNM, "Selection", GSF_XML_NO_CONTENT, &xml_sax_selection_range, NULL),
3185 GSF_XML_IN_NODE (SHEET, SHEET_CELLS, GNM, "Cells", GSF_XML_NO_CONTENT, NULL, NULL),
3186 GSF_XML_IN_NODE (SHEET_CELLS, CELL, GNM, "Cell", GSF_XML_CONTENT, &xml_sax_cell, &xml_sax_cell_content),
3187 GSF_XML_IN_NODE (CELL, CELL_CONTENT, GNM, "Content", GSF_XML_CONTENT, NULL, &xml_sax_cell_content),
3189 GSF_XML_IN_NODE (SHEET, SHEET_MERGED_REGIONS, GNM, "MergedRegions", GSF_XML_NO_CONTENT, NULL, NULL),
3190 GSF_XML_IN_NODE (SHEET_MERGED_REGIONS, MERGED_REGION, GNM, "Merge", GSF_XML_CONTENT, NULL, &xml_sax_merge),
3192 GSF_XML_IN_NODE (SHEET, SHEET_FILTERS, GNM, "Filters", GSF_XML_NO_CONTENT, NULL, NULL),
3193 GSF_XML_IN_NODE (SHEET_FILTERS, FILTER, GNM, "Filter", GSF_XML_NO_CONTENT, &xml_sax_filter_start, &xml_sax_filter_end),
3194 GSF_XML_IN_NODE (FILTER, FILTER_FIELD, GNM, "Field", GSF_XML_NO_CONTENT, &xml_sax_filter_condition, NULL),
3196 GSF_XML_IN_NODE (SHEET, SHEET_LAYOUT, GNM, "SheetLayout", GSF_XML_NO_CONTENT, &xml_sax_sheet_layout, NULL),
3197 GSF_XML_IN_NODE (SHEET_LAYOUT, SHEET_FREEZEPANES, GNM, "FreezePanes", GSF_XML_NO_CONTENT, &xml_sax_sheet_freezepanes, NULL),
3199 GSF_XML_IN_NODE (SHEET, SHEET_SOLVER, GNM, "Solver", GSF_XML_NO_CONTENT, xml_sax_solver_start, NULL),
3200 GSF_XML_IN_NODE (SHEET_SOLVER, SOLVER_CONSTR, GNM, "Constr", GSF_XML_NO_CONTENT, xml_sax_solver_constr_start, NULL),
3201 GSF_XML_IN_NODE (SHEET, SHEET_SCENARIOS, GNM, "Scenarios", GSF_XML_NO_CONTENT, NULL, NULL),
3202 GSF_XML_IN_NODE (SHEET_SCENARIOS, SHEET_SCENARIO, GNM, "Scenario", GSF_XML_NO_CONTENT, xml_sax_scenario_start, xml_sax_scenario_end),
3203 GSF_XML_IN_NODE (SHEET_SCENARIO, SCENARIO_ITEM, GNM, "Item", GSF_XML_CONTENT, xml_sax_scenario_item_start, xml_sax_scenario_item_end),
3205 GSF_XML_IN_NODE (SHEET, SHEET_OBJECTS, GNM, "Objects", GSF_XML_NO_CONTENT, NULL, NULL),
3206 /* Old crufty IO */
3207 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_RECT, GNM, "Rectangle", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3208 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_ELLIPSE, GNM, "Ellipse", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3209 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_ARROW, GNM, "Arrow", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3210 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_ANCIENT_LINE, GNM, "Line", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3211 /* Class renamed between 1.0.x and 1.2.x */
3212 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_GRAPH, GNM, "GnmGraph", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3213 /* Class renamed in 1.2.2 */
3214 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_COMMENT, GNM, "CellComment", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3215 /* Class renamed in 1.3.91 */
3216 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_LINE, GNM, "SheetObjectGraphic", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3217 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_FILLED, GNM, "SheetObjectFilled", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3218 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_OLD_TEXT, GNM, "SheetObjectText", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3219 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_GRAPH, GNM, "SheetObjectGraph", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3220 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_IMAGE, GNM, "SheetObjectImage", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3221 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_COMPONENT, GNM, "SheetObjectComponent", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3222 GSF_XML_IN_NODE (SHEET_OBJECTS, OBJECT_PATH, GNM, "SheetObjectPath", GSF_XML_NO_CONTENT, &xml_sax_object_start, &xml_sax_object_end),
3224 GSF_XML_IN_NODE (WB, WB_GEOMETRY, GNM, "Geometry", GSF_XML_NO_CONTENT, &xml_sax_wb_view, NULL),
3225 GSF_XML_IN_NODE (WB, WB_VIEW, GNM, "UIData", GSF_XML_NO_CONTENT, &xml_sax_wb_view, NULL),
3226 GSF_XML_IN_NODE (WB, WB_CALC, GNM, "Calculation", GSF_XML_NO_CONTENT, &xml_sax_calculation, NULL),
3227 GSF_XML_IN_NODE (WB, WB_DATE, GNM, "DateConvention", GSF_XML_CONTENT, NULL, &xml_sax_old_dateconvention),
3228 GSF_XML_IN_NODE (WB, GODOC, -1, "GODoc", GSF_XML_NO_CONTENT, &xml_sax_go_doc, NULL),
3229 GSF_XML_IN_NODE (WB, DOCUMENTMETA, OO_NS_OFFICE, "document-meta", GSF_XML_NO_CONTENT, &xml_sax_document_meta, NULL),
3230 GSF_XML_IN_NODE_END
3233 static void
3234 xml_sax_clipboardrange_start (GsfXMLIn *xin, xmlChar const **attrs)
3236 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3237 int cols = -1, rows = -1, base_col = -1, base_row = -1;
3238 GnmCellRegion *cr;
3240 cr = state->clipboard = gnm_cell_region_new (state->sheet);
3242 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3243 if (gnm_xml_attr_int (attrs, "Cols", &cols) ||
3244 gnm_xml_attr_int (attrs, "Rows", &rows) ||
3245 gnm_xml_attr_int (attrs, "BaseCol", &base_col) ||
3246 gnm_xml_attr_int (attrs, "BaseRow", &base_row) ||
3247 gnm_xml_attr_bool (attrs, "NotAsContent", &cr->not_as_contents))
3248 ; /* Nothing */
3249 else if (attr_eq (attrs[0], "DateConvention")) {
3250 GODateConventions const *date_conv =
3251 go_date_conv_from_str (CXML2C (attrs[1]));
3252 if (date_conv)
3253 cr->date_conv = date_conv;
3254 else
3255 g_printerr ("Ignoring invalid date conventions.\n");
3259 if (cols <= 0 || rows <= 0 || base_col < 0 || base_row < 0) {
3260 g_printerr ("Invalid clipboard contents.\n");
3261 } else {
3262 cr->cols = cols;
3263 cr->rows = rows;
3264 cr->base.col = base_col;
3265 cr->base.row = base_row;
3269 static GsfXMLInNode clipboard_dtd[] = {
3270 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3271 GSF_XML_IN_NODE_FULL (START, CLIPBOARDRANGE, GNM, "ClipboardRange", GSF_XML_NO_CONTENT, TRUE, TRUE, xml_sax_clipboardrange_start, NULL, 0),
3272 /* We insert "Styles" (etc) */
3273 GSF_XML_IN_NODE_END
3276 static void
3277 gnm_xml_in_doc_add_subset (GsfXMLInDoc *doc, GsfXMLInNode *dtd,
3278 const char *id, const char *new_parent)
3280 GHashTable *parents = g_hash_table_new (g_str_hash, g_str_equal);
3281 GsfXMLInNode end_node = GSF_XML_IN_NODE_END;
3282 GArray *new_dtd = g_array_new (FALSE, FALSE, sizeof (GsfXMLInNode));
3284 for (; dtd->id; dtd++) {
3285 GsfXMLInNode node = *dtd;
3287 if (g_str_equal (id, dtd->id)) {
3288 g_hash_table_insert (parents,
3289 (gpointer)id,
3290 (gpointer)id);
3291 if (new_parent)
3292 node.parent_id = new_parent;
3293 } else if (g_hash_table_lookup (parents, dtd->parent_id))
3294 g_hash_table_insert (parents,
3295 (gpointer)dtd->id,
3296 (gpointer)dtd->id);
3297 else
3298 continue;
3300 g_array_append_val (new_dtd, node);
3303 g_array_append_val (new_dtd, end_node);
3305 gsf_xml_in_doc_add_nodes (doc, (GsfXMLInNode*)(new_dtd->data));
3307 g_array_free (new_dtd, TRUE);
3308 g_hash_table_destroy (parents);
3312 static gboolean
3313 xml_sax_unknown (GsfXMLIn *xin, xmlChar const *elem, xmlChar const **attrs)
3315 g_return_val_if_fail (xin != NULL, FALSE);
3316 g_return_val_if_fail (xin->doc != NULL, FALSE);
3317 g_return_val_if_fail (xin->node != NULL, FALSE);
3319 if (GNM == xin->node->ns_id &&
3320 0 == strcmp (xin->node->id, "SHEET_OBJECTS")) {
3321 char const *type_name = gsf_xml_in_check_ns (xin, CXML2C (elem), GNM);
3322 if (type_name != NULL) {
3323 XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
3324 /* This may change xin->user_state. */
3325 xml_sax_read_obj (xin, TRUE, type_name, attrs);
3326 /* xin->user_state hasn't been restored yet. */
3327 return state->so != NULL;
3330 return FALSE;
3333 static void
3334 read_file_init_state (XMLSaxParseState *state,
3335 GOIOContext *io_context,
3336 WorkbookView *wb_view, Sheet *sheet)
3338 state->context = io_context;
3339 state->wb_view = wb_view;
3340 state->wb = sheet
3341 ? sheet->workbook
3342 : (wb_view ? wb_view_get_workbook (wb_view) : NULL);
3343 state->sheet = sheet;
3344 state->version = GNM_XML_UNKNOWN;
3345 state->last_progress_update = 0;
3346 state->convs = gnm_xml_io_conventions ();
3347 state->attribute.name = state->attribute.value = NULL;
3348 state->name.name = state->name.value = state->name.position = NULL;
3349 state->style_range_init = FALSE;
3350 state->style = NULL;
3351 state->cell.row = state->cell.col = -1;
3352 state->seen_cell_contents = FALSE;
3353 state->array_rows = state->array_cols = -1;
3354 state->expr_id = -1;
3355 state->value_type = -1;
3356 state->value_fmt = NULL;
3357 state->scenario = NULL;
3358 state->scenario_range = NULL;
3359 state->filter = NULL;
3360 state->validation.title = state->validation.msg = NULL;
3361 state->validation.texpr[0] = state->validation.texpr[1] = NULL;
3362 state->cond = NULL;
3363 state->cond_save_style = NULL;
3364 state->expr_map = g_hash_table_new_full
3365 (g_direct_hash, g_direct_equal,
3366 NULL, (GFreeFunc)gnm_expr_top_unref);
3367 state->delayed_names = NULL;
3368 state->so = NULL;
3369 state->page_breaks = NULL;
3370 state->clipboard = NULL;
3371 state->style_handler = NULL;
3372 state->style_handler_user = NULL;
3373 state->style_handler_doc = NULL;
3376 static void
3377 read_file_free_state (XMLSaxParseState *state, gboolean self)
3379 g_hash_table_destroy (state->expr_map);
3380 state->expr_map = NULL;
3382 gnm_conventions_unref (state->convs);
3383 state->convs = NULL;
3386 * Malformed documents can cause the parser to exit early.
3387 * This cleans up various bits that may be left.
3390 if (state->style) {
3391 gnm_style_unref (state->style);
3392 state->style = NULL;
3395 if (state->cond_save_style) {
3396 gnm_style_unref (state->cond_save_style);
3397 state->cond_save_style = NULL;
3400 if (state->cond) {
3401 gnm_style_cond_free (state->cond);
3402 state->cond = NULL;
3405 if (state->style_handler_doc) {
3406 gsf_xml_in_doc_free (state->style_handler_doc);
3407 state->style_handler_doc = NULL;
3410 if (self)
3411 g_free (state);
3414 typedef enum {
3415 READ_FULL_FILE,
3416 READ_CLIPBOARD
3417 } ReadFileWhat;
3419 static gboolean
3420 read_file_common (ReadFileWhat what, XMLSaxParseState *state,
3421 GOIOContext *io_context,
3422 WorkbookView *wb_view, Sheet *sheet,
3423 GsfInput *input)
3425 GsfXMLInDoc *doc;
3426 GnmLocale *locale;
3427 gboolean ok;
3429 g_return_val_if_fail (GNM_IS_WORKBOOK_VIEW (wb_view), FALSE);
3430 g_return_val_if_fail (GSF_IS_INPUT (input), FALSE);
3432 read_file_init_state (state, io_context, wb_view, sheet);
3434 switch (what) {
3435 case READ_FULL_FILE:
3436 state->do_progress = TRUE;
3437 doc = gsf_xml_in_doc_new (gnumeric_1_0_dtd, content_ns);
3438 break;
3439 case READ_CLIPBOARD:
3440 state->do_progress = FALSE;
3441 doc = gsf_xml_in_doc_new (clipboard_dtd, content_ns);
3442 if (!doc)
3443 break;
3444 gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3445 "SHEET_STYLES",
3446 "CLIPBOARDRANGE");
3447 gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3448 "SHEET_CELLS",
3449 "CLIPBOARDRANGE");
3450 gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3451 "SHEET_MERGED_REGIONS",
3452 "CLIPBOARDRANGE");
3453 gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3454 "SHEET_OBJECTS",
3455 "CLIPBOARDRANGE");
3456 break;
3457 default:
3458 g_assert_not_reached ();
3459 return FALSE;
3462 if (doc == NULL)
3463 return FALSE;
3465 gsf_xml_in_doc_set_unknown_handler (doc, &xml_sax_unknown);
3467 go_doc_init_read (GO_DOC (state->wb), input);
3468 gsf_input_seek (input, 0, G_SEEK_SET);
3470 if (state->do_progress) {
3471 go_io_progress_message (state->context,
3472 _("Reading file..."));
3473 go_io_value_progress_set (state->context,
3474 gsf_input_size (input), 0);
3477 locale = gnm_push_C_locale ();
3478 ok = gsf_xml_in_doc_parse (doc, input, state);
3479 handle_delayed_names (state);
3480 gnm_pop_C_locale (locale);
3482 go_doc_end_read (GO_DOC (state->wb));
3484 if (state->do_progress)
3485 go_io_progress_unset (state->context);
3487 if (!ok) {
3488 go_io_error_string (state->context,
3489 _("XML document not well formed!"));
3492 gsf_xml_in_doc_free (doc);
3494 return ok;
3497 /* ------------------------------------------------------------------------- */
3499 static GsfInput *
3500 maybe_gunzip (GsfInput *input)
3502 GsfInput *gzip = gsf_input_gzip_new (input, NULL);
3503 if (gzip) {
3504 g_object_unref (input);
3505 return gzip;
3506 } else {
3507 gsf_input_seek (input, 0, G_SEEK_SET);
3508 return input;
3512 static GsfInput *
3513 maybe_convert (GsfInput *input, gboolean quiet)
3515 static char const *noencheader = "<?xml version=\"1.0\"?>";
3516 static char const *encheader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3517 const size_t nelen = strlen (noencheader);
3518 const size_t elen = strlen (encheader);
3519 guint8 const *buf;
3520 gsf_off_t input_size;
3521 GString the_buffer, *buffer = &the_buffer;
3522 guint ui;
3523 GString *converted = NULL;
3524 char const *encoding;
3525 gboolean ok;
3526 gboolean any_numbered = FALSE;
3528 input_size = gsf_input_remaining (input);
3530 buf = gsf_input_read (input, nelen, NULL);
3531 if (!buf ||
3532 strncmp (noencheader, (const char *)buf, nelen) != 0 ||
3533 input_size >= (gsf_off_t)(G_MAXINT - elen))
3534 return input;
3536 input_size -= nelen;
3538 the_buffer.len = 0;
3539 the_buffer.allocated_len = input_size + elen + 1;
3540 the_buffer.str = g_try_malloc (the_buffer.allocated_len);
3541 if (!the_buffer.str)
3542 return input;
3544 g_string_append (buffer, encheader);
3545 ok = gsf_input_read (input, input_size, (guint8 *)buffer->str + elen) != NULL;
3546 gsf_input_seek (input, 0, G_SEEK_SET);
3547 if (!ok) {
3548 g_free (buffer->str);
3549 return input;
3551 buffer->len = input_size + elen;
3552 buffer->str[buffer->len] = 0;
3554 for (ui = 0; ui < buffer->len; ui++) {
3555 if (buffer->str[ui] == '&' &&
3556 buffer->str[ui + 1] == '#' &&
3557 g_ascii_isdigit (buffer->str[ui + 2])) {
3558 guint start = ui;
3559 guint c = 0;
3560 ui += 2;
3561 while (g_ascii_isdigit (buffer->str[ui])) {
3562 c = c * 10 + (buffer->str[ui] - '0');
3563 ui++;
3565 if (buffer->str[ui] == ';' && c >= 128 && c <= 255) {
3566 buffer->str[start] = c;
3567 g_string_erase (buffer, start + 1, ui - start);
3568 ui = start;
3570 any_numbered = TRUE;
3574 encoding = go_guess_encoding (buffer->str, buffer->len, NULL, &converted, NULL);
3575 if (encoding && !any_numbered &&
3576 converted && buffer->len == converted->len &&
3577 strcmp (buffer->str, converted->str) == 0)
3578 quiet = TRUE;
3580 g_free (buffer->str);
3582 if (encoding) {
3583 gsize len = converted->len;
3584 g_object_unref (input);
3585 if (!quiet)
3586 g_warning ("Converted xml document with no explicit encoding from transliterated %s to UTF-8.",
3587 encoding);
3588 return gsf_input_memory_new ((void *)g_string_free (converted, FALSE), len, TRUE);
3589 } else {
3590 if (!quiet)
3591 g_warning ("Failed to convert xml document with no explicit encoding to UTF-8.");
3592 return input;
3596 static void
3597 gnm_xml_file_open (G_GNUC_UNUSED GOFileOpener const *fo, GOIOContext *io_context,
3598 GoView *view, GsfInput *input)
3600 XMLSaxParseState state;
3601 gboolean ok;
3603 g_object_ref (input);
3604 input = maybe_gunzip (input);
3605 input = maybe_convert (input, FALSE);
3607 ok = read_file_common (READ_FULL_FILE, &state,
3608 io_context, GNM_WORKBOOK_VIEW (view), NULL,
3609 input);
3611 g_object_unref (input);
3613 if (ok) {
3614 workbook_queue_all_recalc (state.wb);
3616 workbook_set_saveinfo
3617 (state.wb,
3618 GO_FILE_FL_AUTO,
3619 go_file_saver_for_id ("Gnumeric_XmlIO:sax"));
3622 read_file_free_state (&state, FALSE);
3625 /* ------------------------------------------------------------------------- */
3627 GnmCellRegion *
3628 gnm_xml_cellregion_read (WorkbookControl *wbc, GOIOContext *io_context,
3629 Sheet *sheet,
3630 const char *buffer, int length)
3632 WorkbookView *wb_view;
3633 GsfInput *input;
3634 XMLSaxParseState state;
3635 GnmCellRegion *result;
3637 wb_view = wb_control_view (wbc);
3638 input = gsf_input_memory_new (buffer, length, FALSE);
3639 read_file_common (READ_CLIPBOARD, &state,
3640 io_context, wb_view, sheet,
3641 input);
3642 g_object_unref (input);
3644 result = state.clipboard;
3645 state.clipboard = NULL;
3647 read_file_free_state (&state, FALSE);
3649 return result;
3652 /* ------------------------------------------------------------------------- */
3654 static void
3655 style_parser_done (GsfXMLIn *xin, XMLSaxParseState *old_state)
3657 GnmStyle *style = old_state->style;
3658 old_state->style_handler (xin, style, old_state->style_handler_user);
3659 read_file_free_state (old_state, TRUE);
3663 * gnm_xml_prep_style_parser:
3664 * @xin:
3665 * @attrs:
3666 * @handler: (scope call):
3667 * @user: user data.
3670 void
3671 gnm_xml_prep_style_parser (GsfXMLIn *xin,
3672 xmlChar const **attrs,
3673 GnmXmlStyleHandler handler,
3674 gpointer user)
3676 static GsfXMLInNode dtd[] = {
3677 GSF_XML_IN_NODE (STYLE_STYLE, STYLE_STYLE, GNM, "Style", GSF_XML_NO_CONTENT, &xml_sax_style_start, NULL),
3678 /* Nodes added below. */
3679 GSF_XML_IN_NODE_END
3681 GsfXMLInDoc *doc = gsf_xml_in_doc_new (dtd, NULL);
3682 XMLSaxParseState *state = g_new0 (XMLSaxParseState, 1);
3684 read_file_init_state (state, NULL, NULL, NULL);
3685 state->style_handler = handler;
3686 state->style_handler_user = user;
3687 state->style_handler_doc = doc;
3688 state->style = gnm_style_new_default ();
3690 /* Not a full style, just those parts that do not require a sheet. */
3691 gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3692 "STYLE_FONT",
3693 "STYLE_STYLE");
3694 gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
3695 "STYLE_BORDER",
3696 "STYLE_STYLE");
3698 gsf_xml_in_push_state (xin, doc, state,
3699 (GsfXMLInExtDtor)style_parser_done, attrs);
3702 /* ------------------------------------------------------------------------- */
3704 static gboolean
3705 gnm_xml_probe_element (const xmlChar *name,
3706 G_GNUC_UNUSED const xmlChar *prefix,
3707 const xmlChar *URI,
3708 G_GNUC_UNUSED int nb_namespaces,
3709 G_GNUC_UNUSED const xmlChar **namespaces,
3710 G_GNUC_UNUSED int nb_attributes,
3711 G_GNUC_UNUSED int nb_defaulted,
3712 G_GNUC_UNUSED const xmlChar **attributes)
3714 return 0 == strcmp (name, "Workbook") &&
3715 NULL != URI && NULL != strstr (URI, "gnumeric");
3718 static gboolean
3719 xml_probe (G_GNUC_UNUSED GOFileOpener const *fo, GsfInput *input, GOFileProbeLevel pl)
3721 if (pl == GO_FILE_PROBE_FILE_NAME) {
3722 char const *name = gsf_input_name (input);
3723 int len;
3725 if (name == NULL)
3726 return FALSE;
3728 len = strlen (name);
3729 if (len >= 7 && !g_ascii_strcasecmp (name+len-7, ".xml.gz"))
3730 return TRUE;
3732 name = gsf_extension_pointer (name);
3734 return (name != NULL &&
3735 (g_ascii_strcasecmp (name, "gnumeric") == 0 ||
3736 g_ascii_strcasecmp (name, "xml") == 0));
3738 /* probe by content */
3739 return gsf_xml_probe (input, &gnm_xml_probe_element);
3742 #define XML_SAX_ID "Gnumeric_XmlIO:sax"
3744 void
3745 gnm_xml_sax_read_init (void)
3747 GOFileOpener *opener;
3748 GSList *suffixes = go_slist_create (g_strdup ("gnumeric"),
3749 g_strdup ("xml"),
3750 NULL);
3751 GSList *mimes = go_slist_create (g_strdup ("application/x-gnumeric"),
3752 NULL);
3754 opener = go_file_opener_new
3755 (XML_SAX_ID,
3756 _("Gnumeric XML (*.gnumeric)"),
3757 suffixes, mimes,
3758 xml_probe, gnm_xml_file_open);
3759 go_file_opener_register (opener, 50);
3760 g_object_unref (opener);
3763 void
3764 gnm_xml_sax_read_shutdown (void)
3766 go_file_opener_unregister
3767 (go_file_opener_for_id (XML_SAX_ID));