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