Make graphs (and images) not resize with cells by default. [#684450]
[gnumeric.git] / plugins / excel / xlsx-read.c
blob61ef640c1a97f0917e886ca0ab5830c7ced5104b
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * xlsx-read.c : Read MS Excel 2007 Office Open xml
5 * Copyright (C) 2006-2007 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
22 #include <gnumeric-config.h>
23 #include "xlsx-utils.h"
24 #include "ms-excel-write.h"
26 #include "sheet-view.h"
27 #include "sheet-style.h"
28 #include "sheet-merge.h"
29 #include "sheet.h"
30 #include "ranges.h"
31 #include "style.h"
32 #include "style-border.h"
33 #include "style-color.h"
34 #include "style-conditions.h"
35 #include "gnm-format.h"
36 #include "cell.h"
37 #include "position.h"
38 #include "expr.h"
39 #include "expr-name.h"
40 #include "print-info.h"
41 #include "validation.h"
42 #include "input-msg.h"
43 #include "value.h"
44 #include "sheet-filter.h"
45 #include "hlink.h"
46 #include "selection.h"
47 #include "command-context.h"
48 #include "workbook-view.h"
49 #include "workbook.h"
50 #include "gutils.h"
51 #include "graph.h"
52 #include "sheet-object-graph.h"
53 #include "sheet-object-cell-comment.h"
54 #include "gnm-sheet-slicer.h"
55 #include "gnm-so-filled.h"
56 #include "gnm-so-line.h"
57 #include "sheet-object-image.h"
58 #include "number-match.h"
59 #include "dead-kittens.h"
61 #include <goffice/goffice.h>
64 #include "goffice-data.h" /* MOVE TO GOFFCE with slicer code */
65 #include "go-data-slicer-field.h" /* MOVE TO GOFFCE with slicer code */
67 #include <gsf/gsf-libxml.h>
68 #include <gsf/gsf-input.h>
69 #include <gsf/gsf-infile.h>
70 #include <gsf/gsf-infile-zip.h>
71 #include <gsf/gsf-open-pkg-utils.h>
72 #include <gsf/gsf-meta-names.h>
73 #include <gsf/gsf-doc-meta-data.h>
74 #include <gsf/gsf-docprop-vector.h>
75 #include <gsf/gsf-timestamp.h>
77 #include <glib/gi18n-lib.h>
78 #include <gmodule.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include <errno.h>
83 /*****************************************************************************/
85 #define CXML2C(s) ((char const *)(s))
87 enum {
88 ECMA_376_2006 = 1,
89 ECMA_376_2008 = 2
92 typedef enum {
93 XLXS_TYPE_NUM,
94 XLXS_TYPE_SST_STR, /* 0 based index into sst */
95 XLXS_TYPE_BOOL,
96 XLXS_TYPE_ERR,
97 XLXS_TYPE_INLINE_STR, /* inline string */
98 /* How is this different from inlineStr ?? */
99 XLXS_TYPE_STR2
100 } XLSXValueType;
101 typedef enum {
102 XLSX_PANE_TOP_LEFT = 0,
103 XLSX_PANE_TOP_RIGHT = 1,
104 XLSX_PANE_BOTTOM_LEFT = 2,
105 XLSX_PANE_BOTTOM_RIGHT = 3
106 } XLSXPanePos;
108 typedef enum {
109 XLSX_AXIS_UNKNOWN,
110 XLSX_AXIS_CAT,
111 XLSX_AXIS_VAL,
112 XLSX_AXIS_DATE
113 } XLSXAxisType;
114 typedef struct {
115 char *id;
116 GogAxis *axis;
117 GSList *plots;
118 XLSXAxisType type;
119 GogObjectPosition compass;
120 GogAxisPosition cross;
121 char *cross_id;
122 gnm_float cross_value;
123 gboolean invert_axis;
124 double logbase;
126 double axis_elements[GOG_AXIS_ELEM_MAX_ENTRY];
127 guint8 axis_element_set[GOG_AXIS_ELEM_MAX_ENTRY];
129 gboolean deleted;
130 } XLSXAxisInfo;
132 typedef struct {
133 GsfInfile *zip;
135 int version;
137 GOIOContext *context; /* The IOcontext managing things */
138 WorkbookView *wb_view; /* View for the new workbook */
139 Workbook *wb; /* The new workbook */
141 Sheet *sheet; /* current sheet */
142 GnmCellPos pos; /* current cell */
143 XLSXValueType pos_type;
144 GnmValue *val;
145 GnmExprTop const *texpr;
146 GnmRange array;
147 char *shared_id;
148 GHashTable *shared_exprs;
149 GnmConventions *convs;
151 SheetView *sv; /* current sheetview */
153 GArray *sst;
155 GHashTable *num_fmts;
156 GOFormat *date_fmt;
157 GHashTable *cell_styles;
158 GPtrArray *fonts;
159 GPtrArray *fills;
160 GPtrArray *borders;
161 GPtrArray *xfs;
162 GPtrArray *style_xfs;
163 GPtrArray *dxfs;
164 GPtrArray *table_styles;
165 GnmStyle *style_accum;
166 gboolean style_accum_partial;
167 GnmStyleBorderType border_style;
168 GnmColor *border_color;
170 GHashTable *theme_colors_by_name;
172 GPtrArray *collection; /* utility for the shared collection handlers */
173 unsigned count;
174 XLSXPanePos pane_pos;
176 GnmStyleConditions *conditions;
177 GSList *cond_regions;
178 GnmStyleCond *cond;
180 GnmFilter *filter;
181 int filter_cur_field;
182 GSList *filter_items; /* an accumulator */
184 GSList *validation_regions;
185 GnmValidation *validation;
186 GnmInputMsg *input_msg;
188 GnmPageBreaks *page_breaks;
190 /* Rows/Cols state */
191 GnmStyle *pending_rowcol_style;
192 GnmRange pending_rowcol_range;
194 /* Drawing state */
195 SheetObject *so;
196 gint64 drawing_pos[8];
197 int drawing_pos_flags;
198 GODrawingAnchorDir so_direction;
199 GnmSOAnchorMode so_anchor_mode;
200 GnmExprTop const *link_texpr;
202 /* Legacy drawing state */
203 double grp_offset[4];
204 GSList *grp_stack;
206 /* Charting state */
207 GogGraph *graph;
208 GogChart *chart;
209 GogPlot *plot;
210 GogSeries *series;
211 int dim_type;
212 GogObject *series_pt;
213 gboolean series_pt_has_index;
214 GOStyle *cur_style;
215 int gradient_count;
216 guint32 chart_color_state;
217 GOColor color;
218 GOMarker *marker;
219 GogObject *cur_obj;
220 GSList *obj_stack;
221 GSList *style_stack;
222 unsigned int sp_type;
223 char *chart_tx;
224 gboolean inhibit_text_pop;
225 gnm_float chart_pos[4]; /* x, w, y, h */
226 gboolean chart_pos_mode[4]; /* false: "factor", true: "edge" */
227 gboolean chart_pos_target; /* true if "inner" */
228 int radio_value;
229 int zindex;
231 struct {
232 GogAxis *obj;
233 int type;
234 GHashTable *by_id;
235 GHashTable *by_obj;
236 XLSXAxisInfo *info;
237 } axis;
239 char *defined_name;
240 Sheet *defined_name_sheet;
241 GList *delayed_names;
243 GSList *pending_objects;
244 GHashTable *zorder;
246 /* external refs */
247 Workbook *external_ref;
248 Sheet *external_ref_sheet;
250 /* Pivot state */
251 struct {
252 GnmSheetSlicer *slicer;
253 GODataSlicerField *slicer_field;
255 GHashTable *cache_by_id;
256 GODataCache *cache;
257 GODataCacheSource *cache_src;
258 GODataCacheField *cache_field;
259 GPtrArray *cache_field_values;
261 unsigned int field_count, record_count;
262 char *cache_record_part_id;
263 } pivot;
265 /* Comment state */
266 GPtrArray *authors;
267 GObject *comment;
269 /* Document Properties */
270 GsfDocMetaData *metadata;
271 char *meta_prop_name;
273 /* Rich Text handling */
274 GString *r_text;
275 PangoAttrList *rich_attrs;
276 PangoAttrList *run_attrs;
277 } XLSXReadState;
278 typedef struct {
279 GOString *str;
280 GOFormat *markup;
281 } XLSXStr;
283 static GsfXMLInNS const xlsx_ns[] = {
284 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.openxmlformats.org/spreadsheetml/2006/main"), /* Office 12 */
285 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.openxmlformats.org/spreadsheetml/2006/7/main"), /* Office 12 BETA-2 Technical Refresh */
286 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.openxmlformats.org/spreadsheetml/2006/5/main"), /* Office 12 BETA-2 */
287 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.microsoft.com/office/excel/2006/2"), /* Office 12 BETA-1 Technical Refresh */
288 GSF_XML_IN_NS (XL_NS_SS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"), /* Office 12 BETA-2 */
289 GSF_XML_IN_NS (XL_NS_SS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/3/spreadsheetDrawing"), /* Office 12 BETA-2 Technical Refresh */
290 GSF_XML_IN_NS (XL_NS_CHART, "http://schemas.openxmlformats.org/drawingml/2006/3/chart"), /* Office 12 BETA-2 */
291 GSF_XML_IN_NS (XL_NS_CHART, "http://schemas.openxmlformats.org/drawingml/2006/chart"), /* Office 12 BETA-2 Technical Refresh */
292 GSF_XML_IN_NS (XL_NS_CHART_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"),
293 GSF_XML_IN_NS (XL_NS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/3/main"), /* Office 12 BETA-2 */
294 GSF_XML_IN_NS (XL_NS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/main"), /* Office 12 BETA-2 Technical Refresh */
295 GSF_XML_IN_NS (XL_NS_GNM_EXT, "http://www.gnumeric.org/ext/spreadsheetml"),
296 GSF_XML_IN_NS (XL_NS_DOC_REL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships"),
297 GSF_XML_IN_NS (XL_NS_PKG_REL, "http://schemas.openxmlformats.org/package/2006/relationships"),
298 GSF_XML_IN_NS (XL_NS_LEG_OFF, "urn:schemas-microsoft-com:office:office"),
299 GSF_XML_IN_NS (XL_NS_LEG_XL, "urn:schemas-microsoft-com:office:excel"),
300 GSF_XML_IN_NS (XL_NS_LEG_VML, "urn:schemas-microsoft-com:vml"),
301 GSF_XML_IN_NS (XL_NS_PROP_CP, "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"),
302 GSF_XML_IN_NS (XL_NS_PROP_DC, "http://purl.org/dc/elements/1.1/"),
303 GSF_XML_IN_NS (XL_NS_PROP_DCMITYPE, "http://purl.org/dc/dcmitype"),
304 GSF_XML_IN_NS (XL_NS_PROP_DCTERMS, "http://purl.org/dc/terms/"),
305 GSF_XML_IN_NS (XL_NS_PROP_XSI, "http://www.w3.org/2001/XMLSchema-instance"),
306 GSF_XML_IN_NS (XL_NS_PROP, "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"),
307 GSF_XML_IN_NS (XL_NS_PROP_VT, "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"),
308 GSF_XML_IN_NS (XL_NS_PROP_CUSTOM, "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"),
309 { NULL, 0 }
312 typedef struct {
313 int code;
314 gdouble width;
315 gdouble height;
316 GtkUnit unit;
317 gchar const *name;
318 } XLSXPaperDefs;
321 static void
322 maybe_update_progress (GsfXMLIn *xin)
324 XLSXReadState *state = (XLSXReadState *)xin->user_state;
325 GsfInput *input = gsf_xml_in_get_input (xin);
326 gsf_off_t pos = gsf_input_tell (input);
328 go_io_value_progress_update (state->context, pos);
331 static void
332 start_update_progress (XLSXReadState *state, GsfInput *xin,
333 char const *message, double min, double max)
335 go_io_progress_range_push (state->context, min, max);
336 if (xin) {
337 go_io_value_progress_set (state->context,
338 gsf_input_size (xin), 10000);
339 go_io_progress_message (state->context, message);
343 static void
344 end_update_progress (XLSXReadState *state)
346 go_io_progress_range_pop (state->context);
349 static gboolean
350 xlsx_parse_stream (XLSXReadState *state, GsfInput *in, GsfXMLInNode const *dtd)
352 gboolean success = FALSE;
354 if (NULL != in) {
355 GsfXMLInDoc *doc = gsf_xml_in_doc_new (dtd, xlsx_ns);
357 success = gsf_xml_in_doc_parse (doc, in, state);
359 if (!success)
360 go_io_warning (state->context,
361 _("'%s' is corrupt!"),
362 gsf_input_name (in));
364 gsf_xml_in_doc_free (doc);
365 g_object_unref (in);
367 return success;
370 static void
371 xlsx_parse_rel_by_id (GsfXMLIn *xin, char const *part_id,
372 GsfXMLInNode const *dtd,
373 GsfXMLInNS const *ns)
375 GError *err;
376 gboolean debug = gnm_debug_flag ("xlsx-parsing");
378 if (debug)
379 g_printerr ("{ /* Parsing : %s :: %s */\n",
380 gsf_input_name (gsf_xml_in_get_input (xin)), part_id);
382 err = gsf_open_pkg_parse_rel_by_id (xin, part_id, dtd, ns);
383 if (NULL != err) {
384 XLSXReadState *state = (XLSXReadState *)xin->user_state;
385 go_io_warning (state->context, "%s", err->message);
386 g_error_free (err);
389 if (debug)
390 g_printerr ("} /* DONE : %s :: %s */\n",
391 gsf_input_name (gsf_xml_in_get_input (xin)), part_id);
394 /****************************************************************************/
396 static gboolean xlsx_warning (GsfXMLIn *xin, char const *fmt, ...)
397 G_GNUC_PRINTF (2, 3);
399 static gboolean
400 xlsx_warning (GsfXMLIn *xin, char const *fmt, ...)
402 XLSXReadState *state = (XLSXReadState *)xin->user_state;
403 char *msg;
404 va_list args;
406 va_start (args, fmt);
407 msg = g_strdup_vprintf (fmt, args);
408 va_end (args);
410 if (IS_SHEET (state->sheet)) {
411 char *tmp;
412 if (state->pos.col >= 0 && state->pos.row >= 0)
413 tmp = g_strdup_printf ("%s!%s : %s",
414 state->sheet->name_quoted,
415 cellpos_as_string (&state->pos), msg);
416 else
417 tmp = g_strdup_printf ("%s : %s",
418 state->sheet->name_quoted, msg);
419 g_free (msg);
420 msg = tmp;
423 go_io_warning (state->context, "%s", msg);
424 g_printerr ("%s\n", msg);
425 g_free (msg);
427 return FALSE; /* convenience */
430 typedef struct {
431 char const * const name;
432 int val;
433 } EnumVal;
435 static gboolean
436 attr_enum (GsfXMLIn *xin, xmlChar const **attrs,
437 char const *target, EnumVal const *enums,
438 int *res)
440 g_return_val_if_fail (attrs != NULL, FALSE);
441 g_return_val_if_fail (attrs[0] != NULL, FALSE);
442 g_return_val_if_fail (attrs[1] != NULL, FALSE);
444 if (strcmp (attrs[0], target))
445 return FALSE;
447 for (; enums->name != NULL ; enums++)
448 if (!strcmp (enums->name, attrs[1])) {
449 *res = enums->val;
450 return TRUE;
452 return xlsx_warning (xin,
453 _("Unknown enum value '%s' for attribute %s"),
454 attrs[1], target);
458 * Take an _int_ as a result to allow the caller to use -1 as an undefined state.
460 static gboolean
461 attr_bool (G_GNUC_UNUSED GsfXMLIn *xin, xmlChar const **attrs,
462 char const *target,
463 int *res)
465 g_return_val_if_fail (attrs != NULL, FALSE);
466 g_return_val_if_fail (attrs[0] != NULL, FALSE);
467 g_return_val_if_fail (attrs[1] != NULL, FALSE);
469 if (strcmp (attrs[0], target))
470 return FALSE;
472 *res = (0 == strcmp (attrs[1], "1") || 0 == strcmp (attrs[1], "true")) ;
474 return TRUE;
477 static gboolean
478 attr_int (GsfXMLIn *xin, xmlChar const **attrs,
479 char const *target,
480 int *res)
482 char *end;
483 long tmp;
485 g_return_val_if_fail (attrs != NULL, FALSE);
486 g_return_val_if_fail (attrs[0] != NULL, FALSE);
487 g_return_val_if_fail (attrs[1] != NULL, FALSE);
489 if (strcmp (attrs[0], target))
490 return FALSE;
492 errno = 0;
493 tmp = strtol (attrs[1], &end, 10);
494 if (errno == ERANGE || tmp > G_MAXINT || tmp < G_MININT)
495 return xlsx_warning (xin,
496 _("Integer '%s' is out of range, for attribute %s"),
497 attrs[1], target);
498 if (*end)
499 return xlsx_warning (xin,
500 _("Invalid integer '%s' for attribute %s"),
501 attrs[1], target);
503 *res = tmp;
504 return TRUE;
507 static gboolean
508 attr_uint (GsfXMLIn *xin, xmlChar const **attrs,
509 char const *target, unsigned *res)
511 char *end;
512 unsigned long tmp;
514 g_return_val_if_fail (attrs != NULL, FALSE);
515 g_return_val_if_fail (attrs[0] != NULL, FALSE);
516 g_return_val_if_fail (attrs[1] != NULL, FALSE);
518 if (strcmp (attrs[0], target))
519 return FALSE;
521 errno = 0;
522 tmp = strtoul (attrs[1], &end, 10);
523 if (errno == ERANGE || tmp != (unsigned)tmp)
524 return xlsx_warning (xin,
525 _("Unisgned integer '%s' is out of range, for attribute %s"),
526 attrs[1], target);
527 if (*end)
528 return xlsx_warning (xin,
529 _("Invalid unsigned integer '%s' for attribute %s"),
530 attrs[1], target);
532 *res = tmp;
533 return TRUE;
536 static gboolean
537 attr_int64 (GsfXMLIn *xin, xmlChar const **attrs,
538 char const *target,
539 gint64 *res)
541 char *end;
542 gint64 tmp;
544 g_return_val_if_fail (attrs != NULL, FALSE);
545 g_return_val_if_fail (attrs[0] != NULL, FALSE);
546 g_return_val_if_fail (attrs[1] != NULL, FALSE);
548 if (strcmp (attrs[0], target))
549 return FALSE;
551 errno = 0;
552 tmp = g_ascii_strtoll (attrs[1], &end, 10);
553 if (errno == ERANGE)
554 return xlsx_warning (xin,
555 _("Integer '%s' is out of range, for attribute %s"),
556 attrs[1], target);
557 if (*end)
558 return xlsx_warning (xin,
559 _("Invalid integer '%s' for attribute %s"),
560 attrs[1], target);
562 *res = tmp;
563 return TRUE;
566 static gboolean
567 attr_gocolor (GsfXMLIn *xin, xmlChar const **attrs,
568 char const *target,
569 GOColor *res)
571 char *end;
572 unsigned long rgb;
574 g_return_val_if_fail (attrs != NULL, FALSE);
575 g_return_val_if_fail (attrs[0] != NULL, FALSE);
576 g_return_val_if_fail (attrs[1] != NULL, FALSE);
578 if (strcmp (attrs[0], target))
579 return FALSE;
581 errno = 0;
582 rgb = strtoul (attrs[1], &end, 16);
583 if (errno == ERANGE || *end)
584 return xlsx_warning (xin,
585 _("Invalid RRGGBB color '%s' for attribute %s"),
586 attrs[1], target);
589 guint8 const r = (rgb >> 16) & 0xff;
590 guint8 const g = (rgb >> 8) & 0xff;
591 guint8 const b = (rgb >> 0) & 0xff;
592 *res = GO_COLOR_FROM_RGB (r, g, b);
595 return TRUE;
598 static gboolean
599 attr_float (GsfXMLIn *xin, xmlChar const **attrs,
600 char const *target,
601 gnm_float *res)
603 char *end;
604 double tmp;
606 g_return_val_if_fail (attrs != NULL, FALSE);
607 g_return_val_if_fail (attrs[0] != NULL, FALSE);
608 g_return_val_if_fail (attrs[1] != NULL, FALSE);
610 if (strcmp (attrs[0], target))
611 return FALSE;
613 tmp = gnm_strto (attrs[1], &end);
614 if (*end)
615 return xlsx_warning (xin,
616 _("Invalid number '%s' for attribute %s"),
617 attrs[1], target);
618 *res = tmp;
619 return TRUE;
623 * Either an integer scaled so 100000 means 100%, or something like "50%"
624 * which we'll return as 50*1000.
626 * The first seems off-spec, but is what Excel produces.
628 static gboolean
629 attr_percent (GsfXMLIn *xin, xmlChar const **attrs,
630 char const *target, int *res)
632 char *end;
633 long tmp;
635 g_return_val_if_fail (attrs != NULL, FALSE);
636 g_return_val_if_fail (attrs[0] != NULL, FALSE);
637 g_return_val_if_fail (attrs[1] != NULL, FALSE);
639 if (strcmp (attrs[0], target))
640 return FALSE;
642 errno = 0;
643 tmp = strtol (attrs[1], &end, 10);
644 if (errno == ERANGE || tmp > G_MAXINT / 1000 || tmp < G_MININT / 1000)
645 return xlsx_warning (xin,
646 _("Integer '%s' is out of range, for attribute %s"),
647 attrs[1], target);
648 if (*end == 0)
649 *res = tmp;
650 else if (strcmp (end, "%") == 0)
651 *res = tmp * 1000;
652 else
653 return xlsx_warning (xin,
654 _("Invalid integer '%s' for attribute %s"),
655 attrs[1], target);
657 return TRUE;
661 static gboolean
662 attr_pos (GsfXMLIn *xin, xmlChar const **attrs,
663 char const *target,
664 GnmCellPos *res)
666 XLSXReadState *state = (XLSXReadState *)xin->user_state;
667 char const *end;
668 GnmCellPos tmp;
670 g_return_val_if_fail (attrs != NULL, FALSE);
671 g_return_val_if_fail (attrs[0] != NULL, FALSE);
672 g_return_val_if_fail (attrs[1] != NULL, FALSE);
674 if (strcmp (attrs[0], target))
675 return FALSE;
677 end = cellpos_parse (attrs[1], gnm_sheet_get_size (state->sheet), &tmp, TRUE);
678 if (NULL == end || *end != '\0')
679 return xlsx_warning (xin,
680 _("Invalid cell position '%s' for attribute %s"),
681 attrs[1], target);
682 *res = tmp;
683 return TRUE;
686 static gboolean
687 attr_range (GsfXMLIn *xin, xmlChar const **attrs,
688 char const *target,
689 GnmRange *res)
691 static const GnmSheetSize xlsx_size = {
692 XLSX_MaxCol, XLSX_MaxRow
695 g_return_val_if_fail (attrs != NULL, FALSE);
696 g_return_val_if_fail (attrs[0] != NULL, FALSE);
697 g_return_val_if_fail (attrs[1] != NULL, FALSE);
699 if (strcmp (attrs[0], target))
700 return FALSE;
702 if (!range_parse (res, attrs[1], &xlsx_size))
703 xlsx_warning (xin, _("Invalid range '%s' for attribute %s"),
704 attrs[1], target);
705 return TRUE;
708 static GnmValue *
709 attr_datetime (GsfXMLIn *xin, xmlChar const **attrs,
710 char const *target)
712 unsigned y, m, d, h, mi, n;
713 GnmValue *res = NULL;
714 gnm_float s;
716 g_return_val_if_fail (attrs != NULL, NULL);
717 g_return_val_if_fail (attrs[0] != NULL, NULL);
718 g_return_val_if_fail (attrs[1] != NULL, NULL);
720 if (strcmp (attrs[0], target))
721 return NULL;
723 n = sscanf (attrs[1], "%u-%u-%uT%u:%u:%" GNM_SCANF_g,
724 &y, &m, &d, &h, &mi, &s);
726 if (n >= 3) {
727 GDate date;
728 g_date_set_dmy (&date, d, m, y);
729 if (g_date_valid (&date)) {
730 XLSXReadState *state = (XLSXReadState *)xin->user_state;
731 unsigned d_serial = go_date_g_to_serial (&date,
732 workbook_date_conv (state->wb));
733 if (n >= 6) {
734 double time_frac = h + (gnm_float)mi / 60 + s / 3600;
735 res = value_new_float (d_serial + time_frac / 24.);
736 value_set_fmt (res, state->date_fmt);
737 } else {
738 res = value_new_int (d_serial);
739 value_set_fmt (res, go_format_default_date ());
744 return res;
747 /* returns pts */
748 static gboolean
749 xlsx_parse_distance (GsfXMLIn *xin, xmlChar const *str,
750 char const *name, gnm_float *pts)
752 double num;
753 char *end = NULL;
755 g_return_val_if_fail (str != NULL, FALSE);
757 num = go_strtod (CXML2C (str), &end);
758 if (CXML2C (str) != end) {
759 if (0 == strncmp (end, "mm", 2)) {
760 num = GO_CM_TO_PT (num/10.);
761 end += 2;
762 } else if (0 == strncmp (end, "cm", 2)) {
763 num = GO_CM_TO_PT (num);
764 end += 2;
765 } else if (0 == strncmp (end, "pt", 2)) {
766 end += 2;
767 } else if (0 == strncmp (end, "pc", 2)) { /* pica 12pt == 1 pica */
768 num /= 12.;
769 end += 2;
770 } else if (0 == strncmp (end, "pi", 2)) { /* pica 12pt == 1 pica */
771 num /= 12.;
772 end += 2;
773 } else if (0 == strncmp (end, "in", 2)) {
774 num = GO_IN_TO_PT (num);
775 end += 2;
776 } else {
777 xlsx_warning (xin, _("Invalid attribute '%s', unknown unit '%s'"),
778 name, str);
779 return FALSE;
781 } else {
782 xlsx_warning (xin, _("Invalid attribute '%s', expected distance, received '%s'"),
783 name, str);
784 return FALSE;
787 if (*end) {
788 return xlsx_warning (xin,
789 _("Invalid attribute '%s', expected distance, received '%s'"),
790 name, str);
791 return FALSE;
794 *pts = num;
795 return TRUE;
798 /* returns pts */
799 static gboolean
800 attr_distance (GsfXMLIn *xin, xmlChar const **attrs,
801 char const *target, gnm_float *pts)
803 g_return_val_if_fail (attrs != NULL, FALSE);
804 g_return_val_if_fail (attrs[0] != NULL, FALSE);
805 g_return_val_if_fail (attrs[1] != NULL, FALSE);
807 if (strcmp (attrs[0], target))
808 return FALSE;
810 return xlsx_parse_distance (xin, attrs[1], target, pts);
813 /***********************************************************************/
815 static gboolean
816 simple_bool (GsfXMLIn *xin, xmlChar const **attrs, int *res)
818 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
819 if (attr_bool (xin, attrs, "val", res))
820 return TRUE;
821 return FALSE;
824 #if 0
825 static gboolean
826 simple_int (GsfXMLIn *xin, xmlChar const **attrs, int *res)
828 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
829 if (attr_int (xin, attrs, "val", res))
830 return TRUE;
831 return FALSE;
833 #endif
836 static gboolean
837 simple_uint (GsfXMLIn *xin, xmlChar const **attrs, unsigned *res)
839 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
840 if (attr_uint (xin, attrs, "val", res))
841 return TRUE;
842 return FALSE;
845 static gboolean
846 simple_float (GsfXMLIn *xin, xmlChar const **attrs, gnm_float *res)
848 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
849 if (attr_float (xin, attrs, "val", res))
850 return TRUE;
851 return FALSE;
854 static gboolean
855 simple_enum (GsfXMLIn *xin, xmlChar const **attrs, EnumVal const *enums, int *res)
857 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
858 if (attr_enum (xin, attrs, "val", enums, res))
859 return TRUE;
860 return FALSE;
863 static const char *
864 simple_string (G_GNUC_UNUSED GsfXMLIn *xin, xmlChar const **attrs)
866 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
867 if (strcmp (attrs[0], "val") == 0)
868 return CXML2C (attrs[1]);
869 return NULL;
872 /***********************************************************************
873 * These indexes look like the values in xls. Dup some code from there.
874 * TODO : Can we merge the code ?
875 * Will the 'indexedColors' look like a palette ?
877 static struct {
878 guint8 r, g, b;
879 } xlsx_default_palette_v8 [] = {
880 { 0, 0, 0}, {255,255,255}, {255, 0, 0}, { 0,255, 0},
881 { 0, 0,255}, {255,255, 0}, {255, 0,255}, { 0,255,255},
883 {128, 0, 0}, { 0,128, 0}, { 0, 0,128}, {128,128, 0},
884 {128, 0,128}, { 0,128,128}, {192,192,192}, {128,128,128},
886 {153,153,255}, {153, 51,102}, {255,255,204}, {204,255,255},
887 {102, 0,102}, {255,128,128}, { 0,102,204}, {204,204,255},
889 { 0, 0,128}, {255, 0,255}, {255,255, 0}, { 0,255,255},
890 {128, 0,128}, {128, 0, 0}, { 0,128,128}, { 0, 0,255},
892 { 0,204,255}, {204,255,255}, {204,255,204}, {255,255,153},
893 {153,204,255}, {255,153,204}, {204,153,255}, {255,204,153},
895 { 51,102,255}, { 51,204,204}, {153,204, 0}, {255,204, 0},
896 {255,153, 0}, {255,102, 0}, {102,102,153}, {150,150,150},
898 { 0, 51,102}, { 51,153,102}, { 0, 51, 0}, { 51, 51, 0},
899 {153, 51, 0}, {153, 51,102}, { 51, 51,153}, { 51, 51, 51}
902 static GOColor
903 indexed_color (G_GNUC_UNUSED XLSXReadState *state, gint idx)
905 /* NOTE: not documented but seems close
906 * If you find a normative reference please forward it.
908 * The color index field seems to use
909 * 8-63 = Palette index 0-55
910 * 64 = auto pattern, auto border
911 * 65 = auto background
912 * 127 = auto font
914 * 65 is always white, and 127 always black. 64 is black
915 * if the fDefaultHdr flag in WINDOW2 is unset, otherwise it's
916 * the grid color from WINDOW2.
919 if (idx == 1 || idx == 65)
920 return GO_COLOR_WHITE;
921 switch (idx) {
922 case 0: /* black */
923 case 64 : /* system text ? */
924 case 81 : /* tooltip text */
925 case 0x7fff : /* system text ? */
926 return GO_COLOR_BLACK;
928 case 1 : /* white */
929 case 65 : /* system back ? */
930 return GO_COLOR_WHITE;
932 case 80 : /* tooltip background */
933 return GO_COLOR_YELLOW;
935 case 2 : return GO_COLOR_RED;
936 case 3 : return GO_COLOR_GREEN;
937 case 4 : return GO_COLOR_BLUE;
938 case 5 : return GO_COLOR_YELLOW;
939 case 6 : return GO_COLOR_VIOLET;
940 case 7 : return GO_COLOR_CYAN;
942 default :
943 break;
946 idx -= 8;
947 if (idx < 0 || (int) G_N_ELEMENTS (xlsx_default_palette_v8) <= idx) {
948 g_warning ("EXCEL: color index (%d) is out of range (8..%d). Defaulting to black",
949 idx + 8, (int)G_N_ELEMENTS (xlsx_default_palette_v8) + 8);
950 return GO_COLOR_BLACK;
953 /* TODO cache and ref */
954 return GO_COLOR_FROM_RGB (xlsx_default_palette_v8[idx].r,
955 xlsx_default_palette_v8[idx].g,
956 xlsx_default_palette_v8[idx].b);
959 static GOColor
960 themed_color (GsfXMLIn *xin, gint idx)
962 static char const * const theme_elements [] = {
963 "lt1", "dk1", "lt2", "dk2",
964 "accent1", "accent2", "accent3", "accent4", "accent5", "accent6",
965 "hlink", "folHlink"
967 XLSXReadState *state = (XLSXReadState *)xin->user_state;
969 /* MAGIC :
970 * looks like the indicies map to hard coded names rather than the
971 * order in the file. Indeed the order in the file seems wrong
972 * it inverts the first to pairs
973 * 1,0,3,2, 4,5,6.....
974 * see: http://openxmldeveloper.org/forums/thread/1306.aspx
975 * OOo seems to do something similar
977 * I'll make the assumption we should work by name rather than
978 * index. */
979 if (idx >= 0 && idx < (int) G_N_ELEMENTS (theme_elements)) {
980 gpointer color = g_hash_table_lookup (state->theme_colors_by_name,
981 theme_elements [idx]);
982 if (NULL != color)
983 return GPOINTER_TO_UINT (color);
985 xlsx_warning (xin, _("Unknown theme color %d"), idx);
986 } else {
987 xlsx_warning (xin, "Color index (%d) is out of range (0..%d). Defaulting to black",
988 idx, (int) G_N_ELEMENTS (theme_elements));
991 return GO_COLOR_BLACK;
994 static GOFormat *
995 xlsx_get_num_fmt (GsfXMLIn *xin, char const *id)
997 static char const * const std_builtins[] = {
998 /* 0 */ "General",
999 /* 1 */ "0",
1000 /* 2 */ "0.00",
1001 /* 3 */ "#,##0",
1002 /* 4 */ "#,##0.00",
1003 /* 5 */ NULL,
1004 /* 6 */ NULL,
1005 /* 7 */ NULL,
1006 /* 8 */ NULL,
1007 /* 9 */ "0%",
1008 /* 10 */ "0.00%",
1009 /* 11 */ "0.00E+00",
1010 /* 12 */ "# ?/?",
1011 /* 13 */ "# ?""?/?""?", /* silly trick to avoid using a trigraph */
1012 /* 14 */ "mm-dd-yy",
1013 /* 15 */ "d-mmm-yy",
1014 /* 16 */ "d-mmm",
1015 /* 17 */ "mmm-yy",
1016 /* 18 */ "h:mm AM/PM",
1017 /* 19 */ "h:mm:ss AM/PM",
1018 /* 20 */ "h:mm",
1019 /* 21 */ "h:mm:ss",
1020 /* 22 */ "m/d/yy h:mm",
1021 /* 23 */ NULL,
1022 /* 24 */ NULL,
1023 /* 25 */ NULL,
1024 /* 26 */ NULL,
1025 /* 27 */ NULL,
1026 /* 28 */ NULL,
1027 /* 29 */ NULL,
1028 /* 30 */ NULL,
1029 /* 31 */ NULL,
1030 /* 32 */ NULL,
1031 /* 33 */ NULL,
1032 /* 34 */ NULL,
1033 /* 35 */ NULL,
1034 /* 36 */ NULL,
1035 /* 37 */ "#,##0 ;(#,##0)",
1036 /* 38 */ "#,##0 ;[Red](#,##0)",
1037 /* 39 */ "#,##0.00;(#,##0.00)",
1038 /* 40 */ "#,##0.00;[Red](#,##0.00)",
1039 /* 41 */ NULL,
1040 /* 42 */ NULL,
1041 /* 43 */ NULL,
1042 /* 44 */ NULL,
1043 /* 45 */ "mm:ss",
1044 /* 46 */ "[h]:mm:ss",
1045 /* 47 */ "mmss.0",
1046 /* 48 */ "##0.0E+0",
1047 /* 49 */ "@"
1050 #if 0
1051 CHT CHS
1052 27 [$-404]e/m/d yyyy"5E74"m"6708"
1053 28 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1054 29 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1055 30 m/d/yy m-d-yy
1056 31 yyyy"5E74"m"6708"d"65E5" yyyy"5E74"m"6708"d"65E5"
1057 32 hh"6642"mm"5206" h"65F6"mm"5206"
1058 33 hh"6642"mm"5206"ss"79D2" h"65F6"mm"5206"ss"79D2"
1059 34 4E0A5348/4E0B5348hh"6642"mm"5206" 4E0A5348/4E0B5348h"65F6"mm"5206"
1060 35 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2" 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2"
1061 36 [$-404]e/m/d yyyy"5E74"m"6708"
1062 50 [$-404]e/m/d yyyy"5E74"m"6708"
1063 51 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1064 52 4E0A5348/4E0B5348hh"6642"mm"5206" yyyy"5E74"m"6708"
1065 53 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2" m"6708"d"65E5"
1066 54 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1067 55 4E0A5348/4E0B5348hh"6642"mm"5206" 4E0A5348/4E0B5348h"65F6"mm"5206"
1068 56 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2" 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2"
1069 57 [$-404]e/m/d yyyy"5E74"m"6708"
1070 58 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1072 JPN KOR
1073 27 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1074 28 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1075 29 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1076 30 m/d/yy mm-dd-yy
1077 31 yyyy"5E74"m"6708"d"65E5" yyyy"B144" mm"C6D4" dd"C77C"
1078 32 h"6642"mm"5206" h"C2DC" mm"BD84"
1079 33 h"6642"mm"5206"ss"79D2" h"C2DC" mm"BD84" ss"CD08"
1080 34 yyyy"5E74"m"6708" yyyy-mm-dd
1081 35 m"6708"d"65E5" yyyy-mm-dd
1082 36 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1083 50 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1084 51 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1085 52 yyyy"5E74"m"6708" yyyy-mm-dd
1086 53 m"6708"d"65E5" yyyy-mm-dd
1087 54 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1088 55 yyyy"5E74"m"6708" yyyy-mm-dd
1089 56 m"6708"d"65E5" yyyy-mm-dd
1090 57 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1091 58 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1094 59 "t0"
1095 60 "t0.00"
1096 61 "t#,##0"
1097 62 "t#,##0.00"
1098 67 "t0%"
1099 68 "t0.00%"
1100 69 "t# ?/?"
1101 70 "t# ?""?/?""?" /* silly trick to avoid using a trigraph */
1102 71 0E27/0E14/0E1B0E1B0E1B0E1B
1103 72 0E27-0E140E140E14-0E1B0E1B
1104 73 0E27-0E140E140E14
1105 74 0E140E140E14-0E1B0E1B
1106 75 0E0A:0E190E19
1107 76 0E0A:0E190E19:0E170E17
1108 77 0E27/0E14/0E1B0E1B0E1B0E1B 0E0A:0E190E19
1109 78 0E190E19:0E170E17
1110 79 [0E0A]:0E190E19:0E170E17
1111 80 0E190E19:0E170E17.0
1112 81 d/m/bb
1113 #endif
1115 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1116 GOFormat *res = g_hash_table_lookup (state->num_fmts, id);
1117 char *end;
1118 long i;
1120 if (NULL != res)
1121 return res;
1123 /* builtins */
1124 i = strtol (id, &end, 10);
1125 if (end != id && *end == '\0' &&
1126 i >= 0 && i < (int) G_N_ELEMENTS (std_builtins) &&
1127 std_builtins[i] != NULL) {
1128 res = go_format_new_from_XL (std_builtins[i]);
1129 g_hash_table_replace (state->num_fmts, g_strdup (id), res);
1130 } else
1131 xlsx_warning (xin, _("Undefined number format id '%s'"), id);
1132 return res;
1135 static GnmExprTop const *
1136 xlsx_parse_expr (GsfXMLIn *xin, xmlChar const *expr_str,
1137 GnmParsePos const *pp)
1139 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1140 GnmParseError err;
1141 GnmExprTop const *texpr;
1143 /* Odd, some time IF and CHOOSE show up with leading spaces ??
1144 * = IF(....
1145 * = CHOOSE(...
1146 * I wonder if it is related to some of the funky old
1147 * optimizations in * xls ? */
1148 while (' ' == *expr_str)
1149 expr_str++;
1151 texpr = gnm_expr_parse_str (expr_str, pp,
1152 GNM_EXPR_PARSE_DEFAULT, state->convs,
1153 parse_error_init (&err));
1154 if (NULL == texpr)
1155 xlsx_warning (xin, "At %s: '%s' %s",
1156 parsepos_as_string (pp),
1157 expr_str, err.err->message);
1158 parse_error_free (&err);
1160 return texpr;
1163 /* Returns: a GSList of GnmRange in _reverse_ order
1164 * caller frees the list and the content */
1165 static GSList *
1166 xlsx_parse_sqref (GsfXMLIn *xin, xmlChar const *refs)
1168 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1169 GnmRange r;
1170 xmlChar const *tmp;
1171 GSList *res = NULL;
1173 while (NULL != refs && *refs) {
1174 if (NULL == (tmp = cellpos_parse (refs, gnm_sheet_get_size (state->sheet), &r.start, FALSE))) {
1175 xlsx_warning (xin, "unable to parse reference list '%s'", refs);
1176 return res;
1179 refs = tmp;
1180 if (*refs == '\0' || *refs == ' ')
1181 r.end = r.start;
1182 else if (*refs != ':' ||
1183 NULL == (tmp = cellpos_parse (refs + 1, gnm_sheet_get_size (state->sheet), &r.end, FALSE))) {
1184 xlsx_warning (xin, "unable to parse reference list '%s'", refs);
1185 return res;
1188 range_normalize (&r); /* be anal */
1189 res = g_slist_prepend (res, gnm_range_dup (&r));
1191 for (refs = tmp ; *refs == ' ' ; refs++ ) ;
1194 return res;
1197 /***********************************************************************/
1199 #include "xlsx-read-pivot.c"
1201 /***********************************************************************/
1203 static void xlsx_ext_begin (GsfXMLIn *xin, xmlChar const **attrs);
1204 static void xlsx_ext_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob);
1206 #include "xlsx-read-drawing.c"
1208 /***********************************************************************/
1210 /* RGBMAX, HLSMAX must each fit in a byte. */
1211 /* HLSMAX BEST IF DIVISIBLE BY 6 */
1212 #define HLSMAX 240 /* H,L, and S vary over 0-HLSMAX */
1213 #define RGBMAX 255 /* R,G, and B vary over 0-RGBMAX */
1215 /* Hue is undefined if Saturation is 0 (grey-scale) */
1216 /* This value determines where the Hue scrollbar is */
1217 /* initially set for achromatic colors */
1218 #define UNDEFINED (HLSMAX*2/3)
1220 /* utility routine for HLStoRGB */
1221 static int
1222 hue_to_color (int m1, int m2, int h)
1224 if (h < 0)
1225 h += HLSMAX;
1226 if (h > HLSMAX)
1227 h -= HLSMAX;
1229 /* return r,g, or b value from this tridrant */
1230 if (h < (HLSMAX/6))
1231 return m1 + (((m2 - m1)*h + (HLSMAX/12))/(HLSMAX/6));
1232 if (h < (HLSMAX/2))
1233 return m2;
1234 if (h < ((HLSMAX*2)/3))
1235 return m1 + (((m2 - m1)*(((HLSMAX*2)/3)-h)+(HLSMAX/12))/(HLSMAX/6));
1237 return m1;
1240 static GOColor
1241 apply_tint (GOColor orig, double tint)
1243 int r = GO_COLOR_UINT_R (orig);
1244 int g = GO_COLOR_UINT_G (orig);
1245 int b = GO_COLOR_UINT_B (orig);
1246 int a = GO_COLOR_UINT_A (orig);
1247 int maxC = b, minC = b, delta, sum, h = 0, l, s, m1, m2;
1249 if (fabs (tint) < .005)
1250 return orig;
1252 maxC = MAX (MAX (r,g),b);
1253 minC = MIN (MIN (r,g),b);
1254 l = (((maxC + minC)*HLSMAX) + RGBMAX)/(2*RGBMAX);
1256 delta = maxC - minC;
1257 sum = maxC + minC;
1258 if (delta != 0) {
1259 if (l <= (HLSMAX/2))
1260 s = ( (delta*HLSMAX) + (sum/2) ) / sum;
1261 else
1262 s = ( (delta*HLSMAX) + ((2*RGBMAX - sum)/2) ) / (2*RGBMAX - sum);
1264 if (r == maxC)
1265 h = ((g - b) * HLSMAX) / (6 * delta);
1266 else if (g == maxC)
1267 h = ( HLSMAX/3) + ((b - r) * HLSMAX) / (6 * delta);
1268 else if (b == maxC)
1269 h = (2*HLSMAX/3) + ((r - g) * HLSMAX) / (6 * delta);
1271 if (h < 0)
1272 h += HLSMAX;
1273 else if (h >= HLSMAX)
1274 h -= HLSMAX;
1275 } else {
1276 h = 0;
1277 s = 0;
1280 if (tint < 0.)
1281 l = l * (1. + tint);
1282 else
1283 l = l * (1. - tint) + (HLSMAX - HLSMAX * (1.0 - tint));
1285 if (s == 0) { /* achromatic case */
1286 r = (l * RGBMAX) / HLSMAX;
1287 return GO_COLOR_FROM_RGBA (r, r, r, a);
1290 if (l <= (HLSMAX/2))
1291 m2 = (l*(HLSMAX + s) + (HLSMAX/2))/HLSMAX;
1292 else
1293 m2 = l + s - ((l*s) + (HLSMAX/2))/HLSMAX;
1294 m1 = 2*l - m2;
1296 r = (hue_to_color (m1, m2, h + (HLSMAX/3))*RGBMAX + (HLSMAX/2)) / HLSMAX;
1297 g = (hue_to_color (m1, m2, h )*RGBMAX + (HLSMAX/2)) / HLSMAX;
1298 b = (hue_to_color (m1, m2, h - (HLSMAX/3))*RGBMAX + (HLSMAX/2)) / HLSMAX;
1300 return GO_COLOR_FROM_RGBA (r,g,b,a);
1303 static GnmColor *
1304 elem_color (GsfXMLIn *xin, xmlChar const **attrs, gboolean allow_alpha)
1306 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1307 int indx;
1308 GOColor c = GO_COLOR_BLACK;
1309 gnm_float tint = 0.;
1310 gboolean has_color = FALSE;
1312 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1313 if (0 == strcmp (attrs[0], "rgb")) {
1314 guint a, r, g, b;
1315 if (4 != sscanf (attrs[1], "%02x%02x%02x%02x", &a, &r, &g, &b)) {
1316 xlsx_warning (xin,
1317 _("Invalid color '%s' for attribute rgb"),
1318 attrs[1]);
1319 return NULL;
1321 has_color = TRUE;
1322 c = GO_COLOR_FROM_RGBA (r,g,b,a);
1323 } else if (attr_int (xin, attrs, "indexed", &indx)) {
1324 has_color = TRUE;
1325 c = indexed_color (state, indx);
1326 } else if (attr_int (xin, attrs, "theme", &indx)) {
1327 has_color = TRUE;
1328 c = themed_color (xin, indx);
1329 } else if (attr_float (xin, attrs, "tint", &tint))
1330 tint = CLAMP (tint, -1., 1.);
1333 if (!has_color)
1334 return NULL;
1335 c = apply_tint (c, tint);
1336 if (!allow_alpha)
1337 c |= 0xFF;
1338 return gnm_color_new_go (c);
1341 static GnmStyle *
1342 xlsx_get_style_xf (GsfXMLIn *xin, int xf)
1344 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1345 if (0 <= xf && NULL != state->style_xfs && xf < (int)state->style_xfs->len)
1346 return g_ptr_array_index (state->style_xfs, xf);
1347 xlsx_warning (xin, _("Undefined style record '%d'"), xf);
1348 return NULL;
1350 static GnmStyle *
1351 xlsx_get_xf (GsfXMLIn *xin, int xf)
1353 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1354 if (0 <= xf && NULL != state->xfs && xf < (int)state->xfs->len)
1355 return g_ptr_array_index (state->xfs, xf);
1356 xlsx_warning (xin, _("Undefined style record '%d'"), xf);
1357 return NULL;
1359 static GnmStyle *
1360 xlsx_get_dxf (GsfXMLIn *xin, int dxf)
1362 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1363 if (0 <= dxf && NULL != state->dxfs && dxf < (int)state->dxfs->len)
1364 return g_ptr_array_index (state->dxfs, dxf);
1365 xlsx_warning (xin, _("Undefined partial style record '%d'"), dxf);
1366 return NULL;
1369 /****************************************************************************/
1371 static void
1372 xlsx_cell_val_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1374 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1375 XLSXStr const *entry;
1376 char *end;
1377 long i;
1379 switch (state->pos_type) {
1380 case XLXS_TYPE_NUM :
1381 if (*xin->content->str)
1382 state->val = value_new_float (gnm_strto (xin->content->str, &end));
1383 break;
1384 case XLXS_TYPE_SST_STR :
1385 i = strtol (xin->content->str, &end, 10);
1386 if (end != xin->content->str && *end == '\0' &&
1387 0 <= i && i < (int)state->sst->len) {
1388 entry = &g_array_index (state->sst, XLSXStr, i);
1389 go_string_ref (entry->str);
1390 state->val = value_new_string_str (entry->str);
1391 if (NULL != entry->markup)
1392 value_set_fmt (state->val, entry->markup);
1393 } else {
1394 xlsx_warning (xin, _("Invalid sst ref '%s'"), xin->content->str);
1396 break;
1397 case XLXS_TYPE_BOOL :
1398 if (*xin->content->str)
1399 state->val = value_new_bool (*xin->content->str != '0');
1400 break;
1401 case XLXS_TYPE_ERR :
1402 if (*xin->content->str)
1403 state->val = value_new_error (NULL, xin->content->str);
1404 break;
1406 case XLXS_TYPE_STR2 : /* What is this ? */
1407 case XLXS_TYPE_INLINE_STR :
1408 state->val = value_new_string (xin->content->str);
1409 break;
1410 default :
1411 g_warning ("Unknown val type %d", state->pos_type);
1415 static void
1416 xlsx_cell_inline_text_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1418 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1419 go_string_append_gstring (state->r_text, xin->content);
1423 static void
1424 xlsx_cell_inline_begin (GsfXMLIn *xin, xmlChar const **attrs)
1426 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1428 state->r_text = g_string_new ("");
1431 static void
1432 xlsx_cell_inline_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1434 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1436 state->val = value_new_string_nocopy (g_string_free (state->r_text, FALSE));
1437 state->r_text = NULL;
1439 if (state->rich_attrs) {
1440 GOFormat *fmt = go_format_new_markup (state->rich_attrs, FALSE);
1441 state->rich_attrs = NULL;
1442 value_set_fmt (state->val, fmt);
1443 go_format_unref (fmt);
1448 static void
1449 xlsx_cell_expr_begin (GsfXMLIn *xin, xmlChar const **attrs)
1451 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1452 gboolean has_range = FALSE, is_array = FALSE, is_shared = FALSE;
1453 GnmRange range;
1454 xmlChar const *shared_id = NULL;
1456 /* See https://bugzilla.gnome.org/show_bug.cgi?id=642850 */
1457 /* for some of the issues surrounding shared formulas. */
1459 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1460 if (0 == strcmp (attrs[0], "t")) {
1461 if (0 == strcmp (attrs[1], "array"))
1462 is_array = TRUE;
1463 else if (0 == strcmp (attrs[1], "shared"))
1464 is_shared = TRUE;
1465 } else if (0 == strcmp (attrs[0], "si"))
1466 shared_id = attrs[1];
1467 else if (attr_range (xin, attrs, "ref", &range))
1468 has_range = TRUE;
1470 state->shared_id = NULL;
1471 if (is_shared && NULL != shared_id) {
1472 if (!has_range)
1473 state->texpr = g_hash_table_lookup (state->shared_exprs, shared_id);
1474 if (NULL != state->texpr)
1475 gnm_expr_top_ref (state->texpr);
1476 else
1477 state->shared_id = g_strdup (shared_id);
1478 } else
1479 state->texpr = NULL;
1481 /* if the shared expr is already parsed expression do not even collect content */
1482 ((GsfXMLInNode *)(xin->node))->has_content =
1483 (NULL != state->texpr) ? GSF_XML_NO_CONTENT : GSF_XML_CONTENT;
1485 if (is_array && has_range)
1486 state->array = range;
1489 static void
1490 xlsx_cell_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1492 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1493 GnmParsePos pp;
1495 if (NULL == state->texpr) {
1496 parse_pos_init (&pp, NULL, state->sheet,
1497 state->pos.col, state->pos.row);
1498 state->texpr = xlsx_parse_expr (xin, xin->content->str, &pp);
1499 if (NULL != state->texpr &&
1500 NULL != state->shared_id) {
1501 gnm_expr_top_ref (state->texpr);
1502 g_hash_table_replace (state->shared_exprs,
1503 state->shared_id, (gpointer)state->texpr);
1504 state->shared_id = NULL;
1507 g_free (state->shared_id);
1508 state->shared_id = NULL;
1511 static void
1512 xlsx_cell_begin (GsfXMLIn *xin, xmlChar const **attrs)
1514 static EnumVal const types[] = {
1515 { "n", XLXS_TYPE_NUM },
1516 { "s", XLXS_TYPE_SST_STR },
1517 { "str", XLXS_TYPE_STR2 },
1518 { "b", XLXS_TYPE_BOOL },
1519 { "inlineStr", XLXS_TYPE_INLINE_STR },
1520 { "e", XLXS_TYPE_ERR },
1521 { NULL, 0 }
1523 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1524 int tmp;
1525 GnmStyle *style = NULL;
1527 state->pos.col = state->pos.row = -1;
1528 state->pos_type = XLXS_TYPE_NUM; /* the default */
1529 state->val = NULL;
1530 state->texpr = NULL;
1531 range_init (&state->array, -1, -1, -1, -1); /* invalid */
1533 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1534 if (attr_pos (xin, attrs, "r", &state->pos)) ;
1535 else if (attr_enum (xin, attrs, "t", types, &tmp))
1536 state->pos_type = tmp;
1537 else if (attr_int (xin, attrs, "s", &tmp))
1538 style = xlsx_get_xf (xin, tmp);
1540 if (NULL != style) {
1541 gnm_style_ref (style);
1542 /* There may already be a row style set!*/
1543 sheet_style_apply_pos (state->sheet,
1544 state->pos.col, state->pos.row, style);
1547 static void
1548 xlsx_cell_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1550 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1551 GnmCell *cell;
1553 if (state->texpr == NULL && state->val == NULL) {
1554 /* A cell with only style. */
1555 return;
1558 cell = sheet_cell_fetch (state->sheet, state->pos.col, state->pos.row);
1560 if (NULL == cell) {
1561 xlsx_warning (xin, _("Invalid cell %s"),
1562 cellpos_as_string (&state->pos));
1563 value_release (state->val);
1564 if (NULL != state->texpr)
1565 gnm_expr_top_unref (state->texpr);
1566 } else if (NULL != state->texpr) {
1567 if (state->array.start.col >= 0) {
1568 gnm_cell_set_array (state->sheet,
1569 &state->array,
1570 state->texpr);
1571 gnm_expr_top_unref (state->texpr);
1572 if (NULL != state->val)
1573 gnm_cell_assign_value (cell, state->val);
1574 } else if (NULL != state->val) {
1575 gnm_cell_set_expr_and_value (cell,
1576 state->texpr, state->val, TRUE);
1577 gnm_expr_top_unref (state->texpr);
1578 } else {
1579 gnm_cell_set_expr (cell, state->texpr);
1580 gnm_expr_top_unref (state->texpr);
1582 } else if (NULL != state->val)
1583 gnm_cell_assign_value (cell, state->val);
1585 state->texpr = NULL;
1586 state->val = NULL;
1589 static void
1590 xlsx_CT_Row (GsfXMLIn *xin, xmlChar const **attrs)
1592 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1593 int row = -1, xf_index;
1594 gnm_float h = -1.;
1595 int cust_fmt = FALSE, cust_height = FALSE, collapsed = FALSE;
1596 int hidden = -1;
1597 int outline = -1;
1598 GnmStyle *style = NULL;
1600 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1601 if (attr_int (xin, attrs, "r", &row)) ;
1602 else if (attr_float (xin, attrs, "ht", &h)) ;
1603 else if (attr_bool (xin, attrs, "customFormat", &cust_fmt)) ;
1604 else if (attr_bool (xin, attrs, "customHeight", &cust_height)) ;
1605 else if (attr_int (xin, attrs, "s", &xf_index))
1606 style = xlsx_get_xf (xin, xf_index);
1607 else if (attr_int (xin, attrs, "outlineLevel", &outline)) ;
1608 else if (attr_bool (xin, attrs, "hidden", &hidden)) ;
1609 else if (attr_bool (xin, attrs, "collapsed", &collapsed)) ;
1611 if (row > 0) {
1612 row--;
1613 if (h >= 0.)
1614 sheet_row_set_size_pts (state->sheet, row, h, cust_height);
1615 if (hidden > 0)
1616 colrow_set_visibility (state->sheet, FALSE, FALSE, row, row);
1617 if (outline >= 0)
1618 colrow_set_outline (sheet_row_fetch (state->sheet, row),
1619 outline, collapsed);
1621 if (NULL != style && cust_fmt) {
1622 GnmRange r;
1623 r.start.row = r.end.row = row;
1624 r.start.col = 0;
1625 r.end.col = gnm_sheet_get_max_cols (state->sheet) - 1;
1626 gnm_style_ref (style);
1627 sheet_style_set_range (state->sheet, &r, style);
1631 maybe_update_progress (xin);
1634 static void
1635 xlsx_CT_RowsCols_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1637 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1639 if (!state->pending_rowcol_style)
1640 return;
1642 sheet_style_set_range (state->sheet,
1643 &state->pending_rowcol_range,
1644 state->pending_rowcol_style);
1646 state->pending_rowcol_style = NULL;
1648 maybe_update_progress (xin);
1651 static void
1652 xlsx_CT_Col (GsfXMLIn *xin, xmlChar const **attrs)
1654 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1655 int first = -1, last = -1, xf_index;
1656 double width = -1.;
1657 gboolean cust_width = FALSE, best_fit = FALSE, collapsed = FALSE;
1658 int i, hidden = -1;
1659 int outline = -1;
1660 GnmStyle *style = NULL;
1662 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1663 if (attr_int (xin, attrs, "min", &first)) ;
1664 else if (attr_int (xin, attrs, "max", &last)) ;
1665 else if (attr_float (xin, attrs, "width", &width))
1666 /* FIXME FIXME FIXME arbitrary map from 130 pixels to
1667 * the value stored for a column with 130 pixel width*/
1668 width *= (130. / 18.5703125) * (72./96.);
1669 else if (attr_bool (xin, attrs, "customWidth", &cust_width)) ;
1670 else if (attr_bool (xin, attrs, "bestFit", &best_fit)) ;
1671 else if (attr_int (xin, attrs, "style", &xf_index))
1672 style = xlsx_get_xf (xin, xf_index);
1673 else if (attr_int (xin, attrs, "outlineLevel", &outline)) ;
1674 else if (attr_bool (xin, attrs, "hidden", &hidden)) ;
1675 else if (attr_bool (xin, attrs, "collapsed", &collapsed)) ;
1677 if (first < 0) {
1678 if (last < 0) {
1679 xlsx_warning (xin, _("Ignoring column information that does not specify first or last."));
1680 return;
1682 first = --last;
1683 } else if (last < 0)
1684 last = --first;
1685 else {
1686 first--;
1687 last--;
1690 first = CLAMP (first, 0, gnm_sheet_get_last_col (state->sheet));
1691 last = CLAMP (last, 0, gnm_sheet_get_last_col (state->sheet));
1693 for (i = first; i <= last; i++) {
1694 if (width > 4)
1695 sheet_col_set_size_pts (state->sheet, i, width,
1696 cust_width && !best_fit);
1697 if (outline > 0)
1698 colrow_set_outline (sheet_col_fetch (state->sheet, i),
1699 outline, collapsed);
1701 if (NULL != style) {
1702 GnmRange r;
1703 range_init_cols (&r, state->sheet, first, last);
1706 * Sometimes we see a lot of columns with the same style.
1707 * We delay applying the style because applying column
1708 * by column leads to style fragmentation. #622365
1711 if (style != state->pending_rowcol_style ||
1712 state->pending_rowcol_range.start.row != r.start.row ||
1713 state->pending_rowcol_range.end.row != r.end.row ||
1714 state->pending_rowcol_range.end.col + 1 != r.start.col)
1715 xlsx_CT_RowsCols_end (xin, NULL);
1717 if (state->pending_rowcol_style)
1718 state->pending_rowcol_range.end.col = r.end.col;
1719 else {
1720 gnm_style_ref (style);
1721 state->pending_rowcol_style = style;
1722 state->pending_rowcol_range = r;
1725 if (hidden > 0)
1726 colrow_set_visibility (state->sheet, TRUE, FALSE, first, last);
1729 static void
1730 xlsx_CT_SheetPr (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
1732 #if 0
1733 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1734 <xsd:attribute name="syncHorizontal" type="xsd:boolean" use="optional" default="false">
1735 <xsd:attribute name="syncVertical" type="xsd:boolean" use="optional" default="false">
1736 <xsd:attribute name="syncRef" type="ST_Ref" use="optional">
1737 <xsd:attribute name="transitionEvaluation" type="xsd:boolean" use="optional" default="false">
1738 <xsd:attribute name="transitionEntry" type="xsd:boolean" use="optional" default="false">
1739 <xsd:attribute name="published" type="xsd:boolean" use="optional" default="true">
1740 <xsd:attribute name="codeName" type="xsd:string" use="optional">
1741 <xsd:attribute name="filterMode" type="xsd:boolean" use="optional" default="false">
1742 <xsd:attribute name="enableFormatConditionsCalculation" type="xsd:boolean" use="optional" default="true">
1743 #endif
1746 static void
1747 xlsx_sheet_tabcolor (GsfXMLIn *xin, xmlChar const **attrs)
1749 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1750 GnmColor *text_color, *color = elem_color (xin, attrs, TRUE);
1751 if (NULL != color) {
1752 int contrast =
1753 GO_COLOR_UINT_R (color->go_color) +
1754 GO_COLOR_UINT_G (color->go_color) +
1755 GO_COLOR_UINT_B (color->go_color);
1756 if (contrast >= 0x180)
1757 text_color = style_color_black ();
1758 else
1759 text_color = style_color_white ();
1760 g_object_set (state->sheet,
1761 "tab-foreground", text_color,
1762 "tab-background", color,
1763 NULL);
1764 style_color_unref (text_color);
1765 style_color_unref (color);
1769 static void
1770 xlsx_sheet_page_setup (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
1772 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1773 GnmPrintInformation *pi = state->sheet->print_info;
1774 gboolean tmp;
1776 if (pi->page_setup == NULL)
1777 gnm_print_info_load_defaults (pi);
1779 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1780 if (attr_bool (xin, attrs, "fitToPage", &tmp))
1781 pi->scaling.type = tmp ? PRINT_SCALE_FIT_PAGES : PRINT_SCALE_PERCENTAGE;
1784 static void
1785 xlsx_CT_SheetFormatPr (GsfXMLIn *xin, xmlChar const **attrs)
1787 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1788 gnm_float h;
1789 int i;
1791 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1792 if (attr_float (xin, attrs, "defaultRowHeight", &h))
1793 sheet_row_set_default_size_pts (state->sheet, h);
1794 else if (attr_int (xin, attrs, "outlineLevelRow", &i)) {
1795 if (i > 0)
1796 sheet_colrow_gutter (state->sheet, FALSE, i);
1797 } else if (attr_int (xin, attrs, "outlineLevelCol", &i)) {
1798 if (i > 0)
1799 sheet_colrow_gutter (state->sheet, TRUE, i);
1803 static GtkPaperSize *
1804 xlsx_paper_size (gdouble width, gdouble height, GtkUnit unit, int code)
1806 GtkPaperSize *size;
1807 gchar *name;
1808 gchar *display_name;
1810 if (code == 0) {
1811 name = g_strdup_printf ("xlsx_%ix%i", (int)width, (int)height);
1812 display_name = g_strdup_printf (_("Paper from XLSX file: %ipt\xE2\xA8\x89%ipt"),
1813 (int)width, (int)height);
1814 } else {
1815 name = g_strdup_printf ("xlsx_%i", code);
1816 display_name = g_strdup_printf (_("Paper from XLSX file, #%i"), code);
1818 size = gtk_paper_size_new_custom (name, display_name, width, height, unit);
1819 g_free (name);
1820 g_free (display_name);
1821 return size;
1824 static gboolean
1825 xlsx_set_paper_from_code (GnmPrintInformation *pi, int code)
1827 XLSXPaperDefs paper[] =
1828 {{ 0 , 0 , 0 , GTK_UNIT_MM , NULL },
1829 { 1 , 8.5 , 11 , GTK_UNIT_INCH , GTK_PAPER_NAME_LETTER },
1830 { 2 , 8.5 , 11 , GTK_UNIT_INCH , GTK_PAPER_NAME_LETTER },
1831 { 3 , 11 , 17 , GTK_UNIT_INCH , "na_ledger_11x17in" },
1832 { 4 , 17 , 11 , GTK_UNIT_INCH , NULL },
1833 { 5 , 8.5 , 14 , GTK_UNIT_INCH , GTK_PAPER_NAME_LEGAL },
1834 { 6 , 5.5 , 8.5 , GTK_UNIT_INCH , "na_invoice_5.5x8.5in" },
1835 { 7 , 7.25 , 10.5 , GTK_UNIT_INCH , GTK_PAPER_NAME_EXECUTIVE },
1836 { 8 , 297 , 420 , GTK_UNIT_MM , GTK_PAPER_NAME_A3 },
1837 { 9 , 210 , 297 , GTK_UNIT_MM , GTK_PAPER_NAME_A4 },
1838 { 10 , 210 , 297 , GTK_UNIT_MM , GTK_PAPER_NAME_A4 },
1839 { 11 , 148 , 210 , GTK_UNIT_MM , GTK_PAPER_NAME_A5 },
1840 { 12 , 250 , 353 , GTK_UNIT_MM , "iso_b4_250x353mm" },
1841 { 13 , 176 , 250 , GTK_UNIT_MM , GTK_PAPER_NAME_B5 },
1842 { 14 , 8.5 , 13 , GTK_UNIT_INCH , "na_foolscap_8.5x13in" },
1843 { 15 , 215 , 275 , GTK_UNIT_MM , NULL },
1844 { 16 , 10 , 14 , GTK_UNIT_INCH , "na_10x14_10x14in" },
1845 { 17 , 11 , 17 , GTK_UNIT_INCH , "na_ledger_11x17in" },
1846 { 18 , 8.5 , 11 , GTK_UNIT_INCH , GTK_PAPER_NAME_LETTER },
1847 { 19 , 3.875 , 8.875 , GTK_UNIT_INCH , "na_number-9_3.875x8.875in" },
1848 { 20 , 4.125 , 9.5 , GTK_UNIT_INCH , "na_number-10_4.125x9.5in" },
1849 { 21 , 4.5 , 10.375 , GTK_UNIT_INCH , "na_number-11_4.5x10.375in" },
1850 { 22 , 4.75 , 11 , GTK_UNIT_INCH , "na_number-12_4.75x11in" },
1851 { 23 , 5 , 11.5 , GTK_UNIT_INCH , "na_number-14_5x11.5in" },
1852 { 24 , 17 , 22 , GTK_UNIT_INCH , "na_c_17x22in" },
1853 { 25 , 22 , 34 , GTK_UNIT_INCH , "na_d_22x34in" },
1854 { 26 , 34 , 44 , GTK_UNIT_INCH , "na_e_34x44in" },
1855 { 27 , 110 , 220 , GTK_UNIT_MM , "iso_dl_110x220mm" },
1856 { 28 , 162 , 229 , GTK_UNIT_MM , "iso_c5_162x229mm" },
1857 { 29 , 324 , 458 , GTK_UNIT_MM , "iso_c3_324x458mm" },
1858 { 30 , 229 , 324 , GTK_UNIT_MM , "iso_c4_229x324mm" },
1859 { 31 , 114 , 162 , GTK_UNIT_MM , "iso_c6_114x162mm" },
1860 { 32 , 114 , 229 , GTK_UNIT_MM , "iso_c6c5_114x229mm" },
1861 { 33 , 250 , 353 , GTK_UNIT_MM , "iso_b4_250x353mm" },
1862 { 34 , 176 , 250 , GTK_UNIT_MM , GTK_PAPER_NAME_B5 },
1863 { 35 , 176 , 125 , GTK_UNIT_MM , NULL },
1864 { 36 , 110 , 230 , GTK_UNIT_MM , "om_italian_110x230mm" },
1865 { 37 , 3.875 , 7.5 , GTK_UNIT_INCH , "na_monarch_3.875x7.5in" },
1866 { 38 , 3.625 , 6.5 , GTK_UNIT_INCH , "na_personal_3.625x6.5in" },
1867 { 39 , 14.875 , 11 , GTK_UNIT_INCH , NULL },
1868 { 40 , 8.5 , 12 , GTK_UNIT_INCH , "na_fanfold-eur_8.5x12in" },
1869 { 41 , 8.5 , 13 , GTK_UNIT_INCH , "na_foolscap_8.5x13in" },
1870 { 42 , 250 , 353 , GTK_UNIT_MM , "iso_b4_250x353mm" },
1871 { 43 , 200 , 148 , GTK_UNIT_MM , NULL },
1872 { 44 , 9 , 11 , GTK_UNIT_INCH , "na_9x11_9x11in" },
1873 { 45 , 10 , 11 , GTK_UNIT_INCH , "na_10x11_10x11in" },
1874 { 46 , 15 , 11 , GTK_UNIT_INCH , NULL },
1875 { 47 , 220 , 220 , GTK_UNIT_MM , "om_invite_220x220mm" },
1876 { 48 , 0 , 0 , GTK_UNIT_MM , NULL },
1877 { 49 , 0 , 0 , GTK_UNIT_MM , NULL },
1878 { 50 , 9.275 , 12 , GTK_UNIT_INCH , NULL },
1879 { 51 , 9.275 , 15 , GTK_UNIT_INCH , NULL },
1880 { 52 , 11.69 , 18 , GTK_UNIT_INCH , NULL },
1881 { 53 , 236 , 322 , GTK_UNIT_MM , "iso_a4-extra_235.5x322.3" },
1882 { 54 , 8.275 , 11 , GTK_UNIT_INCH , NULL },
1883 { 55 , 210 , 297 , GTK_UNIT_MM , GTK_PAPER_NAME_A4 },
1884 { 56 , 9.275 , 12 , GTK_UNIT_INCH , NULL },
1885 { 57 , 227 , 356 , GTK_UNIT_MM , NULL },
1886 { 58 , 305 , 487 , GTK_UNIT_MM , NULL },
1887 { 59 , 8.5 , 12.69 , GTK_UNIT_INCH , "na_letter-plus_8.5x12.69in" },
1888 { 60 , 210 , 330 , GTK_UNIT_MM , "om_folio_210x330mm" },
1889 { 61 , 148 , 210 , GTK_UNIT_MM , GTK_PAPER_NAME_A5 },
1890 { 62 , 182 , 257 , GTK_UNIT_MM , "jis_b5_182x257mm" },
1891 { 63 , 322 , 445 , GTK_UNIT_MM , "iso_a3-extra_322x445mm" },
1892 { 64 , 174 , 235 , GTK_UNIT_MM , "iso_a5-extra_174x235mm" },
1893 { 65 , 201 , 276 , GTK_UNIT_MM , "iso_b5-extra_201x276mm" },
1894 { 66 , 420 , 594 , GTK_UNIT_MM , "iso_a2_420x594mm" },
1895 { 67 , 297 , 420 , GTK_UNIT_MM , GTK_PAPER_NAME_A3 },
1896 { 68 , 322 , 445 , GTK_UNIT_MM , "iso_a3-extra_322x445mm" },
1897 { 69 , 200 , 148 , GTK_UNIT_MM , NULL },
1898 { 70 , 105 , 148 , GTK_UNIT_MM , "iso_a6_105x148mm" },
1899 { 71 , 240 , 332 , GTK_UNIT_MM , "jpn_kaku2_240x332mm" },
1900 { 72 , 216 , 277 , GTK_UNIT_MM , NULL },
1901 { 73 , 120 , 235 , GTK_UNIT_MM , "jpn_chou3_120x235mm" },
1902 { 74 , 90 , 205 , GTK_UNIT_MM , "jpn_chou4_90x205mm" },
1903 { 75 , 11 , 8.5 , GTK_UNIT_INCH , NULL },
1904 { 76 , 420 , 297 , GTK_UNIT_MM , NULL },
1905 { 77 , 297 , 210 , GTK_UNIT_MM , NULL },
1906 { 78 , 210 , 148 , GTK_UNIT_MM , NULL },
1907 { 79 , 364 , 257 , GTK_UNIT_MM , NULL },
1908 { 80 , 257 , 182 , GTK_UNIT_MM , NULL },
1909 { 81 , 148 , 100 , GTK_UNIT_MM , NULL },
1910 { 82 , 148 , 200 , GTK_UNIT_MM , "jpn_oufuku_148x200mm" },
1911 { 83 , 148 , 105 , GTK_UNIT_MM , NULL },
1912 { 84 , 332 , 240 , GTK_UNIT_MM , NULL },
1913 { 85 , 277 , 216 , GTK_UNIT_MM , NULL },
1914 { 86 , 235 , 120 , GTK_UNIT_MM , NULL },
1915 { 87 , 205 , 90 , GTK_UNIT_MM , NULL },
1916 { 88 , 128 , 182 , GTK_UNIT_MM , "jis_b6_128x182mm" },
1917 { 89 , 182 , 128 , GTK_UNIT_MM , NULL },
1918 { 90 , 12 , 11 , GTK_UNIT_INCH , NULL },
1919 { 91 , 235 , 105 , GTK_UNIT_MM , NULL },
1920 { 92 , 105 , 235 , GTK_UNIT_MM , "jpn_you4_105x235mm" },
1921 { 93 , 146 , 215 , GTK_UNIT_MM , "prc_16k_146x215mm" },
1922 { 94 , 97 , 151 , GTK_UNIT_MM , "prc_32k_97x151mm" },
1923 { 95 , 97 , 151 , GTK_UNIT_MM , "prc_32k_97x151mm" },
1924 { 96 , 102 , 165 , GTK_UNIT_MM , "prc_1_102x165mm" },
1925 { 97 , 102 , 176 , GTK_UNIT_MM , "prc_2_102x176mm" },
1926 { 98 , 125 , 176 , GTK_UNIT_MM , "prc_3_125x176mm" },
1927 { 99 , 110 , 208 , GTK_UNIT_MM , "prc_4_110x208mm" },
1928 { 100 , 110 , 220 , GTK_UNIT_MM , "prc_5_110x220mm" },
1929 { 101 , 120 , 230 , GTK_UNIT_MM , "prc_6_120x230mm" },
1930 { 102 , 160 , 230 , GTK_UNIT_MM , "prc_7_160x230mm" },
1931 { 103 , 120 , 309 , GTK_UNIT_MM , "prc_8_120x309mm" },
1932 { 104 , 229 , 324 , GTK_UNIT_MM , "iso_c4_229x324mm" },
1933 { 105 , 324 , 458 , GTK_UNIT_MM , "prc_10_324x458mm" },
1934 { 106 , 215 , 146 , GTK_UNIT_MM , NULL },
1935 { 107 , 151 , 97 , GTK_UNIT_MM , NULL },
1936 { 108 , 151 , 97 , GTK_UNIT_MM , NULL },
1937 { 109 , 165 , 102 , GTK_UNIT_MM , NULL },
1938 { 110 , 176 , 102 , GTK_UNIT_MM , NULL },
1939 { 111 , 176 , 125 , GTK_UNIT_MM , NULL },
1940 { 112 , 208 , 110 , GTK_UNIT_MM , NULL },
1941 { 113 , 220 , 110 , GTK_UNIT_MM , NULL },
1942 { 114 , 230 , 120 , GTK_UNIT_MM , NULL },
1943 { 115 , 230 , 160 , GTK_UNIT_MM , NULL },
1944 { 116 , 309 , 120 , GTK_UNIT_MM , NULL },
1945 { 117 , 324 , 229 , GTK_UNIT_MM , NULL },
1946 { 118 , 458 , 324 , GTK_UNIT_MM , NULL }};
1948 if (code < 1 || ((guint) code) >= G_N_ELEMENTS (paper) || paper[code].code == 0)
1949 return FALSE;
1950 g_return_val_if_fail (paper[code].code == code, FALSE);
1952 if (paper[code].name != NULL) {
1953 GtkPaperSize *ps = gtk_paper_size_new (paper[code].name);
1954 if (ps != NULL) {
1955 gtk_page_setup_set_paper_size (pi->page_setup, ps);
1956 return TRUE;
1959 if (paper[code].width > 0.0 && paper[code].height > 0.0) {
1960 GtkPaperSize *ps = xlsx_paper_size (paper[code].width, paper[code].height, paper[code].unit, code);
1961 if (ps != NULL) {
1962 gtk_page_setup_set_paper_size (pi->page_setup, ps);
1963 return TRUE;
1967 return FALSE;
1970 static void
1971 xlsx_CT_PageSetup (GsfXMLIn *xin, xmlChar const **attrs)
1973 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1974 GnmPrintInformation *pi = state->sheet->print_info;
1975 int orient, paper_code = 0, scale, tmp_int;
1976 gboolean orient_set = FALSE, first_page_number = TRUE, tmp_bool;
1977 gnm_float width = 0., height = 0.;
1978 static EnumVal const orientation_types[] = {
1979 { "default", GTK_PAGE_ORIENTATION_PORTRAIT },
1980 { "portrait", GTK_PAGE_ORIENTATION_PORTRAIT },
1981 { "landscape", GTK_PAGE_ORIENTATION_LANDSCAPE },
1982 { NULL, 0 }
1984 static EnumVal const comment_types[] = {
1985 { "asDisplayed", GNM_PRINT_COMMENTS_IN_PLACE },
1986 { "atEnd", GNM_PRINT_COMMENTS_AT_END },
1987 { "none", GNM_PRINT_COMMENTS_NONE },
1988 { NULL, 0 }
1990 static EnumVal const error_types[] = {
1991 { "blank", GNM_PRINT_ERRORS_AS_BLANK },
1992 { "dash", GNM_PRINT_ERRORS_AS_DASHES },
1993 { "NA", GNM_PRINT_ERRORS_AS_NA },
1994 { "displayed", GNM_PRINT_ERRORS_AS_DISPLAYED },
1995 { NULL, 0 }
1997 static EnumVal const page_order_types[] = {
1998 { "overThenDown", 1 },
1999 { "downThenOver", 0 },
2000 { NULL, 0 }
2003 if (pi->page_setup == NULL)
2004 gnm_print_info_load_defaults (pi);
2006 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2007 if (attr_enum (xin, attrs, "orientation", orientation_types, &orient))
2008 orient_set = TRUE;
2009 else if (attr_enum (xin, attrs, "cellComments", comment_types, &tmp_int))
2010 pi->comment_placement = tmp_int;
2011 else if (attr_enum (xin, attrs, "errors", error_types, &tmp_int))
2012 pi->error_display = tmp_int;
2013 else if (attr_enum (xin, attrs, "pageOrder", page_order_types, &tmp_int))
2014 pi->print_across_then_down = (tmp_int != 0);
2015 else if (attr_int (xin, attrs, "paperSize", &paper_code))
2017 else if (attr_distance (xin, attrs, "paperWidth", &width))
2019 else if (attr_distance (xin, attrs, "paperHeight", &height))
2021 else if (attr_bool (xin, attrs, "blackAndWhite", &tmp_bool))
2022 pi->print_black_and_white = tmp_bool;
2023 else if (attr_int (xin, attrs, "copies", &(pi->n_copies)))
2025 else if (attr_bool (xin, attrs, "draft", &tmp_bool))
2026 pi->print_as_draft = tmp_bool;
2027 else if (attr_int (xin, attrs, "firstPageNumber", &(pi->start_page)))
2029 else if (attr_int (xin, attrs, "fitToHeight", &(pi->scaling.dim.rows)))
2031 else if (attr_int (xin, attrs, "fitToWidth", &(pi->scaling.dim.cols)))
2033 else if (attr_int (xin, attrs, "scale", &scale)) {
2034 pi->scaling.percentage.x = scale;
2035 pi->scaling.percentage.y = scale;
2036 } else if (attr_bool (xin, attrs, "useFirstPageNumber", &first_page_number))
2039 if (!first_page_number)
2040 pi->start_page = -1;
2042 if (!xlsx_set_paper_from_code (pi, paper_code) && width > 0.0 && height > 0.0)
2043 gtk_page_setup_set_paper_size (pi->page_setup,
2044 xlsx_paper_size (width, height, GTK_UNIT_POINTS, 0));
2045 if (orient_set)
2046 print_info_set_paper_orientation (pi, orient);
2049 static void
2050 xlsx_CT_PageMargins (GsfXMLIn *xin, xmlChar const **attrs)
2052 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2053 gnm_float margin;
2054 GnmPrintInformation *pi = state->sheet->print_info;
2056 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2057 if (attr_float (xin, attrs, "left", &margin))
2058 print_info_set_margin_left (pi, GO_IN_TO_PT (margin));
2059 else if (attr_float (xin, attrs, "right", &margin))
2060 print_info_set_margin_right (pi, GO_IN_TO_PT (margin));
2061 else if (attr_float (xin, attrs, "top", &margin))
2062 print_info_set_edge_to_below_header (pi, GO_IN_TO_PT (margin));
2063 else if (attr_float (xin, attrs, "bottom", &margin))
2064 print_info_set_edge_to_above_footer (pi, GO_IN_TO_PT (margin));
2065 else if (attr_float (xin, attrs, "header", &margin))
2066 print_info_set_margin_header (pi, GO_IN_TO_PT (margin));
2067 else if (attr_float (xin, attrs, "footer", &margin))
2068 print_info_set_margin_footer (pi, GO_IN_TO_PT (margin));
2072 static void
2073 xlsx_CT_oddheader_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2075 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2076 GnmPrintInformation *pi = state->sheet->print_info;
2077 xls_header_footer_import (pi->header, xin->content->str);
2080 static void
2081 xlsx_CT_oddfooter_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2083 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2084 GnmPrintInformation *pi = state->sheet->print_info;
2085 xls_header_footer_import (pi->footer, xin->content->str);
2088 static void
2089 xlsx_CT_PageBreak (GsfXMLIn *xin, xmlChar const **attrs)
2091 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2092 GnmPageBreakType type = GNM_PAGE_BREAK_AUTO;
2093 gboolean tmp;
2094 int pos;
2096 if (NULL == state->page_breaks)
2097 return;
2099 pos = 0;
2101 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2102 if (attr_int (xin, attrs, "id", &pos)) ;
2103 else if (attr_bool (xin, attrs, "man", &tmp)) { if (tmp) type = GNM_PAGE_BREAK_MANUAL; }
2104 else if (attr_bool (xin, attrs, "pt", &tmp)) { if (tmp) type = GNM_PAGE_BREAK_DATA_SLICE; }
2105 #if 0 /* Ignored */
2106 else if (attr_int (xin, attrs, "min", &first)) ;
2107 else if (attr_int (xin, attrs, "max", &last)) ;
2108 #endif
2110 gnm_page_breaks_append_break (state->page_breaks, pos, type);
2113 static void
2114 xlsx_CT_PageBreaks_begin (GsfXMLIn *xin, xmlChar const **attrs)
2116 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2117 int count = 0;
2119 g_return_if_fail (state->page_breaks == NULL);
2121 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2122 if (attr_int (xin, attrs, "count", &count)) ;
2123 #if 0 /* Ignored */
2124 else if (attr_int (xin, attrs, "manualBreakCount", &manual_count)) ;
2125 #endif
2127 state->page_breaks = gnm_page_breaks_new (xin->node->user_data.v_int);
2130 static void
2131 xlsx_CT_PageBreaks_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2133 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2135 if (NULL != state->page_breaks) {
2136 print_info_set_breaks (state->sheet->print_info,
2137 state->page_breaks);
2138 state->page_breaks = NULL;
2142 static void
2143 xlsx_CT_DataValidation_begin (GsfXMLIn *xin, xmlChar const **attrs)
2145 static EnumVal const val_styles[] = {
2146 { "stop", GNM_VALIDATION_STYLE_STOP },
2147 { "warning", GNM_VALIDATION_STYLE_WARNING },
2148 { "information", GNM_VALIDATION_STYLE_INFO },
2149 { NULL, 0 }
2151 static EnumVal const val_types[] = {
2152 { "none", GNM_VALIDATION_TYPE_ANY },
2153 { "whole", GNM_VALIDATION_TYPE_AS_INT },
2154 { "decimal", GNM_VALIDATION_TYPE_AS_NUMBER },
2155 { "list", GNM_VALIDATION_TYPE_IN_LIST },
2156 { "date", GNM_VALIDATION_TYPE_AS_DATE },
2157 { "time", GNM_VALIDATION_TYPE_AS_TIME },
2158 { "textLength", GNM_VALIDATION_TYPE_TEXT_LENGTH },
2159 { "custom", GNM_VALIDATION_TYPE_CUSTOM },
2160 { NULL, 0 }
2162 static EnumVal const val_ops[] = {
2163 { "between", GNM_VALIDATION_OP_BETWEEN },
2164 { "notBetween", GNM_VALIDATION_OP_NOT_BETWEEN },
2165 { "equal", GNM_VALIDATION_OP_EQUAL },
2166 { "notEqual", GNM_VALIDATION_OP_NOT_EQUAL },
2167 { "lessThan", GNM_VALIDATION_OP_LT },
2168 { "lessThanOrEqual", GNM_VALIDATION_OP_LTE },
2169 { "greaterThan", GNM_VALIDATION_OP_GT },
2170 { "greaterThanOrEqual", GNM_VALIDATION_OP_GTE },
2171 { NULL, 0 }
2173 #if 0
2174 /* Get docs on this */
2175 "imeMode" default="noControl"
2176 "noControl"
2177 "off"
2178 "on"
2179 "disabled"
2180 "hiragana"
2181 "fullKatakana"
2182 "halfKatakana"
2183 "fullAlpha"
2184 "halfAlpha"
2185 "fullHangul"
2186 "halfHangul"
2187 #endif
2189 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2191 /* defaults */
2192 ValidationStyle val_style = GNM_VALIDATION_STYLE_STOP;
2193 ValidationType val_type = GNM_VALIDATION_TYPE_ANY;
2194 ValidationOp val_op = GNM_VALIDATION_OP_BETWEEN;
2195 gboolean allowBlank = FALSE;
2196 gboolean showDropDown = FALSE;
2197 gboolean showInputMessage = FALSE;
2198 gboolean showErrorMessage = FALSE;
2199 xmlChar const *errorTitle = NULL;
2200 xmlChar const *error = NULL;
2201 xmlChar const *promptTitle = NULL;
2202 xmlChar const *prompt = NULL;
2203 xmlChar const *refs = NULL;
2204 int tmp;
2206 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2207 if (0 == strcmp (attrs[0], "sqref"))
2208 refs = attrs[1];
2209 else if (attr_enum (xin, attrs, "errorStyle", val_styles, &tmp))
2210 val_style = tmp;
2211 else if (attr_enum (xin, attrs, "type", val_types, &tmp))
2212 val_type = tmp;
2213 else if (attr_enum (xin, attrs, "operator", val_ops, &tmp))
2214 val_op = tmp;
2216 else if (attr_bool (xin, attrs, "allowBlank", &allowBlank)) ;
2217 else if (attr_bool (xin, attrs, "showDropDown", &showDropDown)) ;
2218 else if (attr_bool (xin, attrs, "showInputMessage", &showInputMessage)) ;
2219 else if (attr_bool (xin, attrs, "showErrorMessage", &showErrorMessage)) ;
2221 else if (0 == strcmp (attrs[0], "errorTitle"))
2222 errorTitle = attrs[1];
2223 else if (0 == strcmp (attrs[0], "error"))
2224 error = attrs[1];
2225 else if (0 == strcmp (attrs[0], "promptTitle"))
2226 promptTitle = attrs[1];
2227 else if (0 == strcmp (attrs[0], "prompt"))
2228 prompt = attrs[1];
2230 /* order matters, we need the 1st item */
2231 state->validation_regions = g_slist_reverse (
2232 xlsx_parse_sqref (xin, refs));
2234 if (NULL == state->validation_regions)
2235 return;
2237 if (showErrorMessage) {
2238 GnmRange const *r = state->validation_regions->data;
2239 state->pos = r->start;
2240 state->validation = gnm_validation_new
2241 (val_style, val_type, val_op,
2242 state->sheet,
2243 errorTitle, error,
2244 NULL, NULL, allowBlank, showDropDown);
2247 if (showInputMessage && (NULL != promptTitle || NULL != prompt))
2248 state->input_msg = gnm_input_msg_new (prompt, promptTitle);
2251 static void
2252 xlsx_CT_DataValidation_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2254 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2255 GError *err;
2256 GnmStyle *style = NULL;
2257 GSList *ptr;
2259 if (NULL != state->validation &&
2260 NULL != (err = gnm_validation_is_ok (state->validation))) {
2261 xlsx_warning (xin, _("Ignoring invalid data validation because : %s"),
2262 _(err->message));
2263 gnm_validation_unref (state->validation);
2264 state->validation = NULL;
2267 if (NULL != state->validation) {
2268 style = gnm_style_new ();
2269 gnm_style_set_validation (style, state->validation);
2270 state->validation = NULL;
2273 if (NULL != state->input_msg) {
2274 if (NULL == style)
2275 style = gnm_style_new ();
2276 gnm_style_set_input_msg (style, state->input_msg);
2277 state->input_msg = NULL;
2280 for (ptr = state->validation_regions ; ptr != NULL ; ptr = ptr->next) {
2281 if (NULL != style) {
2282 gnm_style_ref (style);
2283 sheet_style_apply_range (state->sheet, ptr->data, style);
2285 g_free (ptr->data);
2287 if (NULL != style)
2288 gnm_style_unref (style);
2289 g_slist_free (state->validation_regions);
2290 state->validation_regions = NULL;
2291 state->pos.col = state->pos.row = -1;
2294 static void
2295 xlsx_validation_expr (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2297 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2298 GnmParsePos pp;
2299 GnmExprTop const *texpr;
2301 if (state->validation == NULL)
2302 return;
2304 /* Sneaky buggers, parse relative to the 1st sqRef */
2305 parse_pos_init (&pp, NULL, state->sheet,
2306 state->pos.col, state->pos.row);
2307 texpr = xlsx_parse_expr (xin, xin->content->str, &pp);
2308 if (NULL != texpr) {
2309 gnm_validation_set_expr (state->validation, texpr,
2310 xin->node->user_data.v_int);
2311 gnm_expr_top_unref (texpr);
2315 static void
2316 xlsx_CT_AutoFilter_begin (GsfXMLIn *xin, xmlChar const **attrs)
2318 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2319 GnmRange r;
2321 g_return_if_fail (state->filter == NULL);
2323 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2324 if (attr_range (xin, attrs, "ref", &r))
2325 state->filter = gnm_filter_new (state->sheet, &r);
2328 static void
2329 xlsx_CT_AutoFilter_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2331 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2332 g_return_if_fail (state->filter != NULL);
2333 state->filter = NULL;
2336 static void
2337 xlsx_CT_FilterColumn_begin (GsfXMLIn *xin, xmlChar const **attrs)
2339 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2340 int id = -1;
2341 gboolean hidden = FALSE;
2342 gboolean show = TRUE;
2344 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2345 if (attr_int (xin, attrs, "colId", &id)) ;
2346 else if (attr_bool (xin, attrs, "hiddenButton", &hidden)) ;
2347 else if (attr_bool (xin, attrs, "showButton", &show)) ;
2349 state->filter_cur_field = id;
2352 static void
2353 xlsx_CT_Filters_begin (GsfXMLIn *xin, xmlChar const **attrs)
2355 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2357 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2358 if (0 == strcmp (attrs[0], "val")) {
2360 state->filter_items = NULL;
2362 static void
2363 xlsx_CT_Filters_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2365 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2366 state->filter_items = NULL;
2368 static void
2369 xlsx_CT_Filter (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2371 #if 0
2372 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2374 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2375 if (0 == strcmp (attrs[0], "val")) {
2377 #endif
2380 static void
2381 xlsx_CT_CustomFilters_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2383 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2385 #if 0
2386 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2387 if (0 == strcmp (attrs[0], "val")) {
2389 #endif
2390 state->filter_items = NULL;
2392 static void
2393 xlsx_CT_CustomFilters_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2395 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2396 state->filter_items = NULL;
2399 static void
2400 xlsx_CT_CustomFilter (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2402 static EnumVal const ops[] = {
2403 { "lessThan", GNM_FILTER_OP_LT },
2404 { "lessThanOrEqual", GNM_FILTER_OP_LTE },
2405 { "equal", GNM_FILTER_OP_EQUAL },
2406 { "notEqual", GNM_FILTER_OP_NOT_EQUAL },
2407 { "greaterThanOrEqual", GNM_FILTER_OP_GTE },
2408 { "greaterThan", GNM_FILTER_OP_GT },
2409 { NULL, 0 }
2411 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2412 int tmp;
2413 GnmFilterOp op = GNM_FILTER_OP_EQUAL;
2414 GnmValue *v = NULL;
2415 GnmFilterCondition *cond;
2416 GODateConventions const *date_conv = workbook_date_conv (state->wb);
2418 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2419 if (0 == strcmp (attrs[0], "val")) {
2420 const char *txt = CXML2C (attrs[1]);
2421 value_release (v);
2422 v = format_match (txt, NULL, date_conv);
2423 if (!v)
2424 v = value_new_string (txt);
2425 } else if (attr_enum (xin, attrs, "operator", ops, &tmp)) {
2426 op = tmp;
2429 cond = gnm_filter_condition_new_single (op, v);
2430 if (cond)
2431 gnm_filter_set_condition (state->filter, state->filter_cur_field,
2432 cond, FALSE);
2435 static void
2436 xlsx_CT_Top10 (GsfXMLIn *xin, xmlChar const **attrs)
2438 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2439 gboolean top = TRUE;
2440 gboolean percent = FALSE;
2441 gnm_float val = -1.;
2442 GnmFilterCondition *cond;
2444 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2445 if (attr_float (xin, attrs, "val", &val)) ;
2446 else if (attr_bool (xin, attrs, "top", &top)) ;
2447 else if (attr_bool (xin, attrs, "percent", &percent)) ;
2449 if (NULL != (cond = gnm_filter_condition_new_bucket (top, !percent, FALSE, val)))
2450 gnm_filter_set_condition (state->filter, state->filter_cur_field,
2451 cond, FALSE);
2454 static void
2455 xlsx_CT_DynamicFilter (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2457 #if 0
2458 static EnumVal const types[] = {
2459 { "null", 0 },
2460 { "aboveAverage", 0 },
2461 { "belowAverage", 0 },
2462 { "tomorrow", 0 },
2463 { "today", 0 },
2464 { "yesterday", 0 },
2465 { "nextWeek", 0 },
2466 { "thisWeek", 0 },
2467 { "lastWeek", 0 },
2468 { "nextMonth", 0 },
2469 { "thisMonth", 0 },
2470 { "lastMonth", 0 },
2471 { "nextQuarter", 0 },
2472 { "thisQuarter", 0 },
2473 { "lastQuarter", 0 },
2474 { "nextYear", 0 },
2475 { "thisYear", 0 },
2476 { "lastYear", 0 },
2477 { "yearToDate", 0 },
2478 { "Q1", 0 },
2479 { "Q2", 0 },
2480 { "Q3", 0 },
2481 { "Q4", 0 },
2482 { "M1", 0 },
2483 { "M2", 0 },
2484 { "M3", 0 },
2485 { "M4", 0 },
2486 { "M5", 0 },
2487 { "M6", 0 },
2488 { "M7", 0 },
2489 { "M8", 0 },
2490 { "M9", 0 },
2491 { "M10", 0 },
2492 { "M11", 0 },
2493 { "M12", 0 },
2494 { NULL, 0 }
2496 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2497 int type = -1;
2499 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2500 if (attr_enum (xin, attrs, "type", types, &type)) ;
2501 #endif
2504 static void
2505 xlsx_CT_MergeCell (GsfXMLIn *xin, xmlChar const **attrs)
2507 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2508 GnmRange r;
2510 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2511 if (attr_range (xin, attrs, "ref", &r))
2512 gnm_sheet_merge_add (state->sheet, &r, FALSE,
2513 GO_CMD_CONTEXT (state->context));
2516 static void
2517 xlsx_CT_SheetProtection (GsfXMLIn *xin, xmlChar const **attrs)
2519 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2520 gboolean sheet = FALSE;
2521 gboolean objects = FALSE;
2522 gboolean scenarios = FALSE;
2523 gboolean formatCells = TRUE;
2524 gboolean formatColumns = TRUE;
2525 gboolean formatRows = TRUE;
2526 gboolean insertColumns = TRUE;
2527 gboolean insertRows = TRUE;
2528 gboolean insertHyperlinks = TRUE;
2529 gboolean deleteColumns = TRUE;
2530 gboolean deleteRows = TRUE;
2531 gboolean selectLockedCells = FALSE;
2532 gboolean sort = TRUE;
2533 gboolean autoFilter = TRUE;
2534 gboolean pivotTables = TRUE;
2535 gboolean selectUnlockedCells = FALSE;
2537 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2538 if (attr_bool (xin, attrs, "sheet", &sheet)) ;
2539 else if (attr_bool (xin, attrs, "objects", &objects)) ;
2540 else if (attr_bool (xin, attrs, "scenarios", &scenarios)) ;
2541 else if (attr_bool (xin, attrs, "formatCells", &formatCells)) ;
2542 else if (attr_bool (xin, attrs, "formatColumns", &formatColumns)) ;
2543 else if (attr_bool (xin, attrs, "formatRows", &formatRows)) ;
2544 else if (attr_bool (xin, attrs, "insertColumns", &insertColumns)) ;
2545 else if (attr_bool (xin, attrs, "insertRows", &insertRows)) ;
2546 else if (attr_bool (xin, attrs, "insertHyperlinks", &insertHyperlinks)) ;
2547 else if (attr_bool (xin, attrs, "deleteColumns", &deleteColumns)) ;
2548 else if (attr_bool (xin, attrs, "deleteRows", &deleteRows)) ;
2549 else if (attr_bool (xin, attrs, "selectLockedCells", &selectLockedCells)) ;
2550 else if (attr_bool (xin, attrs, "sort", &sort)) ;
2551 else if (attr_bool (xin, attrs, "autoFilter", &autoFilter)) ;
2552 else if (attr_bool (xin, attrs, "pivotTables", &pivotTables)) ;
2553 else if (attr_bool (xin, attrs, "selectUnlockedCells", &selectUnlockedCells)) ;
2555 g_object_set (state->sheet,
2556 "protected", sheet,
2557 "protected-allow-edit-objects", objects,
2558 "protected-allow-edit-scenarios", scenarios,
2559 "protected-allow-cell-formatting", formatCells,
2560 "protected-allow-column-formatting", formatColumns,
2561 "protected-allow-row-formatting", formatRows,
2562 "protected-allow-insert-columns", insertColumns,
2563 "protected-allow-insert-rows", insertRows,
2564 "protected-allow-insert-hyperlinks", insertHyperlinks,
2565 "protected-allow-delete-columns", deleteColumns,
2566 "protected-allow-delete-rows", deleteRows,
2567 "protected-allow-select-locked-cells", selectLockedCells,
2568 "protected-allow-sort-ranges", sort,
2569 "protected-allow-edit-auto-filters", autoFilter,
2570 "protected-allow-edit-pivottable", pivotTables,
2571 "protected-allow-select-unlocked-cells", selectUnlockedCells,
2572 NULL);
2575 static void
2576 xlsx_cond_fmt_begin (GsfXMLIn *xin, xmlChar const **attrs)
2578 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2579 char const *refs = NULL;
2581 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2582 if (0 == strcmp (attrs[0], "sqref"))
2583 refs = attrs[1];
2585 state->cond_regions = xlsx_parse_sqref (xin, refs);
2587 /* create in first call xlsx_cond_rule to avoid creating condition with
2588 * no rules */
2589 state->conditions = NULL;
2592 static void
2593 xlsx_cond_fmt_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2595 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2596 GnmStyle *style = NULL;
2597 GSList *ptr;
2599 if (NULL != state->conditions) {
2600 style = gnm_style_new ();
2601 gnm_style_set_conditions (style, state->conditions);
2602 for (ptr = state->cond_regions ; ptr != NULL ; ptr = ptr->next) {
2603 gnm_style_ref (style);
2604 sheet_style_apply_range (state->sheet, ptr->data, style);
2605 g_free (ptr->data);
2607 gnm_style_unref (style);
2608 } else for (ptr = state->cond_regions ; ptr != NULL ; ptr = ptr->next)
2609 g_free (ptr->data);
2610 g_slist_free (state->cond_regions);
2611 state->cond_regions = NULL;
2614 typedef enum {
2615 XLSX_CF_TYPE_UNDEFINED,
2617 XLSX_CF_TYPE_EXPRESSION,
2618 XLSX_CF_TYPE_CELL_IS,
2619 XLSX_CF_TYPE_COLOR_SCALE,
2620 XLSX_CF_TYPE_DATA_BAR,
2621 XLSX_CF_TYPE_ICON_SET,
2622 XLSX_CF_TYPE_TOP10,
2623 XLSX_CF_TYPE_UNIQUE_VALUES,
2624 XLSX_CF_TYPE_DUPLICATE_VALUES,
2625 XLSX_CF_TYPE_CONTAINS_STR,
2626 XLSX_CF_TYPE_NOT_CONTAINS_STR,
2627 XLSX_CF_TYPE_BEGINS_WITH,
2628 XLSX_CF_TYPE_ENDS_WITH,
2629 XLSX_CF_TYPE_CONTAINS_BLANKS,
2630 XLSX_CF_TYPE_NOT_CONTAINS_BLANKS,
2631 XLSX_CF_TYPE_CONTAINS_ERRORS,
2632 XLSX_CF_TYPE_NOT_CONTAINS_ERRORS,
2633 XLSX_CF_TYPE_COMPARE_COLUMNS,
2634 XLSX_CF_TYPE_TIME_PERIOD,
2635 XLSX_CF_TYPE_ABOVE_AVERAGE
2636 } XlsxCFTypes;
2637 static void
2638 xlsx_cond_fmt_rule_begin (GsfXMLIn *xin, xmlChar const **attrs)
2640 static EnumVal const ops[] = {
2641 { "lessThan", GNM_STYLE_COND_LT },
2642 { "lessThanOrEqual", GNM_STYLE_COND_LTE },
2643 { "equal", GNM_STYLE_COND_EQUAL },
2644 { "notEqual", GNM_STYLE_COND_NOT_EQUAL },
2645 { "greaterThanOrEqual", GNM_STYLE_COND_GTE },
2646 { "greaterThan", GNM_STYLE_COND_GT },
2647 { "between", GNM_STYLE_COND_BETWEEN },
2648 { "notBetween", GNM_STYLE_COND_NOT_BETWEEN },
2649 { "containsText", GNM_STYLE_COND_CONTAINS_STR },
2650 { "notContainsText", GNM_STYLE_COND_NOT_CONTAINS_STR },
2651 { "beginsWith", GNM_STYLE_COND_BEGINS_WITH_STR },
2652 { "endsWith", GNM_STYLE_COND_ENDS_WITH_STR },
2653 { "notContain", GNM_STYLE_COND_NOT_CONTAINS_STR },
2654 { NULL, 0 }
2657 static EnumVal const types[] = {
2658 { "expression", XLSX_CF_TYPE_EXPRESSION },
2659 { "cellIs", XLSX_CF_TYPE_CELL_IS },
2660 { "colorScale", XLSX_CF_TYPE_COLOR_SCALE },
2661 { "dataBar", XLSX_CF_TYPE_DATA_BAR },
2662 { "iconSet", XLSX_CF_TYPE_ICON_SET },
2663 { "top10", XLSX_CF_TYPE_TOP10 },
2664 { "uniqueValues", XLSX_CF_TYPE_UNIQUE_VALUES },
2665 { "duplicateValues", XLSX_CF_TYPE_DUPLICATE_VALUES },
2666 { "containsText", XLSX_CF_TYPE_CONTAINS_STR },
2667 { "doesNotContainText", XLSX_CF_TYPE_NOT_CONTAINS_STR }, /* ??? */
2668 { "notContainsText", XLSX_CF_TYPE_NOT_CONTAINS_STR },
2669 { "beginsWith", XLSX_CF_TYPE_BEGINS_WITH },
2670 { "endsWith", XLSX_CF_TYPE_ENDS_WITH },
2671 { "containsBlanks", XLSX_CF_TYPE_CONTAINS_BLANKS },
2672 { "containsNoBlanks", XLSX_CF_TYPE_NOT_CONTAINS_BLANKS }, /* ??? */
2673 { "notContainsBlanks", XLSX_CF_TYPE_NOT_CONTAINS_BLANKS },
2674 { "containsErrors", XLSX_CF_TYPE_CONTAINS_ERRORS },
2675 { "containsNoErrors", XLSX_CF_TYPE_NOT_CONTAINS_ERRORS }, /* ??? */
2676 { "notContainsErrors", XLSX_CF_TYPE_NOT_CONTAINS_ERRORS },
2677 { "compareColumns", XLSX_CF_TYPE_COMPARE_COLUMNS },
2678 { "timePeriod", XLSX_CF_TYPE_TIME_PERIOD },
2679 { "aboveAverage", XLSX_CF_TYPE_ABOVE_AVERAGE },
2680 { NULL, 0 }
2683 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2684 gboolean formatRow = FALSE;
2685 gboolean stopIfTrue = FALSE;
2686 gboolean above = TRUE;
2687 gboolean percent = FALSE;
2688 gboolean bottom = FALSE;
2689 int tmp, dxf = -1;
2690 /* use custom invalid flag, it is not in MS enum */
2691 GnmStyleCondOp op = GNM_STYLE_COND_CUSTOM;
2692 XlsxCFTypes type = XLSX_CF_TYPE_UNDEFINED;
2693 char const *type_str = "-";
2694 GnmStyle *overlay = NULL;
2696 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2697 if (attr_bool (xin, attrs, "formatRow", &formatRow)) ;
2698 else if (attr_bool (xin, attrs, "stopIfTrue", &stopIfTrue)) ;
2699 else if (attr_bool (xin, attrs, "above", &above)) ;
2700 else if (attr_bool (xin, attrs, "percent", &percent)) ;
2701 else if (attr_bool (xin, attrs, "bottom", &bottom)) ;
2702 else if (attr_int (xin, attrs, "dxfId", &dxf)) ;
2703 else if (attr_enum (xin, attrs, "operator", ops, &tmp))
2704 op = tmp;
2705 else if (attr_enum (xin, attrs, "type", types, &tmp)) {
2706 type = tmp;
2707 type_str = attrs[1];
2710 #if 0
2712 "numFmtId" ="ST_NumFmtId" use="optional">
2713 "priority" ="xs:int" use="required">
2714 "text" ="xs:string" use="optional">
2715 "timePeriod" ="ST_TimePeriod" use="optional">
2716 "col1" ="xs:unsignedInt" use="optional">
2717 "col2" ="xs:unsignedInt" use="optional">
2719 #endif
2721 if (dxf >= 0)
2722 overlay = xlsx_get_dxf (xin, dxf);
2724 switch (type) {
2725 case XLSX_CF_TYPE_CELL_IS :
2726 /* Nothing */
2727 break;
2728 case XLSX_CF_TYPE_CONTAINS_STR:
2729 case XLSX_CF_TYPE_NOT_CONTAINS_STR:
2730 case XLSX_CF_TYPE_BEGINS_WITH:
2731 case XLSX_CF_TYPE_ENDS_WITH:
2732 case XLSX_CF_TYPE_CONTAINS_BLANKS:
2733 case XLSX_CF_TYPE_NOT_CONTAINS_BLANKS:
2734 case XLSX_CF_TYPE_CONTAINS_ERRORS:
2735 case XLSX_CF_TYPE_NOT_CONTAINS_ERRORS:
2736 /* The expressions stored for these are the full
2737 expressions, not just what we search for. */
2738 op = GNM_STYLE_COND_CUSTOM;
2739 break;
2741 case XLSX_CF_TYPE_EXPRESSION:
2742 op = GNM_STYLE_COND_CUSTOM;
2743 break;
2745 default :
2746 xlsx_warning (xin, _("Ignoring unhandled conditional format of type '%s'"), type_str);
2749 state->cond = gnm_style_cond_new (op, state->sheet);
2750 gnm_style_cond_set_overlay (state->cond, overlay);
2752 state->count = 0;
2755 static void
2756 xlsx_cond_fmt_rule_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2758 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2759 if (state->cond) {
2760 if (gnm_style_cond_is_valid (state->cond)) {
2761 if (NULL == state->conditions)
2762 state->conditions = gnm_style_conditions_new (state->sheet);
2763 /* Reverse the alternate-expression treatment. */
2764 gnm_style_cond_canonicalize (state->cond);
2766 gnm_style_conditions_insert (state->conditions,
2767 state->cond, -1);
2769 gnm_style_cond_free (state->cond);
2770 state->cond = NULL;
2774 static void
2775 xlsx_cond_fmt_formula_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2777 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2778 GnmParsePos pp;
2779 GnmExprTop const *texpr;
2780 GnmCellPos const *cp;
2782 if (!state->cond || state->count > 1 || state->cond_regions == NULL)
2783 return;
2785 cp = g_slist_last (state->cond_regions)->data;
2786 parse_pos_init (&pp, state->sheet->workbook, state->sheet, cp->col, cp->row);
2787 texpr = xlsx_parse_expr (xin, xin->content->str, &pp);
2788 if (texpr) {
2789 gnm_style_cond_set_expr (state->cond, texpr, state->count);
2790 gnm_expr_top_unref (texpr);
2793 state->count++;
2796 static void
2797 xlsx_CT_SheetView_begin (GsfXMLIn *xin, xmlChar const **attrs)
2799 /* static EnumVal const view_types[] = { */
2800 /* { "normal", GNM_SHEET_VIEW_NORMAL_MODE }, */
2801 /* { "pageBreakPreview", GNM_SHEET_VIEW_PAGE_BREAK_MODE }, */
2802 /* { "pageLayout", GNM_SHEET_VIEW_LAYOUT_MODE }, */
2803 /* { NULL, 0 } */
2804 /* }; */
2806 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2807 int showGridLines = TRUE;
2808 int showFormulas = FALSE;
2809 int showRowColHeaders = TRUE;
2810 int showZeros = TRUE;
2811 int frozen = FALSE;
2812 int frozenSplit = TRUE;
2813 int rightToLeft = FALSE;
2814 int tabSelected = FALSE;
2815 int active = FALSE;
2816 int showRuler = TRUE;
2817 int showOutlineSymbols = TRUE;
2818 int defaultGridColor = TRUE;
2819 int showWhiteSpace = TRUE;
2820 int scale = 100;
2821 int grid_color_index = -1;
2822 /* int tmp; */
2823 /* GnmSheetViewMode view_mode = GNM_SHEET_VIEW_NORMAL_MODE; */
2824 GnmCellPos topLeft = { -1, -1 };
2826 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2827 if (attr_pos (xin, attrs, "topLeftCell", &topLeft)) ;
2828 else if (attr_bool (xin, attrs, "showGridLines", &showGridLines)) ;
2829 else if (attr_bool (xin, attrs, "showFormulas", &showFormulas)) ;
2830 else if (attr_bool (xin, attrs, "showRowColHeaders", &showRowColHeaders)) ;
2831 else if (attr_bool (xin, attrs, "showZeros", &showZeros)) ;
2832 else if (attr_bool (xin, attrs, "frozen", &frozen)) ;
2833 else if (attr_bool (xin, attrs, "frozenSplit", &frozenSplit)) ;
2834 else if (attr_bool (xin, attrs, "rightToLeft", &rightToLeft)) ;
2835 else if (attr_bool (xin, attrs, "tabSelected", &tabSelected)) ;
2836 else if (attr_bool (xin, attrs, "active", &active)) ;
2837 else if (attr_bool (xin, attrs, "showRuler", &showRuler)) ;
2838 else if (attr_bool (xin, attrs, "showOutlineSymbols", &showOutlineSymbols)) ;
2839 else if (attr_bool (xin, attrs, "defaultGridColor", &defaultGridColor)) ;
2840 else if (attr_bool (xin, attrs, "showWhiteSpace", &showWhiteSpace)) ;
2841 else if (attr_int (xin, attrs, "zoomScale", &scale)) ;
2842 else if (attr_int (xin, attrs, "colorId", &grid_color_index)) ;
2843 /* else if (attr_enum (xin, attrs, "view", view_types, &tmp)) */
2844 /* view_mode = tmp; */
2845 #if 0
2846 "zoomScaleNormal" type="xs:unsignedInt" use="optional" default="0"
2847 "zoomScaleSheetLayoutView" type="xs:unsignedInt" use="optional" default="0"
2848 "zoomScalePageLayoutView" type="xs:unsignedInt" use="optional" default="0"
2849 "workbookViewId" type="xs:unsignedInt" use="required"
2850 #endif
2852 /* get this from the workbookViewId */
2853 g_return_if_fail (state->sv == NULL);
2854 state->sv = sheet_get_view (state->sheet, state->wb_view);
2855 state->pane_pos = XLSX_PANE_TOP_LEFT;
2857 /* until we import multiple views unfreeze just in case a previous view
2858 * had frozen */
2859 sv_freeze_panes (state->sv, NULL, NULL);
2861 if (topLeft.col >= 0)
2862 sv_set_initial_top_left (state->sv, topLeft.col, topLeft.row);
2863 g_object_set (state->sheet,
2864 "text-is-rtl", rightToLeft,
2865 "display-formulas", showFormulas,
2866 "display-zeros", showZeros,
2867 "display-grid", showGridLines,
2868 "display-column-header", showRowColHeaders,
2869 "display-row-header", showRowColHeaders,
2870 "display-outlines", showOutlineSymbols,
2871 "zoom-factor", ((double)scale) / 100.,
2872 NULL);
2873 #if 0
2874 gboolean active = FALSE;
2875 gboolean showRuler = TRUE;
2876 gboolean showWhiteSpace = TRUE;
2877 #endif
2879 #if 0
2880 g_object_set (state->sv,
2881 "displayMode", view_mode,
2882 NULL);
2883 #endif
2885 if (!defaultGridColor && grid_color_index >= 0)
2886 sheet_style_set_auto_pattern_color (state->sheet,
2887 gnm_color_new_go (indexed_color (state, grid_color_index)));
2888 if (tabSelected)
2889 wb_view_sheet_focus (state->wb_view, state->sheet);
2891 static void
2892 xlsx_CT_SheetView_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2894 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2895 g_return_if_fail (state->sv != NULL);
2896 state->sv = NULL;
2899 static EnumVal const pane_types[] = {
2900 { "topLeft", XLSX_PANE_TOP_LEFT },
2901 { "topRight", XLSX_PANE_TOP_RIGHT },
2902 { "bottomLeft", XLSX_PANE_BOTTOM_LEFT },
2903 { "bottomRight", XLSX_PANE_BOTTOM_RIGHT },
2904 { NULL, 0 }
2906 static void
2907 xlsx_CT_Selection (GsfXMLIn *xin, xmlChar const **attrs)
2909 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2910 GnmCellPos edit_pos = { -1, -1 };
2911 int i, sel_with_edit_pos = 0;
2912 char const *refs = NULL;
2913 XLSXPanePos pane_pos = XLSX_PANE_TOP_LEFT;
2914 GnmRange r;
2915 GSList *ptr, *accum = NULL;
2917 g_return_if_fail (state->sv != NULL);
2919 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2920 if (0 == strcmp (attrs[0], "sqref"))
2921 refs = attrs[1];
2922 else if (attr_enum (xin, attrs, "activePane", pane_types, &i))
2923 pane_pos = i;
2924 else if (attr_pos (xin, attrs, "activeCell", &edit_pos)) ;
2925 else if (attr_int (xin, attrs, "activeCellId", &sel_with_edit_pos))
2928 if (pane_pos != state->pane_pos)
2929 return;
2931 for (i = 0 ; NULL != refs && *refs ; i++) {
2932 if (NULL == (refs = cellpos_parse (refs, gnm_sheet_get_size (state->sheet), &r.start, FALSE)))
2933 return;
2935 if (*refs == '\0' || *refs == ' ')
2936 r.end = r.start;
2937 else if (*refs != ':' ||
2938 NULL == (refs = cellpos_parse (refs + 1, gnm_sheet_get_size (state->sheet), &r.end, FALSE)))
2939 return;
2941 if (i == 0)
2942 sv_selection_reset (state->sv);
2944 /* gnumeric assumes the edit_pos is in the last selected range.
2945 * We need to re-order the selection list. */
2946 if (i <= sel_with_edit_pos && edit_pos.col >= 0)
2947 accum = g_slist_prepend (accum, gnm_range_dup (&r));
2948 else
2949 sv_selection_add_range (state->sv, &r);
2950 while (*refs == ' ')
2951 refs++;
2954 if (NULL != accum) {
2955 accum = g_slist_reverse (accum);
2956 for (ptr = accum ; ptr != NULL ; ptr = ptr->next) {
2957 sv_selection_add_range (state->sv, ptr->data);
2958 g_free (ptr->data);
2960 sv_set_edit_pos (state->sv, &edit_pos);
2961 g_slist_free (accum);
2965 static void
2966 xlsx_CT_PivotSelection (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2968 #if 0
2969 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2970 <xsd:attribute name="pane" type="ST_Pane" use="optional" default="topLeft">
2971 <xsd:attribute name="showHeader" type="xsd:boolean" default="false">
2972 <xsd:attribute name="label" type="xsd:boolean" default="false">
2973 <xsd:attribute name="data" type="xsd:boolean" default="false">
2974 <xsd:attribute name="extendable" type="xsd:boolean" default="false">
2975 <xsd:attribute name="count" type="xsd:unsignedInt" default="0">
2976 <xsd:attribute name="axis" type="ST_Axis" use="optional">
2977 <xsd:attribute name="dimension" type="xsd:unsignedInt" default="0">
2978 <xsd:attribute name="start" type="xsd:unsignedInt" default="0">
2979 <xsd:attribute name="min" type="xsd:unsignedInt" default="0">
2980 <xsd:attribute name="max" type="xsd:unsignedInt" default="0">
2981 <xsd:attribute name="activeRow" type="xsd:unsignedInt" default="0">
2982 <xsd:attribute name="activeCol" type="xsd:unsignedInt" default="0">
2983 <xsd:attribute name="previousRow" type="xsd:unsignedInt" default="0">
2984 <xsd:attribute name="previousCol" type="xsd:unsignedInt" default="0">
2985 <xsd:attribute name="click" type="xsd:unsignedInt" default="0">
2986 <xsd:attribute ref="r:id" use="optional">
2987 #endif
2990 static void
2991 xlsx_CT_PivotArea (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2993 #if 0
2994 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2995 <xsd:attribute name="field" use="optional" type="xsd:int">
2996 <xsd:attribute name="type" type="ST_PivotAreaType" default="normal">
2997 <xsd:attribute name="dataOnly" type="xsd:boolean" default="true">
2998 <xsd:attribute name="labelOnly" type="xsd:boolean" default="false">
2999 <xsd:attribute name="grandRow" type="xsd:boolean" default="false">
3000 <xsd:attribute name="grandCol" type="xsd:boolean" default="false">
3001 <xsd:attribute name="cacheIndex" type="xsd:boolean" default="false">
3002 <xsd:attribute name="outline" type="xsd:boolean" default="true">
3003 <xsd:attribute name="offset" type="ST_Ref">
3004 <xsd:attribute name="collapsedLevelsAreSubtotals" type="xsd:boolean" default="false">
3005 <xsd:attribute name="axis" type="ST_Axis" use="optional">
3006 <xsd:attribute name="fieldPosition" type="xsd:unsignedInt" use="optional">
3007 #endif
3009 static void
3010 xlsx_CT_PivotAreaReferences (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3012 #if 0
3013 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3014 #endif
3016 static void
3017 xlsx_CT_PivotAreaReference (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3019 #if 0
3020 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3021 <xsd:attribute name="field" use="optional" type="xsd:unsignedInt">
3022 <xsd:attribute name="count" type="xsd:unsignedInt">
3023 <xsd:attribute name="selected" type="xsd:boolean" default="true">
3024 <xsd:attribute name="byPosition" type="xsd:boolean" default="false">
3025 <xsd:attribute name="relative" type="xsd:boolean" default="false">
3026 <xsd:attribute name="defaultSubtotal" type="xsd:boolean" default="false">
3027 <xsd:attribute name="sumSubtotal" type="xsd:boolean" default="false">
3028 <xsd:attribute name="countASubtotal" type="xsd:boolean" default="false">
3029 <xsd:attribute name="avgSubtotal" type="xsd:boolean" default="false">
3030 <xsd:attribute name="maxSubtotal" type="xsd:boolean" default="false">
3031 <xsd:attribute name="minSubtotal" type="xsd:boolean" default="false">
3032 <xsd:attribute name="productSubtotal" type="xsd:boolean" default="false">
3033 <xsd:attribute name="countSubtotal" type="xsd:boolean" default="false">
3034 <xsd:attribute name="stdDevSubtotal" type="xsd:boolean" default="false">
3035 <xsd:attribute name="stdDevPSubtotal" type="xsd:boolean" default="false">
3036 <xsd:attribute name="varSubtotal" type="xsd:boolean" default="false">
3037 <xsd:attribute name="varPSubtotal" type="xsd:boolean" default="false">
3038 #endif
3041 static void
3042 xlsx_CT_Pane (GsfXMLIn *xin, xmlChar const **attrs)
3044 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3045 GnmCellPos topLeft = { 0, 0 };
3046 int tmp;
3047 gnm_float xSplit = -1., ySplit = -1.;
3048 gboolean frozen = FALSE;
3050 g_return_if_fail (state->sv != NULL);
3052 /* <pane xSplit="2" ySplit="3" topLeftCell="J15" activePane="bottomRight" state="frozen"/> */
3053 state->pane_pos = XLSX_PANE_TOP_LEFT;
3054 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3055 if (0 == strcmp (attrs[0], "state"))
3056 frozen = (0 == strcmp (attrs[1], "frozen"));
3057 else if (attr_pos (xin, attrs, "topLeftCell", &topLeft)) ;
3058 else if (attr_float (xin, attrs, "xSplit", &xSplit)) ;
3059 else if (attr_float (xin, attrs, "ySplit", &ySplit)) ;
3060 else if (attr_enum (xin, attrs, "pane", pane_types, &tmp))
3061 state->pane_pos = tmp;
3063 if (frozen) {
3064 GnmCellPos frozen, unfrozen;
3065 frozen = unfrozen = state->sv->initial_top_left;
3066 if (xSplit > 0)
3067 unfrozen.col += xSplit;
3068 else
3069 topLeft.col = state->sv->initial_top_left.col;
3070 if (ySplit > 0)
3071 unfrozen.row += ySplit;
3072 else
3073 topLeft.row = state->sv->initial_top_left.row;
3074 sv_freeze_panes (state->sv, &frozen, &unfrozen);
3075 sv_set_initial_top_left (state->sv, topLeft.col, topLeft.row);
3079 static void
3080 xlsx_ole_object (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3082 #if 0
3083 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3085 /* <oleObject progId="Wordpad.Document.1" shapeId="1032" r:id="rId5"/> */
3086 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3088 #endif
3091 static void
3092 xlsx_CT_HyperLinks (GsfXMLIn *xin, xmlChar const **attrs)
3094 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3095 gboolean has_ref = FALSE;
3096 GnmStyle *style;
3097 GnmRange r;
3098 GType link_type = 0;
3099 GnmHLink *link = NULL;
3100 xmlChar const *target = NULL;
3101 xmlChar const *tooltip = NULL;
3102 xmlChar const *extern_id = NULL;
3104 /* <hyperlink ref="A42" r:id="rId1"/> */
3105 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3106 if (attr_range (xin, attrs, "ref", &r))
3107 has_ref = TRUE;
3108 else if (0 == strcmp (attrs[0], "location"))
3109 target = attrs[1];
3110 else if (0 == strcmp (attrs[0], "tooltip"))
3111 tooltip = attrs[1];
3112 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3113 extern_id = attrs[1];
3114 #if 0 /* ignore "display" on import, it always seems to be the cell content */
3115 else if (0 == strcmp (attrs[0], "display"))
3116 #endif
3117 if (!has_ref)
3118 return;
3120 if (NULL != target)
3121 link_type = gnm_hlink_cur_wb_get_type ();
3122 else if (NULL != extern_id) {
3123 GsfOpenPkgRel const *rel = gsf_open_pkg_lookup_rel_by_id (
3124 gsf_xml_in_get_input (xin), extern_id);
3125 if (NULL != rel &&
3126 gsf_open_pkg_rel_is_extern (rel) &&
3127 0 == strcmp (gsf_open_pkg_rel_get_type (rel),
3128 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")) {
3129 target = gsf_open_pkg_rel_get_target (rel);
3130 if (NULL != target) {
3131 if (0 == strncmp (target, "mailto:", 7))
3132 link_type = gnm_hlink_email_get_type ();
3133 else
3134 link_type = gnm_hlink_url_get_type ();
3139 if (0 == link_type) {
3140 xlsx_warning (xin, _("Unknown type of hyperlink"));
3141 return;
3144 link = g_object_new (link_type, NULL);
3145 if (NULL != target)
3146 gnm_hlink_set_target (link, target);
3147 if (NULL != tooltip)
3148 gnm_hlink_set_tip (link, tooltip);
3149 style = gnm_style_new ();
3150 gnm_style_set_hlink (style, link);
3151 sheet_style_apply_range (state->sheet, &r, style);
3154 static void
3155 cb_find_pivots (GsfInput *opkg, GsfOpenPkgRel const *rel, gpointer user_data)
3157 XLSXReadState *state = user_data;
3158 GsfInput *part_stream;
3159 char const *t = gsf_open_pkg_rel_get_type (rel);
3161 if (NULL != t &&
3162 0 == strcmp (t, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable") &&
3163 NULL != (part_stream = gsf_open_pkg_open_rel (opkg, rel, NULL)))
3164 xlsx_parse_stream (state, part_stream, xlsx_pivot_table_dtd);
3167 static void
3168 xlsx_CT_worksheet (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3170 gsf_open_pkg_foreach_rel (gsf_xml_in_get_input (xin),
3171 &cb_find_pivots, (XLSXReadState *)xin->user_state);
3175 static void
3176 xlsx_ext_begin (GsfXMLIn *xin, xmlChar const **attrs)
3178 gboolean warned = FALSE;
3179 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3180 if (0 == strcmp (attrs[0], "uri")) {
3181 #if 0
3182 xlsx_warning (xin,
3183 _("Encountered uninterpretable \"ext\" extension in namespace \"%s\""),
3184 attrs[1]);
3185 #endif
3186 warned = TRUE;
3188 if (!warned)
3189 xlsx_warning (xin,
3190 _("Encountered uninterpretable \"ext\" extension with missing namespace"));
3191 gsf_xml_in_set_silent_unknowns (xin, TRUE);
3194 static void
3195 xlsx_ext_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3197 gsf_xml_in_set_silent_unknowns (xin, FALSE);
3202 static void
3203 add_attr (XLSXReadState *state, PangoAttribute *attr)
3205 attr->start_index = 0;
3206 attr->end_index = -1;
3208 if (state->run_attrs == NULL)
3209 state->run_attrs = pango_attr_list_new ();
3211 pango_attr_list_insert (state->run_attrs, attr);
3214 static void
3215 xlsx_run_weight (GsfXMLIn *xin, xmlChar const **attrs)
3217 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3218 PangoWeight wt = PANGO_WEIGHT_BOLD; /* Default */
3220 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3221 int i;
3222 if (attr_bool (xin, attrs, "val", &i))
3223 wt = i ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL;
3226 add_attr (state, pango_attr_weight_new (wt));
3229 static void
3230 xlsx_run_style (GsfXMLIn *xin, xmlChar const **attrs)
3232 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3233 PangoStyle st = PANGO_STYLE_ITALIC;
3235 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3236 int i;
3237 if (attr_bool (xin, attrs, "val", &i))
3238 st = i ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
3241 add_attr (state, pango_attr_style_new (st));
3244 static void
3245 xlsx_run_family (GsfXMLIn *xin, xmlChar const **attrs)
3247 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3248 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3249 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
3250 PangoAttribute *attr = pango_attr_family_new (attrs[1]);
3251 add_attr (state, attr);
3255 static void
3256 xlsx_run_size (GsfXMLIn *xin, xmlChar const **attrs)
3258 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3259 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3260 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
3261 PangoAttribute *attr = pango_attr_size_new (atoi (attrs[1]) * PANGO_SCALE);
3262 add_attr (state, attr);
3267 static void
3268 xlsx_run_strikethrough (GsfXMLIn *xin, xmlChar const **attrs)
3270 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3271 gboolean st = TRUE; /* Default */
3273 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3274 int i;
3275 if (attr_bool (xin, attrs, "val", &i))
3276 st = i;
3279 add_attr (state, pango_attr_strikethrough_new (st));
3282 static void
3283 xlsx_run_underline (GsfXMLIn *xin, xmlChar const **attrs)
3285 static EnumVal const types[] = {
3286 { "single", PANGO_UNDERLINE_SINGLE },
3287 { "double", PANGO_UNDERLINE_DOUBLE },
3288 { "singleAccounting", PANGO_UNDERLINE_LOW },
3289 { "doubleAccounting", PANGO_UNDERLINE_LOW }, /* fixme? */
3290 { "none", PANGO_UNDERLINE_NONE },
3291 { NULL, 0 }
3293 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3294 int u = PANGO_UNDERLINE_SINGLE;
3296 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3297 if (attr_enum (xin, attrs, "val", types, &u))
3301 add_attr (state, pango_attr_underline_new (u));
3304 static void
3305 xlsx_run_vertalign (GsfXMLIn *xin, xmlChar const **attrs)
3307 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3308 static EnumVal const types[] = {
3309 { "subscript", GO_FONT_SCRIPT_SUB },
3310 { "baseline", GO_FONT_SCRIPT_STANDARD },
3311 { "superscript", GO_FONT_SCRIPT_SUPER },
3312 { NULL, 0 }
3314 int v = GO_FONT_SCRIPT_STANDARD;
3316 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3317 if (attr_enum (xin, attrs, "val", types, &v))
3321 switch (v) {
3322 case GO_FONT_SCRIPT_SUB:
3323 add_attr (state, go_pango_attr_subscript_new (TRUE));
3324 break;
3325 case GO_FONT_SCRIPT_SUPER:
3326 add_attr (state, go_pango_attr_superscript_new (TRUE));
3327 break;
3328 default:
3329 break;
3334 static void
3335 xlsx_run_color (GsfXMLIn *xin, xmlChar const **attrs)
3337 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3338 GOColor c = GO_COLOR_BLACK;
3340 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3341 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "rgb")) {
3342 unsigned r, g, b, a;
3343 if (4 != sscanf (attrs[1], "%02x%02x%02x%02x", &a, &r, &g, &b)) {
3344 xlsx_warning (xin,
3345 _("Invalid color '%s' for attribute rgb"),
3346 attrs[1]);
3347 continue;
3350 c = GO_COLOR_FROM_RGBA (r, g, b, a);
3351 } else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "indexed")) {
3352 int idx = atoi (CXML2C (attrs[1]));
3353 c = indexed_color (state, idx);
3357 add_attr (state, go_color_to_pango (c, TRUE));
3360 static gboolean
3361 cb_trunc_attributes (PangoAttribute *a, gpointer plen)
3363 a->end_index = GPOINTER_TO_UINT (plen);
3364 return FALSE;
3367 static void
3368 xlsx_rich_text (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3370 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3371 const char *s = xin->content->str;
3373 if (state->run_attrs) {
3374 unsigned len = strlen (s);
3375 unsigned start = state->r_text->len, end = start + len;
3376 pango_attr_list_filter (state->run_attrs,
3377 (PangoAttrFilterFunc) cb_trunc_attributes,
3378 GUINT_TO_POINTER (len));
3379 if (state->rich_attrs == NULL)
3380 state->rich_attrs = pango_attr_list_new ();
3381 pango_attr_list_splice (state->rich_attrs, state->run_attrs, start, end);
3382 pango_attr_list_unref (state->run_attrs);
3383 state->run_attrs = NULL;
3385 g_string_append (state->r_text, s);
3389 * Rich text is used in multiple dtds. We don't hanadle that with
3390 * particular elegance, but we've got macros.
3392 #define RICH_TEXT_NODES \
3393 GSF_XML_IN_NODE (RICH, RICH_TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_rich_text), \
3394 GSF_XML_IN_NODE (RICH, RICH_PROPS, XL_NS_SS, "rPr", GSF_XML_NO_CONTENT, NULL, NULL), \
3395 /* GSF_XML_IN_NODE (RICH_PROPS, RICH_FONT, XL_NS_SS, "font", GSF_XML_NO_CONTENT, NULL, NULL), */ \
3396 /* docs say 'font' xl is generating rFont */ \
3397 GSF_XML_IN_NODE (RICH_PROPS, RICH_FONT, XL_NS_SS, "rFont", GSF_XML_NO_CONTENT, NULL, NULL), \
3399 GSF_XML_IN_NODE (RICH_PROPS, RICH_CHARSET, XL_NS_SS, "charset", GSF_XML_NO_CONTENT, NULL, NULL), \
3400 GSF_XML_IN_NODE (RICH_PROPS, RICH_FAMILY, XL_NS_SS, "family", GSF_XML_NO_CONTENT, xlsx_run_family, NULL), \
3401 GSF_XML_IN_NODE (RICH_PROPS, RICH_BOLD, XL_NS_SS, "b", GSF_XML_NO_CONTENT, xlsx_run_weight, NULL), \
3402 GSF_XML_IN_NODE (RICH_PROPS, RICH_ITALIC, XL_NS_SS, "i", GSF_XML_NO_CONTENT, xlsx_run_style, NULL), \
3403 GSF_XML_IN_NODE (RICH_PROPS, RICH_STRIKE, XL_NS_SS, "strike", GSF_XML_NO_CONTENT, xlsx_run_strikethrough, NULL), \
3404 GSF_XML_IN_NODE (RICH_PROPS, RICH_OUTLINE, XL_NS_SS, "outline", GSF_XML_NO_CONTENT, NULL, NULL), \
3405 GSF_XML_IN_NODE (RICH_PROPS, RICH_SHADOW, XL_NS_SS, "shadow", GSF_XML_NO_CONTENT, NULL, NULL), \
3406 GSF_XML_IN_NODE (RICH_PROPS, RICH_CONDENSE, XL_NS_SS, "condense", GSF_XML_NO_CONTENT, NULL, NULL), \
3407 GSF_XML_IN_NODE (RICH_PROPS, RICH_EXTEND, XL_NS_SS, "extend", GSF_XML_NO_CONTENT, NULL, NULL), \
3408 GSF_XML_IN_NODE (RICH_PROPS, RICH_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, xlsx_run_color, NULL), \
3409 GSF_XML_IN_NODE (RICH_PROPS, RICH_SZ, XL_NS_SS, "sz", GSF_XML_NO_CONTENT, xlsx_run_size, NULL), \
3410 GSF_XML_IN_NODE (RICH_PROPS, RICH_ULINE, XL_NS_SS, "u", GSF_XML_NO_CONTENT, xlsx_run_underline, NULL), \
3411 GSF_XML_IN_NODE (RICH_PROPS, RICH_VALIGN, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, xlsx_run_vertalign, NULL), \
3412 GSF_XML_IN_NODE (RICH_PROPS, RICH_SCHEME, XL_NS_SS, "scheme", GSF_XML_NO_CONTENT, NULL, NULL)
3417 static GsfXMLInNode const xlsx_sheet_dtd[] = {
3418 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3419 GSF_XML_IN_NODE_FULL (START, SHEET, XL_NS_SS, "worksheet", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, &xlsx_CT_worksheet, 0),
3420 GSF_XML_IN_NODE (SHEET, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
3421 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_SS, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
3422 GSF_XML_IN_NODE (SHEET, PROPS, XL_NS_SS, "sheetPr", GSF_XML_NO_CONTENT, &xlsx_CT_SheetPr, NULL),
3423 GSF_XML_IN_NODE (PROPS, OUTLINE_PROPS, XL_NS_SS, "outlinePr", GSF_XML_NO_CONTENT, NULL, NULL),
3424 GSF_XML_IN_NODE (PROPS, TAB_COLOR, XL_NS_SS, "tabColor", GSF_XML_NO_CONTENT, &xlsx_sheet_tabcolor, NULL),
3425 GSF_XML_IN_NODE (PROPS, PAGE_SETUP, XL_NS_SS, "pageSetUpPr", GSF_XML_NO_CONTENT, &xlsx_sheet_page_setup, NULL),
3426 GSF_XML_IN_NODE (SHEET, DIMENSION, XL_NS_SS, "dimension", GSF_XML_NO_CONTENT, NULL, NULL),
3427 GSF_XML_IN_NODE (SHEET, VIEWS, XL_NS_SS, "sheetViews", GSF_XML_NO_CONTENT, NULL, NULL),
3428 GSF_XML_IN_NODE (VIEWS, VIEW, XL_NS_SS, "sheetView", GSF_XML_NO_CONTENT, &xlsx_CT_SheetView_begin, &xlsx_CT_SheetView_end),
3429 GSF_XML_IN_NODE (VIEW, PANE, XL_NS_SS, "pane", GSF_XML_NO_CONTENT, &xlsx_CT_Pane, NULL),
3430 GSF_XML_IN_NODE (VIEW, SELECTION, XL_NS_SS, "selection", GSF_XML_NO_CONTENT, &xlsx_CT_Selection, NULL),
3431 GSF_XML_IN_NODE (VIEW, PIV_SELECTION, XL_NS_SS, "pivotSelection", GSF_XML_NO_CONTENT, &xlsx_CT_PivotSelection, NULL),
3432 GSF_XML_IN_NODE (PIV_SELECTION, PIV_AREA, XL_NS_SS, "pivotArea", GSF_XML_NO_CONTENT, &xlsx_CT_PivotArea, NULL),
3433 GSF_XML_IN_NODE (PIV_AREA, PIV_AREA_REFS, XL_NS_SS, "references", GSF_XML_NO_CONTENT, &xlsx_CT_PivotAreaReferences, NULL),
3434 GSF_XML_IN_NODE (PIV_AREA_REFS, PIV_AREA_REF, XL_NS_SS, "reference", GSF_XML_NO_CONTENT, &xlsx_CT_PivotAreaReference, NULL),
3436 GSF_XML_IN_NODE (SHEET, DEFAULT_FMT, XL_NS_SS, "sheetFormatPr", GSF_XML_NO_CONTENT, &xlsx_CT_SheetFormatPr, NULL),
3438 GSF_XML_IN_NODE (SHEET, COLS, XL_NS_SS, "cols", GSF_XML_NO_CONTENT, NULL, xlsx_CT_RowsCols_end),
3439 GSF_XML_IN_NODE (COLS, COL, XL_NS_SS, "col", GSF_XML_NO_CONTENT, &xlsx_CT_Col, NULL),
3441 GSF_XML_IN_NODE (SHEET, CONTENT, XL_NS_SS, "sheetData", GSF_XML_NO_CONTENT, NULL, NULL),
3442 GSF_XML_IN_NODE (CONTENT, ROW, XL_NS_SS, "row", GSF_XML_NO_CONTENT, &xlsx_CT_Row, NULL),
3443 GSF_XML_IN_NODE (ROW, CELL, XL_NS_SS, "c", GSF_XML_NO_CONTENT, &xlsx_cell_begin, &xlsx_cell_end),
3444 GSF_XML_IN_NODE (CELL, VALUE, XL_NS_SS, "v", GSF_XML_CONTENT, NULL, &xlsx_cell_val_end),
3445 GSF_XML_IN_NODE (CELL, FMLA, XL_NS_SS, "f", GSF_XML_CONTENT, &xlsx_cell_expr_begin, &xlsx_cell_expr_end),
3446 GSF_XML_IN_NODE (CELL, TEXTINLINE, XL_NS_SS, "is", GSF_XML_NO_CONTENT, &xlsx_cell_inline_begin, &xlsx_cell_inline_end),
3447 GSF_XML_IN_NODE (TEXTINLINE, TEXTRUN, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, &xlsx_cell_inline_text_end),
3448 GSF_XML_IN_NODE (TEXTINLINE, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
3449 RICH_TEXT_NODES,
3450 GSF_XML_IN_NODE (CELL, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd */
3452 GSF_XML_IN_NODE (SHEET, CALC_PR, XL_NS_SS, "sheetCalcPr", GSF_XML_NO_CONTENT, NULL, NULL),
3453 GSF_XML_IN_NODE (SHEET, CT_SortState, XL_NS_SS, "sortState", GSF_XML_NO_CONTENT, NULL, NULL),
3454 GSF_XML_IN_NODE (CT_SortState, CT_SortCondition, XL_NS_SS, "sortCondition", GSF_XML_NO_CONTENT, NULL, NULL),
3455 GSF_XML_IN_NODE (SHEET, SCENARIOS, XL_NS_SS, "scenarios", GSF_XML_NO_CONTENT, NULL, NULL),
3456 GSF_XML_IN_NODE (SCENARIOS, INPUT_CELLS, XL_NS_SS, "inputCells", GSF_XML_NO_CONTENT, NULL, NULL),
3457 GSF_XML_IN_NODE (SHEET, PROTECTED_RANGES, XL_NS_SS, "protectedRanges", GSF_XML_NO_CONTENT, NULL, NULL),
3458 GSF_XML_IN_NODE (PROTECTED_RANGES, PROTECTED_RANGE, XL_NS_SS, "protectedRange", GSF_XML_NO_CONTENT, NULL, NULL),
3460 GSF_XML_IN_NODE (SHEET, CT_AutoFilter, XL_NS_SS, "autoFilter", GSF_XML_NO_CONTENT,
3461 &xlsx_CT_AutoFilter_begin, &xlsx_CT_AutoFilter_end),
3462 GSF_XML_IN_NODE (CT_AutoFilter, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
3463 GSF_XML_IN_NODE (CT_AutoFilter, CT_SortState, XL_NS_SS, "sortState", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
3464 GSF_XML_IN_NODE (CT_AutoFilter, CT_FilterColumn, XL_NS_SS, "filterColumn", GSF_XML_NO_CONTENT,
3465 &xlsx_CT_FilterColumn_begin, NULL),
3466 GSF_XML_IN_NODE (CT_FilterColumn, CT_Filters, XL_NS_SS, "filters", GSF_XML_NO_CONTENT,
3467 &xlsx_CT_Filters_begin, &xlsx_CT_Filters_end),
3468 GSF_XML_IN_NODE (CT_Filters, CT_Filter, XL_NS_SS, "filter", GSF_XML_NO_CONTENT, &xlsx_CT_Filter, NULL),
3469 GSF_XML_IN_NODE (CT_FilterColumn, CT_CustomFilters, XL_NS_SS, "customFilters", GSF_XML_NO_CONTENT,
3470 &xlsx_CT_CustomFilters_begin, &xlsx_CT_CustomFilters_end),
3471 GSF_XML_IN_NODE (CT_CustomFilters, CT_CustomFilter, XL_NS_SS, "customFilter", GSF_XML_NO_CONTENT, &xlsx_CT_CustomFilter, NULL),
3472 GSF_XML_IN_NODE (CT_FilterColumn, CT_Top10, XL_NS_SS, "top10", GSF_XML_NO_CONTENT, &xlsx_CT_Top10, NULL),
3473 GSF_XML_IN_NODE (CT_FilterColumn, CT_DynamicFilter, XL_NS_SS, "dynamicFilter", GSF_XML_NO_CONTENT, &xlsx_CT_DynamicFilter, NULL),
3474 GSF_XML_IN_NODE (CT_FilterColumn, CT_ColorFilter, XL_NS_SS, "colorFilter", GSF_XML_NO_CONTENT, NULL, NULL),
3475 GSF_XML_IN_NODE (CT_FilterColumn, CT_IconFilter, XL_NS_SS, "iconFilter", GSF_XML_NO_CONTENT, NULL, NULL),
3477 GSF_XML_IN_NODE (SHEET, CT_DataValidations, XL_NS_SS, "dataValidations", GSF_XML_NO_CONTENT, NULL, NULL),
3478 GSF_XML_IN_NODE (CT_DataValidations, CT_DataValidation, XL_NS_SS, "dataValidation", GSF_XML_NO_CONTENT,
3479 &xlsx_CT_DataValidation_begin, &xlsx_CT_DataValidation_end),
3480 GSF_XML_IN_NODE_FULL (CT_DataValidation, VAL_FORMULA1, XL_NS_SS, "formula1", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xlsx_validation_expr, 0),
3481 GSF_XML_IN_NODE_FULL (CT_DataValidation, VAL_FORMULA2, XL_NS_SS, "formula2", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xlsx_validation_expr, 1),
3483 GSF_XML_IN_NODE (SHEET, MERGES, XL_NS_SS, "mergeCells", GSF_XML_NO_CONTENT, NULL, NULL),
3484 GSF_XML_IN_NODE (MERGES, MERGE, XL_NS_SS, "mergeCell", GSF_XML_NO_CONTENT, &xlsx_CT_MergeCell, NULL),
3486 GSF_XML_IN_NODE (SHEET, DRAWING, XL_NS_SS, "drawing", GSF_XML_NO_CONTENT, &xlsx_sheet_drawing, NULL),
3488 GSF_XML_IN_NODE (SHEET, PROTECTION, XL_NS_SS, "sheetProtection", GSF_XML_NO_CONTENT, &xlsx_CT_SheetProtection, NULL),
3489 GSF_XML_IN_NODE (SHEET, PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
3490 GSF_XML_IN_NODE (SHEET, COND_FMTS, XL_NS_SS, "conditionalFormatting", GSF_XML_NO_CONTENT,
3491 &xlsx_cond_fmt_begin, &xlsx_cond_fmt_end),
3492 GSF_XML_IN_NODE (COND_FMTS, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
3493 GSF_XML_IN_NODE (COND_FMTS, COND_RULE, XL_NS_SS, "cfRule", GSF_XML_NO_CONTENT,
3494 &xlsx_cond_fmt_rule_begin, &xlsx_cond_fmt_rule_end),
3495 GSF_XML_IN_NODE (COND_RULE, COND_FMLA, XL_NS_SS, "formula", GSF_XML_CONTENT, NULL, &xlsx_cond_fmt_formula_end),
3496 GSF_XML_IN_NODE (COND_RULE, COND_COLOR_SCALE, XL_NS_SS, "colorScale", GSF_XML_NO_CONTENT, NULL, NULL),
3497 GSF_XML_IN_NODE (COND_COLOR_SCALE, CFVO, XL_NS_SS, "cfvo", GSF_XML_NO_CONTENT, NULL, NULL),
3498 GSF_XML_IN_NODE (COND_COLOR_SCALE, COND_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
3499 GSF_XML_IN_NODE (COND_RULE, COND_DATA_BAR, XL_NS_SS, "dataBar", GSF_XML_NO_CONTENT, NULL, NULL),
3500 GSF_XML_IN_NODE (COND_RULE, COND_ICON_SET, XL_NS_SS, "iconSet", GSF_XML_NO_CONTENT, NULL, NULL),
3501 GSF_XML_IN_NODE (COND_ICON_SET, CFVO, XL_NS_SS, "cfvo", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
3503 GSF_XML_IN_NODE (SHEET, HYPERLINKS, XL_NS_SS, "hyperlinks", GSF_XML_NO_CONTENT, NULL, NULL),
3504 GSF_XML_IN_NODE (HYPERLINKS, HYPERLINK, XL_NS_SS, "hyperlink", GSF_XML_NO_CONTENT, &xlsx_CT_HyperLinks, NULL),
3506 GSF_XML_IN_NODE (SHEET, PRINT_OPTS, XL_NS_SS, "printOptions", GSF_XML_NO_CONTENT, NULL, NULL),
3507 GSF_XML_IN_NODE (SHEET, PRINT_MARGINS, XL_NS_SS, "pageMargins", GSF_XML_NO_CONTENT, &xlsx_CT_PageMargins, NULL),
3508 GSF_XML_IN_NODE (SHEET, PRINT_SETUP, XL_NS_SS, "pageSetup", GSF_XML_NO_CONTENT, &xlsx_CT_PageSetup, NULL),
3509 GSF_XML_IN_NODE (SHEET, PRINT_HEADER_FOOTER, XL_NS_SS, "headerFooter", GSF_XML_NO_CONTENT, NULL, NULL),
3510 GSF_XML_IN_NODE (PRINT_HEADER_FOOTER, ODD_HEADER, XL_NS_SS, "oddHeader", GSF_XML_CONTENT, NULL, &xlsx_CT_oddheader_end),
3511 GSF_XML_IN_NODE (PRINT_HEADER_FOOTER, ODD_FOOTER, XL_NS_SS, "oddFooter", GSF_XML_CONTENT, NULL, &xlsx_CT_oddfooter_end),
3513 GSF_XML_IN_NODE_FULL (SHEET, ROW_BREAKS, XL_NS_SS, "rowBreaks", GSF_XML_NO_CONTENT,
3514 FALSE, FALSE, &xlsx_CT_PageBreaks_begin, &xlsx_CT_PageBreaks_end, 1),
3515 GSF_XML_IN_NODE (ROW_BREAKS, CT_PageBreak, XL_NS_SS, "brk", GSF_XML_NO_CONTENT, &xlsx_CT_PageBreak, NULL),
3516 GSF_XML_IN_NODE_FULL (SHEET, COL_BREAKS, XL_NS_SS, "colBreaks", GSF_XML_NO_CONTENT,
3517 FALSE, FALSE, &xlsx_CT_PageBreaks_begin, &xlsx_CT_PageBreaks_end, 0),
3518 GSF_XML_IN_NODE (COL_BREAKS, CT_PageBreak, XL_NS_SS, "brk", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
3520 GSF_XML_IN_NODE (SHEET, LEGACY_DRAW, XL_NS_SS, "legacyDrawing", GSF_XML_NO_CONTENT, &xlsx_sheet_legacy_drawing, NULL),
3521 GSF_XML_IN_NODE (SHEET, OLE_OBJECTS, XL_NS_SS, "oleObjects", GSF_XML_NO_CONTENT, NULL, NULL),
3522 GSF_XML_IN_NODE (OLE_OBJECTS, OLE_OBJECT, XL_NS_SS, "oleObject", GSF_XML_NO_CONTENT, &xlsx_ole_object, NULL),
3524 GSF_XML_IN_NODE_END
3527 /****************************************************************************/
3529 static void
3530 xlsx_CT_PivotCache (GsfXMLIn *xin, xmlChar const **attrs)
3532 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3533 xmlChar const *id = NULL;
3534 xmlChar const *cacheId = NULL;
3536 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3537 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3538 id = attrs[1];
3539 else if (0 == strcmp (attrs[0], "cacheId"))
3540 cacheId = attrs[1];
3542 if (NULL != id && NULL != cacheId) {
3543 g_return_if_fail (NULL == state->pivot.cache);
3545 xlsx_parse_rel_by_id (xin, id,
3546 xlsx_pivot_cache_def_dtd, xlsx_ns);
3548 g_return_if_fail (NULL != state->pivot.cache);
3550 /* absorb the reference to the cache */
3551 g_hash_table_replace (state->pivot.cache_by_id,
3552 g_strdup (cacheId), state->pivot.cache);
3553 state->pivot.cache = NULL;
3557 static void
3558 xlsx_CT_WorkbookPr (GsfXMLIn *xin, xmlChar const **attrs)
3560 static EnumVal const switchModes[] = {
3561 { "on", TRUE },
3562 { "1", TRUE },
3563 { "true", TRUE },
3564 { "off", FALSE },
3565 { "0", FALSE },
3566 { "false", FALSE },
3567 { NULL, 0 }
3569 int tmp;
3570 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3572 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3573 if (attr_enum (xin, attrs, "date1904", switchModes, &tmp))
3574 workbook_set_1904 (state->wb, tmp);
3577 static void
3578 xlsx_CT_CalcPr (GsfXMLIn *xin, xmlChar const **attrs)
3580 static EnumVal const calcModes[] = {
3581 { "manual", FALSE },
3582 { "auto", TRUE },
3583 { "autoNoTable", TRUE },
3584 { NULL, 0 }
3586 static EnumVal const refModes[] = {
3587 { "A1", TRUE },
3588 { "R1C1", FALSE },
3589 { NULL, 0 }
3591 int tmp;
3592 gnm_float delta;
3593 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3595 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3596 if (attr_enum (xin, attrs, "calcMode", calcModes, &tmp))
3597 workbook_set_recalcmode (state->wb, tmp);
3598 else if (attr_bool (xin, attrs, "fullCalcOnLoad", &tmp))
3600 else if (attr_enum (xin, attrs, "refMode", refModes, &tmp))
3602 else if (attr_bool (xin, attrs, "iterate", &tmp))
3603 workbook_iteration_enabled (state->wb, tmp);
3604 else if (attr_int (xin, attrs, "iterateCount", &tmp))
3605 workbook_iteration_max_number (state->wb, tmp);
3606 else if (attr_float (xin, attrs, "iterateDelta", &delta))
3607 workbook_iteration_tolerance (state->wb, delta);
3608 else if (attr_bool (xin, attrs, "fullPrecision", &tmp))
3610 else if (attr_bool (xin, attrs, "calcCompleted", &tmp))
3612 else if (attr_bool (xin, attrs, "calcOnSave", &tmp))
3614 else if (attr_bool (xin, attrs, "conncurrentCalc", &tmp))
3616 else if (attr_bool (xin, attrs, "forceFullCalc", &tmp))
3618 else if (attr_int (xin, attrs, "concurrentManualCalc", &tmp))
3622 static void
3623 xlsx_CT_workbookView (GsfXMLIn *xin, xmlChar const **attrs)
3625 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3626 int active_tab = -1;
3627 int width = -1, height = -1;
3628 const int scale = 10; /* Guess */
3630 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3631 if (attr_int (xin, attrs, "activeTab", &active_tab))
3633 else if (attr_int (xin, attrs, "windowHeight", &height))
3635 else if (attr_int (xin, attrs, "windowWidth", &width))
3639 if (width > scale / 2 && height > scale / 2)
3640 wb_view_preferred_size (state->wb_view,
3641 (width + scale / 2) / scale,
3642 (height + scale / 2) / scale);
3645 static void
3646 xlsx_sheet_begin (GsfXMLIn *xin, xmlChar const **attrs)
3648 static EnumVal const visibilities[] = {
3649 { "visible", GNM_SHEET_VISIBILITY_VISIBLE },
3650 { "hidden", GNM_SHEET_VISIBILITY_HIDDEN },
3651 { "veryHidden", GNM_SHEET_VISIBILITY_VERY_HIDDEN },
3652 { NULL, 0 }
3654 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3655 char const *name = NULL;
3656 char const *part_id = NULL;
3657 Sheet *sheet;
3658 int viz = (int)GNM_SHEET_VISIBILITY_VISIBLE;
3660 maybe_update_progress (xin);
3662 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3663 if (0 == strcmp (attrs[0], "name"))
3664 name = attrs[1];
3665 else if (attr_enum (xin, attrs, "state", visibilities, &viz))
3666 ; /* Nothing */
3667 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3668 part_id = attrs[1];
3670 if (NULL == name) {
3671 xlsx_warning (xin, _("Ignoring a sheet without a name"));
3672 return;
3675 sheet = workbook_sheet_by_name (state->wb, name);
3676 if (NULL == sheet) {
3677 sheet = sheet_new (state->wb, name, XLSX_MaxCol, XLSX_MaxRow);
3678 workbook_sheet_attach (state->wb, sheet);
3680 g_object_set (sheet, "visibility", viz, NULL);
3682 g_object_set_data_full (G_OBJECT (sheet), "_XLSX_RelID", g_strdup (part_id),
3683 (GDestroyNotify) g_free);
3686 static void
3687 xlsx_wb_name_begin (GsfXMLIn *xin, xmlChar const **attrs)
3689 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3690 const char *name = NULL;
3691 int sheet_idx = -1;
3693 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3694 if (0 == strcmp (attrs[0], "name"))
3695 name = attrs[1];
3696 else if (attr_int (xin, attrs, "localSheetId", &sheet_idx))
3697 ; /* Nothing */
3700 state->defined_name = g_strdup (name);
3701 state->defined_name_sheet =
3702 sheet_idx >= 0
3703 ? workbook_sheet_by_index (state->wb, sheet_idx)
3704 : NULL;
3707 static void
3708 xlsx_wb_name_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3710 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3711 GnmParsePos pp;
3712 Sheet *sheet = state->defined_name_sheet;
3713 GnmNamedExpr *nexpr;
3714 char *error_msg = NULL;
3716 g_return_if_fail (state->defined_name != NULL);
3718 parse_pos_init (&pp, state->wb, sheet, 0, 0);
3720 if (g_str_has_prefix (state->defined_name, "_xlnm.")) {
3721 gboolean editable = (0 == strcmp (state->defined_name + 6, "Sheet_Title"));
3722 nexpr = expr_name_add (&pp, state->defined_name + 6,
3723 gnm_expr_top_new_constant (value_new_empty ()),
3724 &error_msg, TRUE, NULL);
3725 nexpr->is_permanent = TRUE;
3726 nexpr->is_editable = editable;
3727 } else
3728 nexpr = expr_name_add (&pp, state->defined_name,
3729 gnm_expr_top_new_constant (value_new_empty ()),
3730 &error_msg, TRUE, NULL);
3732 if (nexpr) {
3733 state->delayed_names =
3734 g_list_prepend (state->delayed_names, sheet);
3735 state->delayed_names =
3736 g_list_prepend (state->delayed_names,
3737 g_strdup (xin->content->str));
3738 state->delayed_names =
3739 g_list_prepend (state->delayed_names, nexpr);
3740 } else {
3741 xlsx_warning (xin, _("Failed to define name: %s"), error_msg);
3742 g_free (error_msg);
3745 g_free (state->defined_name);
3746 state->defined_name = NULL;
3749 static void
3750 handle_delayed_names (GsfXMLIn *xin)
3752 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3753 GList *l;
3755 for (l = state->delayed_names; l; l = l->next->next->next) {
3756 GnmNamedExpr *nexpr = l->data;
3757 char *expr_str = l->next->data;
3758 Sheet *sheet = l->next->next->data;
3759 GnmExprTop const *texpr;
3760 GnmParsePos pp;
3762 parse_pos_init (&pp, state->wb, sheet, 0, 0);
3763 if (*expr_str == 0)
3764 texpr = gnm_expr_top_new_constant (value_new_error_REF (NULL));
3765 else
3766 texpr = xlsx_parse_expr (xin, expr_str, &pp);
3767 if (texpr) {
3768 expr_name_set_expr (nexpr, texpr);
3770 g_free (expr_str);
3773 g_list_free (state->delayed_names);
3774 state->delayed_names = NULL;
3777 static void
3778 xlsx_wb_names_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3780 handle_delayed_names (xin);
3784 /**************************************************************************************************/
3786 static void
3787 xlsx_read_external_book (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3789 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3790 GsfOpenPkgRel const *rel = gsf_open_pkg_lookup_rel_by_type
3791 (gsf_xml_in_get_input (xin),
3792 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/"
3793 "externalLink");
3794 if (rel == NULL)
3795 rel = gsf_open_pkg_lookup_rel_by_type
3796 (gsf_xml_in_get_input (xin),
3797 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/"
3798 "externalLinkPath");
3799 if (NULL != rel && gsf_open_pkg_rel_is_extern (rel))
3800 state->external_ref = xlsx_conventions_add_extern_ref (
3801 state->convs, gsf_open_pkg_rel_get_target (rel));
3802 else
3803 xlsx_warning (xin, _("Unable to resolve external relationship"));
3805 static void
3806 xlsx_read_external_book_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3808 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3809 state->external_ref = NULL;
3811 static void
3812 xlsx_read_external_sheetname (GsfXMLIn *xin, xmlChar const **attrs)
3814 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3815 if (state->external_ref)
3816 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3817 if (0 == strcmp (attrs[0], "val"))
3818 workbook_sheet_attach
3819 (state->external_ref,
3820 state->external_ref_sheet =
3821 sheet_new (state->external_ref, attrs[1], 256, 65536));
3823 static void
3824 xlsx_read_external_sheetname_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3826 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3827 state->external_ref_sheet = NULL;
3830 static GsfXMLInNode const xlsx_extern_dtd[] = {
3831 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3832 GSF_XML_IN_NODE_FULL (START, LINK, XL_NS_SS, "externalLink", GSF_XML_NO_CONTENT, TRUE, TRUE, xlsx_read_external_book, xlsx_read_external_book_end, 0),
3833 GSF_XML_IN_NODE (LINK, BOOK, XL_NS_SS, "externalBook", GSF_XML_NO_CONTENT, NULL, NULL),
3834 GSF_XML_IN_NODE (BOOK, SHEET_NAMES, XL_NS_SS, "sheetNames", GSF_XML_NO_CONTENT, NULL, NULL),
3835 GSF_XML_IN_NODE (SHEET_NAMES, SHEET_NAME, XL_NS_SS, "sheetName", GSF_XML_NO_CONTENT, xlsx_read_external_sheetname, xlsx_read_external_sheetname_end),
3836 GSF_XML_IN_NODE (BOOK, SHEET_DATASET, XL_NS_SS, "sheetDataSet", GSF_XML_NO_CONTENT, NULL, NULL),
3837 GSF_XML_IN_NODE (SHEET_DATASET, SHEET_DATA, XL_NS_SS, "sheetData", GSF_XML_NO_CONTENT, NULL, NULL),
3838 GSF_XML_IN_NODE (SHEET_DATA, ROW, XL_NS_SS, "row", GSF_XML_NO_CONTENT, NULL, NULL),
3839 GSF_XML_IN_NODE (ROW, CELL, XL_NS_SS, "cell", GSF_XML_NO_CONTENT, NULL, NULL),
3840 GSF_XML_IN_NODE (CELL, VAL, XL_NS_SS, "v", GSF_XML_NO_CONTENT, NULL, NULL),
3842 GSF_XML_IN_NODE_END
3845 static void
3846 xlsx_wb_external_ref (GsfXMLIn *xin, xmlChar const **attrs)
3848 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3849 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3850 xlsx_parse_rel_by_id (xin, attrs[1], xlsx_extern_dtd, xlsx_ns);
3853 /**************************************************************************************************/
3855 static void
3856 xlsx_comments_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3858 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3859 state->authors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
3862 static void
3863 xlsx_comments_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3865 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3866 g_ptr_array_unref (state->authors);
3867 state->authors = NULL;
3870 static void
3871 xlsx_comment_author_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3873 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3874 int i = strlen (xin->content->str);
3875 char *name = xin->content->str;
3876 /* remove any trailing white space */
3877 /* not sure this is correct, we might be careful about encoding */
3878 while (i > 0 && g_ascii_isspace (name[i-1]))
3879 i--;
3880 name = g_new (char, i + 1);
3881 memcpy (name, xin->content->str, i);
3882 name[i] = 0;
3883 g_ptr_array_add (state->authors, name);
3886 static void
3887 xlsx_comment_start (GsfXMLIn *xin, xmlChar const **attrs)
3889 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3890 SheetObject *so;
3891 GnmRange anchor_r;
3893 state->comment = g_object_new (cell_comment_get_type (), NULL);
3894 so = GNM_SO (state->comment);
3895 anchor_r = sheet_object_get_anchor (so)->cell_bound;
3897 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3898 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "ref"))
3899 range_parse (&anchor_r, attrs[1], gnm_sheet_get_size (state->sheet));
3900 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "authorId")) {
3901 unsigned id = atoi (attrs[1]);
3902 char const *name;
3903 if (id < state->authors->len) {
3904 name = g_ptr_array_index (state->authors, id);
3905 if (*name) /* do not set an empty name */
3906 g_object_set (state->comment, "author", name, NULL);
3910 cell_comment_set_pos (GNM_CELL_COMMENT (so), &anchor_r.start);
3911 state->r_text = g_string_new ("");
3914 static void
3915 xlsx_comment_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3917 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3918 char *text = g_string_free (state->r_text, FALSE);
3919 state->r_text = NULL;
3920 g_object_set (state->comment, "text", text, NULL);
3921 g_free (text);
3922 if (state->rich_attrs) {
3923 g_object_set (state->comment, "markup", state->rich_attrs, NULL);
3924 pango_attr_list_unref (state->rich_attrs);
3925 state->rich_attrs = NULL;
3927 sheet_object_set_sheet (GNM_SO (state->comment), state->sheet);
3928 g_object_unref (state->comment);
3929 state->comment = NULL;
3931 maybe_update_progress (xin);
3934 static void
3935 xlsx_r_text (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3937 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3938 g_string_append (state->r_text, xin->content->str);
3941 static GsfXMLInNode const xlsx_comments_dtd[] = {
3942 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3943 GSF_XML_IN_NODE_FULL (START, COMMENTS, XL_NS_SS, "comments", GSF_XML_NO_CONTENT, TRUE, TRUE, xlsx_comments_start, xlsx_comments_end, 0),
3944 GSF_XML_IN_NODE (COMMENTS, AUTHORS, XL_NS_SS, "authors", GSF_XML_NO_CONTENT, NULL, NULL),
3945 GSF_XML_IN_NODE (AUTHORS, AUTHOR, XL_NS_SS, "author", GSF_XML_CONTENT, NULL, xlsx_comment_author_end),
3946 GSF_XML_IN_NODE (COMMENTS, COMMENTLIST, XL_NS_SS, "commentList", GSF_XML_NO_CONTENT, NULL, NULL),
3947 GSF_XML_IN_NODE (COMMENTLIST, COMMENT, XL_NS_SS, "comment", GSF_XML_NO_CONTENT, xlsx_comment_start, xlsx_comment_end),
3948 GSF_XML_IN_NODE (COMMENT, TEXTITEM, XL_NS_SS, "text", GSF_XML_NO_CONTENT, NULL, NULL),
3949 GSF_XML_IN_NODE (TEXTITEM, TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_r_text),
3950 GSF_XML_IN_NODE (TEXTITEM, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
3951 RICH_TEXT_NODES,
3952 GSF_XML_IN_NODE (TEXTITEM, ITEM_PHONETIC_RUN, XL_NS_SS, "rPh", GSF_XML_NO_CONTENT, NULL, NULL),
3953 GSF_XML_IN_NODE (ITEM_PHONETIC_RUN, PHONETIC_TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, NULL),
3954 GSF_XML_IN_NODE (TEXTITEM, ITEM_PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
3956 GSF_XML_IN_NODE_END
3959 /**************************************************************************************************/
3961 static gint
3962 cb_by_zorder (gconstpointer a, gconstpointer b, gpointer data)
3964 GHashTable *zorder = data;
3965 int za = GPOINTER_TO_UINT (g_hash_table_lookup (zorder, a));
3966 int zb = GPOINTER_TO_UINT (g_hash_table_lookup (zorder, b));
3967 return zb - za; /* descending */
3971 static void
3972 xlsx_wb_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3974 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3975 int i, n = workbook_sheet_count (state->wb);
3976 char const *part_id;
3977 GnmStyle *style;
3978 GsfInput *sin, *cin;
3979 GError *err = NULL;
3981 end_update_progress (state);
3983 /* Load sheets after setting up the workbooks to give us time to create
3984 * all of them and parse names */
3985 for (i = 0 ; i < n ; i++, state->sheet = NULL) {
3986 char *message;
3987 int j, zoffset;
3988 GSList *l;
3990 if (NULL == (state->sheet = workbook_sheet_by_index (state->wb, i)))
3991 continue;
3992 if (NULL == (part_id = g_object_get_data (G_OBJECT (state->sheet), "_XLSX_RelID"))) {
3993 xlsx_warning (xin, _("Missing part-id for sheet '%s'"),
3994 state->sheet->name_unquoted);
3995 continue;
3998 /* Apply the 'Normal' style (aka builtin 0) to the entire sheet */
3999 if (NULL != (style = g_hash_table_lookup(state->cell_styles, "0"))) {
4000 GnmRange r;
4001 gnm_style_ref (style);
4002 range_init_full_sheet (&r, state->sheet);
4003 sheet_style_set_range (state->sheet, &r, style);
4006 sin = gsf_open_pkg_open_rel_by_id (gsf_xml_in_get_input (xin), part_id, &err);
4007 if (NULL != err) {
4008 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4009 go_io_warning (state->context, "%s", err->message);
4010 g_error_free (err);
4011 err = NULL;
4012 continue;
4014 /* load comments */
4016 cin = gsf_open_pkg_open_rel_by_type (sin,
4017 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", NULL);
4018 message = g_strdup_printf (_("Reading sheet '%s'..."), state->sheet->name_unquoted);
4019 start_update_progress (state, sin, message,
4020 0.3 + i*0.6/n, 0.3 + i*0.6/n + 0.5/n);
4021 g_free (message);
4022 xlsx_parse_stream (state, sin, xlsx_sheet_dtd);
4023 end_update_progress (state);
4025 if (cin != NULL) {
4026 start_update_progress (state, cin, _("Reading comments..."),
4027 0.3 + i*0.6/n + 0.5/n, 0.3 + i*0.6/n + 0.6/n);
4028 xlsx_parse_stream (state, cin, xlsx_comments_dtd);
4029 end_update_progress (state);
4032 zoffset = (g_slist_length (state->pending_objects) -
4033 g_hash_table_size (state->zorder));
4034 for (j = zoffset, l = state->pending_objects; l; l = l->next) {
4035 SheetObject *so = l->data;
4036 int z = GPOINTER_TO_UINT (g_hash_table_lookup (state->zorder, so));
4037 if (z >= 1)
4038 z += zoffset;
4039 else
4040 z = j--;
4041 g_hash_table_insert (state->zorder, so, GINT_TO_POINTER (z));
4043 state->pending_objects = g_slist_sort_with_data
4044 (state->pending_objects, cb_by_zorder, state->zorder);
4046 while (state->pending_objects) {
4047 SheetObject *obj = state->pending_objects->data;
4048 state->pending_objects = g_slist_delete_link (state->pending_objects,
4049 state->pending_objects);
4050 sheet_object_set_sheet (obj, state->sheet);
4051 g_object_unref (obj);
4054 /* Flag a respan here in case nothing else does */
4055 sheet_flag_recompute_spans (state->sheet);
4059 static void
4060 xlsx_webpub_begin (GsfXMLIn *xin, xmlChar const **attrs)
4062 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4063 if (strcmp (attrs[0], "characterSet") == 0) {
4064 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4065 state->version = ECMA_376_2008;
4069 static GsfXMLInNode const xlsx_workbook_dtd[] = {
4070 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4071 GSF_XML_IN_NODE_FULL (START, WORKBOOK, XL_NS_SS, "workbook", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, &xlsx_wb_end, 0),
4072 GSF_XML_IN_NODE (WORKBOOK, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
4073 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_SS, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
4074 GSF_XML_IN_NODE (WORKBOOK, VERSION, XL_NS_SS, "fileVersion", GSF_XML_NO_CONTENT, NULL, NULL),
4075 GSF_XML_IN_NODE (WORKBOOK, PROPERTIES, XL_NS_SS, "workbookPr", GSF_XML_NO_CONTENT, &xlsx_CT_WorkbookPr, NULL),
4076 GSF_XML_IN_NODE (WORKBOOK, CALC_PROPS, XL_NS_SS, "calcPr", GSF_XML_NO_CONTENT, &xlsx_CT_CalcPr, NULL),
4078 GSF_XML_IN_NODE (WORKBOOK, VIEWS, XL_NS_SS, "bookViews", GSF_XML_NO_CONTENT, NULL, NULL),
4079 GSF_XML_IN_NODE (VIEWS, VIEW, XL_NS_SS, "workbookView", GSF_XML_NO_CONTENT, &xlsx_CT_workbookView, NULL),
4080 GSF_XML_IN_NODE (WORKBOOK, CUSTOMWVIEWS, XL_NS_SS, "customWorkbookViews", GSF_XML_NO_CONTENT, NULL, NULL),
4081 GSF_XML_IN_NODE (CUSTOMWVIEWS, CUSTOMWVIEW , XL_NS_SS, "customWorkbookView", GSF_XML_NO_CONTENT, NULL, NULL),
4082 GSF_XML_IN_NODE (CUSTOMWVIEW, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd */
4083 GSF_XML_IN_NODE (WORKBOOK, SHEETS, XL_NS_SS, "sheets", GSF_XML_NO_CONTENT, NULL, NULL),
4084 GSF_XML_IN_NODE (SHEETS, SHEET, XL_NS_SS, "sheet", GSF_XML_NO_CONTENT, &xlsx_sheet_begin, NULL),
4085 GSF_XML_IN_NODE (WORKBOOK, FGROUPS, XL_NS_SS, "functionGroups", GSF_XML_NO_CONTENT, NULL, NULL),
4086 GSF_XML_IN_NODE (FGROUPS, FGROUP, XL_NS_SS, "functionGroup", GSF_XML_NO_CONTENT, NULL, NULL),
4087 GSF_XML_IN_NODE (WORKBOOK, WEB_PUB, XL_NS_SS, "webPublishing", GSF_XML_NO_CONTENT, xlsx_webpub_begin, NULL),
4088 GSF_XML_IN_NODE (WORKBOOK, EXTERNS, XL_NS_SS, "externalReferences", GSF_XML_NO_CONTENT, NULL, NULL),
4089 GSF_XML_IN_NODE (EXTERNS, EXTERN, XL_NS_SS, "externalReference", GSF_XML_NO_CONTENT, xlsx_wb_external_ref, NULL),
4090 GSF_XML_IN_NODE (WORKBOOK, NAMES, XL_NS_SS, "definedNames", GSF_XML_NO_CONTENT, NULL, xlsx_wb_names_end),
4091 GSF_XML_IN_NODE (NAMES, NAME, XL_NS_SS, "definedName", GSF_XML_CONTENT, xlsx_wb_name_begin, xlsx_wb_name_end),
4092 GSF_XML_IN_NODE (WORKBOOK, PIVOTCACHES, XL_NS_SS, "pivotCaches", GSF_XML_NO_CONTENT, NULL, NULL),
4093 GSF_XML_IN_NODE (PIVOTCACHES, PIVOTCACHE, XL_NS_SS, "pivotCache", GSF_XML_NO_CONTENT, &xlsx_CT_PivotCache, NULL),
4095 GSF_XML_IN_NODE (WORKBOOK, RECOVERY, XL_NS_SS, "fileRecoveryPr", GSF_XML_NO_CONTENT, NULL, NULL),
4096 GSF_XML_IN_NODE (WORKBOOK, OLESIZE, XL_NS_SS, "oleSize", GSF_XML_NO_CONTENT, NULL, NULL),
4097 GSF_XML_IN_NODE (WORKBOOK, SMARTTAGPR, XL_NS_SS, "smartTagPr", GSF_XML_NO_CONTENT, NULL, NULL),
4098 GSF_XML_IN_NODE (WORKBOOK, SMARTTTYPES, XL_NS_SS, "smartTagTypes", GSF_XML_NO_CONTENT, NULL, NULL),
4099 GSF_XML_IN_NODE (SMARTTTYPES, SMARTTTYPE, XL_NS_SS, "smartTagType", GSF_XML_NO_CONTENT, NULL, NULL),
4100 GSF_XML_IN_NODE (WORKBOOK, WEB_PUB_OBJS, XL_NS_SS, "webPublishObjects", GSF_XML_NO_CONTENT, NULL, NULL),
4101 GSF_XML_IN_NODE (WEB_PUB_OBJS, WEB_PUB_OBJ, XL_NS_SS, "webPublishObject", GSF_XML_NO_CONTENT, NULL, NULL),
4103 GSF_XML_IN_NODE_END
4106 /****************************************************************************/
4108 static void
4109 xlsx_sst_begin (GsfXMLIn *xin, xmlChar const **attrs)
4111 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4112 int count;
4114 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4115 if (attr_int (xin, attrs, "uniqueCount", &count))
4116 g_array_set_size (state->sst, count);
4117 state->count = 0;
4120 static void
4121 xlsx_sstitem_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4123 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4124 state->r_text = g_string_new ("");
4127 static void
4128 xlsx_sstitem_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4130 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4131 XLSXStr *entry;
4132 char *text = g_string_free (state->r_text, FALSE);
4133 state->r_text = NULL;
4135 if (state->count >= state->sst->len)
4136 g_array_set_size (state->sst, state->count+1);
4137 entry = &g_array_index (state->sst, XLSXStr, state->count);
4138 state->count++;
4139 entry->str = go_string_new_nocopy (text);
4141 if (state->rich_attrs) {
4142 entry->markup = go_format_new_markup (state->rich_attrs, FALSE);
4143 state->rich_attrs = NULL;
4147 static GsfXMLInNode const xlsx_shared_strings_dtd[] = {
4148 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4149 GSF_XML_IN_NODE_FULL (START, SST, XL_NS_SS, "sst", GSF_XML_NO_CONTENT, FALSE, TRUE, &xlsx_sst_begin, NULL, 0),
4150 GSF_XML_IN_NODE (SST, ITEM, XL_NS_SS, "si", GSF_XML_NO_CONTENT, &xlsx_sstitem_start, &xlsx_sstitem_end), /* beta2 */
4151 GSF_XML_IN_NODE (ITEM, TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_r_text),
4152 GSF_XML_IN_NODE (ITEM, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
4153 RICH_TEXT_NODES,
4154 GSF_XML_IN_NODE (ITEM, ITEM_PHONETIC_RUN, XL_NS_SS, "rPh", GSF_XML_NO_CONTENT, NULL, NULL),
4155 GSF_XML_IN_NODE (ITEM_PHONETIC_RUN, PHONETIC_TEXT, XL_NS_SS, "t", GSF_XML_SHARED_CONTENT, NULL, NULL),
4156 GSF_XML_IN_NODE (ITEM, ITEM_PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
4158 GSF_XML_IN_NODE_END
4161 /****************************************************************************/
4163 static void
4164 xlsx_numfmt_common (GsfXMLIn *xin, xmlChar const **attrs, gboolean apply)
4166 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4167 xmlChar const *fmt = NULL;
4168 xmlChar const *id = NULL;
4170 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4171 if (0 == strcmp (attrs[0], "numFmtId"))
4172 id = attrs[1];
4173 else if (0 == strcmp (attrs[0], "formatCode"))
4174 fmt = attrs[1];
4176 if (NULL != id && NULL != fmt) {
4177 GOFormat *gfmt = go_format_new_from_XL (fmt);
4178 if (apply)
4179 gnm_style_set_format (state->style_accum, gfmt);
4180 g_hash_table_replace (state->num_fmts, g_strdup (id), gfmt);
4184 static void
4185 xlsx_style_numfmt (GsfXMLIn *xin, xmlChar const **attrs)
4187 xlsx_numfmt_common (xin, attrs, FALSE);
4190 enum {
4191 XLSX_COLLECT_FONT,
4192 XLSX_COLLECT_FILLS,
4193 XLSX_COLLECT_BORDERS,
4194 XLSX_COLLECT_XFS,
4195 XLSX_COLLECT_STYLE_XFS,
4196 XLSX_COLLECT_DXFS,
4197 XLSX_COLLECT_TABLE_STYLES
4200 static void
4201 xlsx_collection_begin (GsfXMLIn *xin, xmlChar const **attrs)
4203 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4204 int count = 0;
4206 g_return_if_fail (NULL == state->collection);
4208 state->count = 0;
4209 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4210 if (attr_int (xin, attrs, "count", &count))
4212 state->collection = g_ptr_array_new ();
4213 g_ptr_array_set_size (state->collection, count);
4215 switch (xin->node->user_data.v_int) {
4216 case XLSX_COLLECT_FONT : state->fonts = state->collection; break;
4217 case XLSX_COLLECT_FILLS : state->fills = state->collection; break;
4218 case XLSX_COLLECT_BORDERS : state->borders = state->collection; break;
4219 case XLSX_COLLECT_XFS : state->xfs = state->collection; break;
4220 case XLSX_COLLECT_STYLE_XFS : state->style_xfs = state->collection; break;
4221 case XLSX_COLLECT_DXFS : state->dxfs = state->collection; break;
4222 case XLSX_COLLECT_TABLE_STYLES: state->table_styles = state->collection; break;
4226 static void
4227 xlsx_collection_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4229 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4231 /* resize just in case the count hint was wrong */
4232 g_ptr_array_set_size (state->collection, state->count);
4233 state->count = 0;
4234 state->collection = NULL;
4237 static void
4238 xlsx_col_elem_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4240 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4242 if (!state->style_accum_partial) {
4243 GnmStyle *res = state->style_accum;
4244 state->style_accum = NULL;
4245 if (state->count >= state->collection->len)
4246 g_ptr_array_add (state->collection, res);
4247 else if (NULL != g_ptr_array_index (state->collection, state->count)) {
4248 g_warning ("dup @ %d = %p", state->count, res);
4249 gnm_style_unref (res);
4250 } else
4251 g_ptr_array_index (state->collection, state->count) = res;
4252 state->count++;
4256 static void
4257 xlsx_col_elem_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4259 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4260 if (!state->style_accum_partial) {
4261 g_return_if_fail (NULL == state->style_accum);
4262 state->style_accum = gnm_style_new ();
4266 static void
4267 xlsx_col_border_begin (GsfXMLIn *xin, xmlChar const **attrs)
4269 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4270 gboolean diagonal_down = FALSE, diagonal_up = FALSE;
4272 xlsx_col_elem_begin (xin, attrs);
4273 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4274 if (attr_bool (xin, attrs, "diagonalDown", &diagonal_down)) ;
4275 else (attr_bool (xin, attrs, "diagonalUp", &diagonal_up)) ;
4277 if (diagonal_up) {
4278 GnmBorder *border = gnm_style_border_fetch
4279 (GNM_STYLE_BORDER_THIN, style_color_black (), GNM_STYLE_BORDER_DIAGONAL);
4280 gnm_style_set_border (state->style_accum,
4281 MSTYLE_BORDER_DIAGONAL,
4282 border);
4284 if (diagonal_down) {
4285 GnmBorder *border = gnm_style_border_fetch
4286 (GNM_STYLE_BORDER_HAIR, style_color_black (), GNM_STYLE_BORDER_DIAGONAL);
4287 gnm_style_set_border (state->style_accum,
4288 MSTYLE_BORDER_REV_DIAGONAL,
4289 border);
4293 static void
4294 xlsx_font_name (GsfXMLIn *xin, xmlChar const **attrs)
4296 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4298 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4299 if (0 == strcmp (attrs[0], "val"))
4300 gnm_style_set_font_name (state->style_accum, attrs[1]);
4302 static void
4303 xlsx_font_bold (GsfXMLIn *xin, xmlChar const **attrs)
4305 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4306 int val = TRUE;
4307 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4308 if (attr_bool (xin, attrs, "val", &val)) ;
4310 gnm_style_set_font_bold (state->style_accum, val);
4312 static void
4313 xlsx_font_italic (GsfXMLIn *xin, xmlChar const **attrs)
4315 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4316 int val = TRUE;
4317 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4318 if (attr_bool (xin, attrs, "val", &val)) ;
4320 gnm_style_set_font_italic (state->style_accum, val);
4322 static void
4323 xlsx_font_strike (GsfXMLIn *xin, xmlChar const **attrs)
4325 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4326 int val = TRUE;
4327 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4328 if (attr_bool (xin, attrs, "val", &val))
4330 gnm_style_set_font_strike (state->style_accum, val);
4332 static void
4333 xlsx_font_color (GsfXMLIn *xin, xmlChar const **attrs)
4335 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4336 /* LibreOffice 3.3.2 sets the alpha to 0, so text becomes invisible */
4337 /* (Excel drops the alpha too it seems.) */
4338 GnmColor *color = elem_color (xin, attrs, FALSE);
4339 if (NULL != color)
4340 gnm_style_set_font_color (state->style_accum, color);
4342 static void
4343 xlsx_CT_FontSize (GsfXMLIn *xin, xmlChar const **attrs)
4345 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4346 gnm_float val;
4348 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4349 if (attr_float (xin, attrs, "val", &val))
4350 gnm_style_set_font_size (state->style_accum, val);
4352 static void
4353 xlsx_CT_vertAlign (GsfXMLIn *xin, xmlChar const **attrs)
4355 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4356 static EnumVal const types[] = {
4357 { "subscript", GO_FONT_SCRIPT_SUB },
4358 { "baseline", GO_FONT_SCRIPT_STANDARD },
4359 { "superscript", GO_FONT_SCRIPT_SUPER },
4360 { NULL, 0 }
4362 int val = GO_FONT_SCRIPT_STANDARD;
4364 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4365 if (attr_enum (xin, attrs, "val", types, &val))
4366 ; /* Nothing */
4368 gnm_style_set_font_script (state->style_accum, val);
4370 static void
4371 xlsx_font_uline (GsfXMLIn *xin, xmlChar const **attrs)
4373 static EnumVal const types[] = {
4374 { "single", UNDERLINE_SINGLE },
4375 { "double", UNDERLINE_DOUBLE },
4376 { "singleAccounting", UNDERLINE_SINGLE_LOW },
4377 { "doubleAccounting", UNDERLINE_DOUBLE_LOW },
4378 { "none", UNDERLINE_NONE },
4379 { NULL, 0 }
4381 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4382 int val = UNDERLINE_SINGLE;
4384 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4385 if (attr_enum (xin, attrs, "val", types, &val))
4387 gnm_style_set_font_uline (state->style_accum, val);
4390 static void
4391 xlsx_font_valign (GsfXMLIn *xin, xmlChar const **attrs)
4393 static EnumVal const types[] = {
4394 { "baseline", GO_FONT_SCRIPT_STANDARD },
4395 { "superscript", GO_FONT_SCRIPT_SUPER },
4396 { "subscript", GO_FONT_SCRIPT_SUB },
4397 { NULL, 0 }
4399 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4400 int val = GO_FONT_SCRIPT_STANDARD;
4402 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4403 if (attr_enum (xin, attrs, "val", types, &val))
4404 gnm_style_set_font_script (state->style_accum, val);
4407 static void
4408 xlsx_pattern (GsfXMLIn *xin, xmlChar const **attrs)
4410 static EnumVal const patterns[] = {
4411 { "none", 0 },
4412 { "solid", 1 },
4413 { "mediumGray", 3 },
4414 { "darkGray", 2 },
4415 { "lightGray", 4 },
4416 { "darkHorizontal", 7 },
4417 { "darkVertical", 8 },
4418 { "darkDown", 10},
4419 { "darkUp", 9 },
4420 { "darkGrid", 11 },
4421 { "darkTrellis", 12 },
4422 { "lightHorizontal", 13 },
4423 { "lightVertical", 14 },
4424 { "lightDown", 15 },
4425 { "lightUp", 16 },
4426 { "lightGrid", 17 },
4427 { "lightTrellis", 18 },
4428 { "gray125", 5 },
4429 { "gray0625", 6 },
4430 { NULL, 0 }
4432 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4433 int val = 0; /* none */
4435 /* we are setting a default pattern of solid, see bug #702615 */
4436 /* Note that this conflicts with ECMA 376: "This element is used
4437 to specify cell fill information for pattern and solid color
4438 cell fills. For solid cell fills (no pattern), fgColor is used.
4439 For cell fills with patterns specified, then the cell fill color
4440 is specified by the bgColor element." */
4441 /* As the above bug report shows Excel 2010 creates: */
4442 /* <dxf><font><color rgb="FF9C0006"/></font><fill><patternFill>
4443 <bgColor rgb="FFFFC7CE"/></patternFill></fill></dxf> */
4445 gnm_style_set_pattern (state->style_accum, 1);
4447 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4448 if (attr_enum (xin, attrs, "patternType", patterns, &val))
4449 gnm_style_set_pattern (state->style_accum, val);
4451 static void
4452 xlsx_pattern_fg_bg (GsfXMLIn *xin, xmlChar const **attrs)
4454 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4455 gboolean solid_pattern = gnm_style_is_element_set (state->style_accum, MSTYLE_PATTERN)
4456 && (1 == gnm_style_get_pattern (state->style_accum));
4457 /* MAGIC :
4458 * Looks like pattern background and forground colours are inverted for
4459 * dxfs with solid fills for no apparent reason. */
4460 gboolean const invert = state->style_accum_partial
4461 && solid_pattern;
4462 /* LibreOffice 3.3.2 sets the alpha to 0, so solid fill becomes invisible */
4463 /* (Excel drops the alpha too it seems.) */
4464 GnmColor *color = elem_color (xin, attrs, !solid_pattern);
4465 if (NULL == color)
4466 return;
4468 if (xin->node->user_data.v_int ^ invert)
4469 gnm_style_set_back_color (state->style_accum, color);
4470 else
4471 gnm_style_set_pattern_color (state->style_accum, color);
4474 static void
4475 xlsx_CT_GradientFill (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4477 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4479 gnm_style_set_pattern (state->style_accum, 1);
4481 #if 0
4482 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4483 <xsd:attribute name="type" type="ST_GradientType" use="optional" default="linear">
4484 <xsd:attribute name="degree" type="xsd:double" use="optional" default="0">
4485 <xsd:attribute name="left" type="xsd:double" use="optional" default="0">
4486 <xsd:attribute name="right" type="xsd:double" use="optional" default="0">
4487 <xsd:attribute name="top" type="xsd:double" use="optional" default="0">
4488 <xsd:attribute name="bottom" type="xsd:double" use="optional" default="0">
4489 #endif
4492 static void
4493 xlsx_border_begin (GsfXMLIn *xin, xmlChar const **attrs)
4495 static EnumVal const borders[] = {
4496 { "none", GNM_STYLE_BORDER_NONE },
4497 { "thin", GNM_STYLE_BORDER_THIN },
4498 { "medium", GNM_STYLE_BORDER_MEDIUM },
4499 { "dashed", GNM_STYLE_BORDER_DASHED },
4500 { "dotted", GNM_STYLE_BORDER_DOTTED },
4501 { "thick", GNM_STYLE_BORDER_THICK },
4502 { "double", GNM_STYLE_BORDER_DOUBLE },
4503 { "hair", GNM_STYLE_BORDER_HAIR },
4504 { "mediumDashed", GNM_STYLE_BORDER_MEDIUM_DASH },
4505 { "dashDot", GNM_STYLE_BORDER_DASH_DOT },
4506 { "mediumDashDot", GNM_STYLE_BORDER_MEDIUM_DASH_DOT },
4507 { "dashDotDot", GNM_STYLE_BORDER_DASH_DOT_DOT },
4508 { "mediumDashDotDot", GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT },
4509 { "slantDashDot", GNM_STYLE_BORDER_SLANTED_DASH_DOT },
4510 { NULL, 0 }
4512 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4513 int border_style = GNM_STYLE_BORDER_NONE;
4515 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4516 if (attr_enum (xin, attrs, "style", borders, &border_style))
4518 state->border_style = border_style;
4519 state->border_color = NULL;
4522 static void
4523 xlsx_border_begin_v2 (GsfXMLIn *xin, xmlChar const **attrs)
4525 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4526 state->version = ECMA_376_2008;
4527 xlsx_border_begin (xin, attrs);
4530 static void
4531 xlsx_border_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4533 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4534 GnmBorder *border;
4535 GnmStyleBorderLocation const loc = xin->node->user_data.v_int;
4537 if (NULL == state->border_color)
4538 state->border_color = style_color_black ();
4539 border = gnm_style_border_fetch (state->border_style,
4540 state->border_color, gnm_style_border_get_orientation (loc));
4541 gnm_style_set_border (state->style_accum,
4542 GNM_STYLE_BORDER_LOCATION_TO_STYLE_ELEMENT (loc),
4543 border);
4544 state->border_color = NULL;
4547 static void
4548 xlsx_border_diagonal_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4550 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4551 GnmBorder *border, *new_border;
4553 if (NULL == state->border_color)
4554 state->border_color = style_color_black ();
4555 new_border = gnm_style_border_fetch
4556 (state->border_style, state->border_color, GNM_STYLE_BORDER_DIAGONAL);
4558 border = gnm_style_get_border (state->style_accum, MSTYLE_BORDER_REV_DIAGONAL);
4559 if (border != NULL && border->line_type != GNM_STYLE_BORDER_NONE) {
4560 gnm_style_border_ref (new_border);
4561 gnm_style_set_border (state->style_accum,
4562 MSTYLE_BORDER_REV_DIAGONAL,
4563 new_border);
4565 border = gnm_style_get_border (state->style_accum, MSTYLE_BORDER_DIAGONAL);
4566 if (border != NULL && border->line_type != GNM_STYLE_BORDER_NONE) {
4567 gnm_style_border_ref (new_border);
4568 gnm_style_set_border (state->style_accum,
4569 MSTYLE_BORDER_DIAGONAL,
4570 new_border);
4572 gnm_style_border_unref (new_border);
4573 state->border_color = NULL;
4576 static void
4577 xlsx_border_color (GsfXMLIn *xin, xmlChar const **attrs)
4579 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4580 GnmColor *color = elem_color (xin, attrs, TRUE);
4581 if (state->border_color)
4582 style_color_unref (state->border_color);
4583 state->border_color = color;
4586 static void
4587 xlsx_xf_begin (GsfXMLIn *xin, xmlChar const **attrs)
4589 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4590 GnmStyle *accum = gnm_style_new ();
4591 GnmStyle *parent = NULL;
4592 GnmStyle *result;
4593 GPtrArray *elem = NULL;
4594 int indx;
4596 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4597 if (0 == strcmp (attrs[0], "numFmtId")) {
4598 GOFormat *fmt = xlsx_get_num_fmt (xin, attrs[1]);
4599 if (NULL != fmt)
4600 gnm_style_set_format (accum, fmt);
4601 } else if (attr_int (xin, attrs, "fontId", &indx))
4602 elem = state->fonts;
4603 else if (attr_int (xin, attrs, "fillId", &indx))
4604 elem = state->fills;
4605 else if (attr_int (xin, attrs, "borderId", &indx))
4606 elem = state->borders;
4607 else if (attr_int (xin, attrs, "xfId", &indx))
4608 parent = xlsx_get_style_xf (xin, indx);
4610 if (NULL != elem) {
4611 GnmStyle const *component = NULL;
4612 if (0 <= indx && indx < (int)elem->len)
4613 component = g_ptr_array_index (elem, indx);
4614 if (NULL != component) {
4615 #if 0
4616 gnm_style_merge (accum, component);
4617 #else
4618 GnmStyle *merged = gnm_style_new_merged (accum, component);
4619 gnm_style_unref (accum);
4620 accum = merged;
4621 #endif
4622 } else
4623 xlsx_warning (xin, "Missing record '%d' for %s", indx, attrs[0]);
4624 elem = NULL;
4627 if (NULL == parent) {
4628 result = gnm_style_new_default ();
4629 gnm_style_merge (result, accum);
4630 } else
4631 result = gnm_style_new_merged (parent, accum);
4632 gnm_style_unref (accum);
4634 state->style_accum = result;
4635 #if 0
4636 "quotePrefix" ??
4638 "applyNumberFormat"
4639 "applyFont"
4640 "applyFill"
4641 "applyBorder"
4642 "applyAlignment"
4643 "applyProtection"
4644 #endif
4646 static void
4647 xlsx_xf_end (GsfXMLIn *xin, GsfXMLBlob *blob)
4649 xlsx_col_elem_end (xin, blob);
4652 static void
4653 xlsx_xf_align (GsfXMLIn *xin, xmlChar const **attrs)
4655 static EnumVal const haligns[] = {
4656 { "general" , GNM_HALIGN_GENERAL },
4657 { "left" , GNM_HALIGN_LEFT },
4658 { "center" , GNM_HALIGN_CENTER },
4659 { "right" , GNM_HALIGN_RIGHT },
4660 { "fill" , GNM_HALIGN_FILL },
4661 { "justify" , GNM_HALIGN_JUSTIFY },
4662 { "centerContinuous" , GNM_HALIGN_CENTER_ACROSS_SELECTION },
4663 { "distributed" , GNM_HALIGN_DISTRIBUTED },
4664 { NULL, 0 }
4667 static EnumVal const valigns[] = {
4668 { "top", GNM_VALIGN_TOP },
4669 { "center", GNM_VALIGN_CENTER },
4670 { "bottom", GNM_VALIGN_BOTTOM },
4671 { "justify", GNM_VALIGN_JUSTIFY },
4672 { "distributed", GNM_VALIGN_DISTRIBUTED },
4673 { NULL, 0 }
4676 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4677 int halign = GNM_HALIGN_GENERAL;
4678 int valign = GNM_VALIGN_BOTTOM;
4679 int rotation = 0, indent = 0;
4680 int wrapText = FALSE, justifyLastLine = FALSE, shrinkToFit = FALSE;
4682 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4683 if (attr_enum (xin, attrs, "horizontal", haligns, &halign)) ;
4684 else if (attr_enum (xin, attrs, "vertical", valigns, &valign)) ;
4685 else if (attr_int (xin, attrs, "textRotation", &rotation));
4686 else if (attr_bool (xin, attrs, "wrapText", &wrapText)) ;
4687 else if (attr_int (xin, attrs, "indent", &indent)) ;
4688 else if (attr_bool (xin, attrs, "justifyLastLine", &justifyLastLine)) ;
4689 else if (attr_bool (xin, attrs, "shrinkToFit", &shrinkToFit)) ;
4690 /* "mergeCell" type="xs:boolean" use="optional" default="false" */
4691 /* "readingOrder" type="xs:unsignedInt" use="optional" default="0" */
4693 gnm_style_set_align_h (state->style_accum, halign);
4694 gnm_style_set_align_v (state->style_accum, valign);
4695 gnm_style_set_rotation (state->style_accum,
4696 (rotation == 0xff) ? -1 : ((rotation > 90) ? (360 + 90 - rotation) : rotation));
4697 gnm_style_set_wrap_text (state->style_accum, wrapText);
4698 gnm_style_set_indent (state->style_accum, indent);
4699 gnm_style_set_shrink_to_fit (state->style_accum, shrinkToFit);
4701 static void
4702 xlsx_xf_protect (GsfXMLIn *xin, xmlChar const **attrs)
4704 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4705 int locked = TRUE;
4706 int hidden = TRUE;
4708 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4709 if (attr_bool (xin, attrs, "locked", &locked)) ;
4710 else if (attr_bool (xin, attrs, "hidden", &hidden)) ;
4711 gnm_style_set_contents_locked (state->style_accum, locked);
4712 gnm_style_set_contents_hidden (state->style_accum, hidden);
4715 static void
4716 xlsx_cell_style (GsfXMLIn *xin, xmlChar const **attrs)
4718 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4719 /* xmlChar const *name = NULL; */
4720 xmlChar const *id = NULL;
4721 GnmStyle *style = NULL;
4722 int tmp;
4724 /* cellStyle name="Normal" xfId="0" builtinId="0" */
4725 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4726 if (attr_int (xin, attrs, "xfId", &tmp))
4727 style = xlsx_get_style_xf (xin, tmp);
4728 else /* if (0 == strcmp (attrs[0], "name")) */
4729 /* name = attrs[1]; */
4730 /* else */ if (0 == strcmp (attrs[0], "builtinId"))
4731 id = attrs[1];
4733 if (NULL != style && NULL != id) {
4734 gnm_style_ref (style);
4735 g_hash_table_replace (state->cell_styles, g_strdup (id), style);
4739 static void
4740 xlsx_dxf_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4742 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4743 state->style_accum_partial = TRUE;
4744 state->style_accum = gnm_style_new ();
4746 static void
4747 xlsx_dxf_end (GsfXMLIn *xin, GsfXMLBlob *blob)
4749 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4750 state->style_accum_partial = FALSE;
4751 xlsx_col_elem_end (xin, blob);
4754 static void
4755 xlsx_dxf_numfmt (GsfXMLIn *xin, xmlChar const **attrs)
4757 xlsx_numfmt_common (xin, attrs, TRUE);
4761 static GsfXMLInNode const xlsx_styles_dtd[] = {
4762 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4763 GSF_XML_IN_NODE_FULL (START, STYLE_INFO, XL_NS_SS, "styleSheet", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4764 GSF_XML_IN_NODE (STYLE_INFO, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
4765 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_SS, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
4766 GSF_XML_IN_NODE (STYLE_INFO, NUM_FMTS, XL_NS_SS, "numFmts", GSF_XML_NO_CONTENT, NULL, NULL),
4767 GSF_XML_IN_NODE (NUM_FMTS, NUM_FMT, XL_NS_SS, "numFmt", GSF_XML_NO_CONTENT, &xlsx_style_numfmt, NULL),
4769 GSF_XML_IN_NODE_FULL (STYLE_INFO, FONTS, XL_NS_SS, "fonts", GSF_XML_NO_CONTENT,
4770 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_FONT),
4771 GSF_XML_IN_NODE (FONTS, FONT, XL_NS_SS, "font", GSF_XML_NO_CONTENT, &xlsx_col_elem_begin, &xlsx_col_elem_end),
4772 GSF_XML_IN_NODE (FONT, FONT_NAME, XL_NS_SS, "name", GSF_XML_NO_CONTENT, &xlsx_font_name, NULL),
4773 GSF_XML_IN_NODE (FONT, FONT_CHARSET, XL_NS_SS, "charset", GSF_XML_NO_CONTENT, NULL, NULL),
4774 GSF_XML_IN_NODE (FONT, FONT_FAMILY, XL_NS_SS, "family", GSF_XML_NO_CONTENT, NULL, NULL),
4775 GSF_XML_IN_NODE (FONT, FONT_BOLD, XL_NS_SS, "b", GSF_XML_NO_CONTENT, &xlsx_font_bold, NULL),
4776 GSF_XML_IN_NODE (FONT, FONT_ITALIC, XL_NS_SS, "i", GSF_XML_NO_CONTENT, &xlsx_font_italic, NULL),
4777 GSF_XML_IN_NODE (FONT, FONT_STRIKE, XL_NS_SS, "strike", GSF_XML_NO_CONTENT, &xlsx_font_strike, NULL),
4778 GSF_XML_IN_NODE (FONT, FONT_OUTLINE, XL_NS_SS, "outline", GSF_XML_NO_CONTENT, NULL, NULL),
4779 GSF_XML_IN_NODE (FONT, FONT_SHADOW, XL_NS_SS, "shadow", GSF_XML_NO_CONTENT, NULL, NULL),
4780 GSF_XML_IN_NODE (FONT, FONT_CONDENSE, XL_NS_SS, "condense", GSF_XML_NO_CONTENT, NULL, NULL),
4781 GSF_XML_IN_NODE (FONT, FONT_EXTEND, XL_NS_SS, "extend", GSF_XML_NO_CONTENT, NULL, NULL),
4782 GSF_XML_IN_NODE (FONT, FONT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_font_color, NULL),
4783 GSF_XML_IN_NODE (FONT, FONT_SZ, XL_NS_SS, "sz", GSF_XML_NO_CONTENT, &xlsx_CT_FontSize, NULL),
4784 GSF_XML_IN_NODE (FONT, FONT_SCRIPT, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, &xlsx_CT_vertAlign, NULL),
4785 GSF_XML_IN_NODE (FONT, FONT_ULINE, XL_NS_SS, "u", GSF_XML_NO_CONTENT, &xlsx_font_uline, NULL),
4786 GSF_XML_IN_NODE (FONT, FONT_VERTALIGN, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, &xlsx_font_valign, NULL),
4787 GSF_XML_IN_NODE (FONT, FONT_SCHEME, XL_NS_SS, "scheme", GSF_XML_NO_CONTENT, NULL, NULL),
4789 GSF_XML_IN_NODE_FULL (STYLE_INFO, FILLS, XL_NS_SS, "fills", GSF_XML_NO_CONTENT,
4790 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_FILLS),
4791 GSF_XML_IN_NODE (FILLS, FILL, XL_NS_SS, "fill", GSF_XML_NO_CONTENT, &xlsx_col_elem_begin, &xlsx_col_elem_end),
4792 GSF_XML_IN_NODE (FILL, PATTERN_FILL, XL_NS_SS, "patternFill", GSF_XML_NO_CONTENT, &xlsx_pattern, NULL),
4793 GSF_XML_IN_NODE_FULL (PATTERN_FILL, PATTERN_FILL_FG, XL_NS_SS, "fgColor", GSF_XML_NO_CONTENT,
4794 FALSE, FALSE, &xlsx_pattern_fg_bg, NULL, TRUE),
4795 GSF_XML_IN_NODE_FULL (PATTERN_FILL, PATTERN_FILL_BG, XL_NS_SS, "bgColor", GSF_XML_NO_CONTENT,
4796 FALSE, FALSE, &xlsx_pattern_fg_bg, NULL, FALSE),
4797 GSF_XML_IN_NODE (FILL, IMAGE_FILL, XL_NS_SS, "image", GSF_XML_NO_CONTENT, NULL, NULL),
4798 GSF_XML_IN_NODE (FILL, GRADIENT_FILL, XL_NS_SS, "gradientFill", GSF_XML_NO_CONTENT, &xlsx_CT_GradientFill, NULL),
4799 GSF_XML_IN_NODE (GRADIENT_FILL, GRADIENT_STOPS, XL_NS_SS, "stop", GSF_XML_NO_CONTENT, NULL, NULL),
4800 GSF_XML_IN_NODE_FULL (GRADIENT_STOPS, GRADIENT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, FALSE, FALSE, &xlsx_pattern_fg_bg, NULL, TRUE),
4802 GSF_XML_IN_NODE_FULL (STYLE_INFO, BORDERS, XL_NS_SS, "borders", GSF_XML_NO_CONTENT,
4803 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_BORDERS),
4804 GSF_XML_IN_NODE (BORDERS, BORDER, XL_NS_SS, "border", GSF_XML_NO_CONTENT, &xlsx_col_border_begin, &xlsx_col_elem_end),
4805 GSF_XML_IN_NODE_FULL (BORDER, LEFT_B, XL_NS_SS, "left", GSF_XML_NO_CONTENT, FALSE, FALSE,
4806 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_LEFT),
4807 GSF_XML_IN_NODE (LEFT_B, LEFT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4808 GSF_XML_IN_NODE_FULL (BORDER, START_B, XL_NS_SS, "start", GSF_XML_NO_CONTENT, FALSE, FALSE,
4809 &xlsx_border_begin_v2, &xlsx_border_end, GNM_STYLE_BORDER_LEFT),
4810 GSF_XML_IN_NODE (START_B, START_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4811 GSF_XML_IN_NODE_FULL (BORDER, RIGHT_B, XL_NS_SS, "right", GSF_XML_NO_CONTENT, FALSE, FALSE,
4812 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_RIGHT),
4813 GSF_XML_IN_NODE (RIGHT_B, RIGHT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4814 GSF_XML_IN_NODE_FULL (BORDER, END_B, XL_NS_SS, "end", GSF_XML_NO_CONTENT, FALSE, FALSE,
4815 &xlsx_border_begin_v2, &xlsx_border_end, GNM_STYLE_BORDER_RIGHT),
4816 GSF_XML_IN_NODE (END_B, END_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4817 GSF_XML_IN_NODE_FULL (BORDER, TOP_B, XL_NS_SS, "top", GSF_XML_NO_CONTENT, FALSE, FALSE,
4818 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_TOP),
4819 GSF_XML_IN_NODE (TOP_B, TOP_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4820 GSF_XML_IN_NODE_FULL (BORDER, BOTTOM_B, XL_NS_SS, "bottom", GSF_XML_NO_CONTENT, FALSE, FALSE,
4821 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_BOTTOM),
4822 GSF_XML_IN_NODE (BOTTOM_B, BOTTOM_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4823 GSF_XML_IN_NODE (BORDER, DIAG_B, XL_NS_SS, "diagonal", GSF_XML_NO_CONTENT,
4824 &xlsx_border_begin, &xlsx_border_diagonal_end),
4825 GSF_XML_IN_NODE (DIAG_B, DIAG_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4827 GSF_XML_IN_NODE (BORDER, BORDER_VERT, XL_NS_SS, "vertical", GSF_XML_NO_CONTENT, NULL, NULL),
4828 GSF_XML_IN_NODE (BORDER_VERT, VERT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
4829 GSF_XML_IN_NODE (BORDER, BORDER_HORIZ, XL_NS_SS, "horizontal", GSF_XML_NO_CONTENT, NULL, NULL),
4830 GSF_XML_IN_NODE (BORDER_HORIZ, HORIZ_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
4832 GSF_XML_IN_NODE_FULL (STYLE_INFO, XFS, XL_NS_SS, "cellXfs", GSF_XML_NO_CONTENT,
4833 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_XFS),
4834 GSF_XML_IN_NODE (XFS, XF, XL_NS_SS, "xf", GSF_XML_NO_CONTENT, &xlsx_xf_begin, &xlsx_xf_end),
4835 GSF_XML_IN_NODE (XF, ALIGNMENT, XL_NS_SS, "alignment", GSF_XML_NO_CONTENT, &xlsx_xf_align, NULL),
4836 GSF_XML_IN_NODE (XF, PROTECTION, XL_NS_SS, "protection", GSF_XML_NO_CONTENT, &xlsx_xf_protect, NULL),
4838 GSF_XML_IN_NODE_FULL (STYLE_INFO, STYLE_XFS, XL_NS_SS, "cellStyleXfs", GSF_XML_NO_CONTENT,
4839 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_STYLE_XFS),
4840 GSF_XML_IN_NODE (STYLE_XFS, STYLE_XF, XL_NS_SS, "xf", GSF_XML_NO_CONTENT, &xlsx_xf_begin, &xlsx_xf_end),
4841 GSF_XML_IN_NODE (STYLE_XF, STYLE_ALIGNMENT, XL_NS_SS, "alignment", GSF_XML_NO_CONTENT, &xlsx_xf_align, NULL),
4842 GSF_XML_IN_NODE (STYLE_XF, STYLE_PROTECTION, XL_NS_SS, "protection", GSF_XML_NO_CONTENT, &xlsx_xf_protect, NULL),
4844 GSF_XML_IN_NODE (STYLE_INFO, STYLE_NAMES, XL_NS_SS, "cellStyles", GSF_XML_NO_CONTENT, NULL, NULL),
4845 GSF_XML_IN_NODE (STYLE_NAMES, STYLE_NAME, XL_NS_SS, "cellStyle", GSF_XML_NO_CONTENT, &xlsx_cell_style, NULL),
4846 GSF_XML_IN_NODE (STYLE_NAME, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4847 GSF_XML_IN_NODE_FULL (STYLE_INFO, PARTIAL_XFS, XL_NS_SS, "dxfs", GSF_XML_NO_CONTENT,
4848 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_DXFS),
4849 GSF_XML_IN_NODE (PARTIAL_XFS, PARTIAL_XF, XL_NS_SS, "dxf", GSF_XML_NO_CONTENT, &xlsx_dxf_begin, &xlsx_dxf_end),
4850 GSF_XML_IN_NODE (PARTIAL_XF, DXF_NUM_FMT, XL_NS_SS, "numFmt", GSF_XML_NO_CONTENT, &xlsx_dxf_numfmt, NULL),
4851 GSF_XML_IN_NODE (PARTIAL_XF, FONT, XL_NS_SS, "font", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4852 GSF_XML_IN_NODE (PARTIAL_XF, FILL, XL_NS_SS, "fill", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4853 GSF_XML_IN_NODE (PARTIAL_XF, BORDER, XL_NS_SS, "border", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4854 GSF_XML_IN_NODE (PARTIAL_XF, DXF_ALIGNMENT, XL_NS_SS, "alignment", GSF_XML_NO_CONTENT, &xlsx_xf_align, NULL),
4855 GSF_XML_IN_NODE (PARTIAL_XF, DXF_PROTECTION, XL_NS_SS, "protection", GSF_XML_NO_CONTENT, &xlsx_xf_protect, NULL),
4856 GSF_XML_IN_NODE (PARTIAL_XF, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4858 GSF_XML_IN_NODE_FULL (STYLE_INFO, TABLE_STYLES, XL_NS_SS, "tableStyles", GSF_XML_NO_CONTENT,
4859 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_TABLE_STYLES),
4860 GSF_XML_IN_NODE (TABLE_STYLES, TABLE_STYLE, XL_NS_SS, "tableStyle", GSF_XML_NO_CONTENT, NULL, NULL),
4862 GSF_XML_IN_NODE (STYLE_INFO, COLORS, XL_NS_SS, "colors", GSF_XML_NO_CONTENT, NULL, NULL),
4863 GSF_XML_IN_NODE (COLORS, INDEXED_COLORS, XL_NS_SS, "indexedColors", GSF_XML_NO_CONTENT, NULL, NULL),
4864 GSF_XML_IN_NODE (INDEXED_COLORS, INDEXED_RGB, XL_NS_SS, "rgbColor", GSF_XML_NO_CONTENT, NULL, NULL),
4865 GSF_XML_IN_NODE (COLORS, THEME_COLORS, XL_NS_SS, "themeColors", GSF_XML_NO_CONTENT, NULL, NULL),
4866 GSF_XML_IN_NODE (THEME_COLORS, THEMED_RGB, XL_NS_SS, "rgbColor", GSF_XML_NO_CONTENT, NULL, NULL),
4867 GSF_XML_IN_NODE (COLORS, MRU_COLORS, XL_NS_SS, "mruColors", GSF_XML_NO_CONTENT, NULL, NULL),
4868 GSF_XML_IN_NODE (MRU_COLORS, MRU_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
4870 GSF_XML_IN_NODE_END
4873 /****************************************************************************/
4875 static void
4876 xlsx_theme_color_sys (GsfXMLIn *xin, xmlChar const **attrs)
4878 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4879 GOColor c;
4880 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4881 if (attr_gocolor (xin, attrs, "lastClr", &c)) {
4882 g_hash_table_replace (state->theme_colors_by_name,
4883 g_strdup (((GsfXMLInNode *)xin->node_stack->data)->name),
4884 GUINT_TO_POINTER (c));
4887 static void
4888 xlsx_theme_color_rgb (GsfXMLIn *xin, xmlChar const **attrs)
4890 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4891 GOColor c;
4892 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
4893 if (attr_gocolor (xin, attrs, "val", &c)) {
4894 g_hash_table_replace (state->theme_colors_by_name,
4895 g_strdup (((GsfXMLInNode *)xin->node_stack->data)->name),
4896 GUINT_TO_POINTER (c));
4900 static GsfXMLInNode const xlsx_theme_dtd[] = {
4901 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4902 GSF_XML_IN_NODE_FULL (START, THEME, XL_NS_DRAW, "theme", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4903 GSF_XML_IN_NODE (THEME, ELEMENTS, XL_NS_DRAW, "themeElements", GSF_XML_NO_CONTENT, NULL, NULL),
4904 GSF_XML_IN_NODE (ELEMENTS, COLOR_SCHEME, XL_NS_DRAW, "clrScheme", GSF_XML_NO_CONTENT, NULL, NULL),
4905 GSF_XML_IN_NODE (COLOR_SCHEME, dk1, XL_NS_DRAW, "dk1", GSF_XML_NO_CONTENT, NULL, NULL),
4906 GSF_XML_IN_NODE (dk1, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, &xlsx_theme_color_sys, NULL),
4907 GSF_XML_IN_NODE (dk1, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, &xlsx_theme_color_rgb, NULL),
4908 GSF_XML_IN_NODE (RGB_COLOR, COLOR_ALPHA, XL_NS_DRAW, "alpha", GSF_XML_NO_CONTENT, NULL, NULL),
4909 GSF_XML_IN_NODE (COLOR_SCHEME, lt1, XL_NS_DRAW, "lt1", GSF_XML_NO_CONTENT, NULL, NULL),
4910 GSF_XML_IN_NODE (lt1, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4911 GSF_XML_IN_NODE (lt1, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4912 GSF_XML_IN_NODE (COLOR_SCHEME, lt2, XL_NS_DRAW, "lt2", GSF_XML_NO_CONTENT, NULL, NULL),
4913 GSF_XML_IN_NODE (lt2, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4914 GSF_XML_IN_NODE (lt2, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4915 GSF_XML_IN_NODE (COLOR_SCHEME, dk2, XL_NS_DRAW, "dk2", GSF_XML_NO_CONTENT, NULL, NULL),
4916 GSF_XML_IN_NODE (dk2, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4917 GSF_XML_IN_NODE (dk2, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4918 GSF_XML_IN_NODE (COLOR_SCHEME, accent1, XL_NS_DRAW, "accent1", GSF_XML_NO_CONTENT, NULL, NULL),
4919 GSF_XML_IN_NODE (accent1, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4920 GSF_XML_IN_NODE (accent1, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4921 GSF_XML_IN_NODE (COLOR_SCHEME, accent2, XL_NS_DRAW, "accent2", GSF_XML_NO_CONTENT, NULL, NULL),
4922 GSF_XML_IN_NODE (accent2, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4923 GSF_XML_IN_NODE (accent2, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4924 GSF_XML_IN_NODE (COLOR_SCHEME, accent3, XL_NS_DRAW, "accent3", GSF_XML_NO_CONTENT, NULL, NULL),
4925 GSF_XML_IN_NODE (accent3, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4926 GSF_XML_IN_NODE (accent3, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4927 GSF_XML_IN_NODE (COLOR_SCHEME, accent4, XL_NS_DRAW, "accent4", GSF_XML_NO_CONTENT, NULL, NULL),
4928 GSF_XML_IN_NODE (accent4, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4929 GSF_XML_IN_NODE (accent4, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4930 GSF_XML_IN_NODE (COLOR_SCHEME, accent5, XL_NS_DRAW, "accent5", GSF_XML_NO_CONTENT, NULL, NULL),
4931 GSF_XML_IN_NODE (accent5, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4932 GSF_XML_IN_NODE (accent5, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4933 GSF_XML_IN_NODE (COLOR_SCHEME, accent6, XL_NS_DRAW, "accent6", GSF_XML_NO_CONTENT, NULL, NULL),
4934 GSF_XML_IN_NODE (accent6, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4935 GSF_XML_IN_NODE (accent6, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4936 GSF_XML_IN_NODE (COLOR_SCHEME, hlink, XL_NS_DRAW, "hlink", GSF_XML_NO_CONTENT, NULL, NULL),
4937 GSF_XML_IN_NODE (hlink, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4938 GSF_XML_IN_NODE (hlink, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4939 GSF_XML_IN_NODE (COLOR_SCHEME, folHlink, XL_NS_DRAW, "folHlink", GSF_XML_NO_CONTENT, NULL, NULL),
4940 GSF_XML_IN_NODE (folHlink, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4941 GSF_XML_IN_NODE (folHlink, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd Def */
4943 GSF_XML_IN_NODE (ELEMENTS, FONT_SCHEME, XL_NS_DRAW, "fontScheme", GSF_XML_NO_CONTENT, NULL, NULL),
4944 GSF_XML_IN_NODE (FONT_SCHEME, MAJOR_FONT, XL_NS_DRAW, "majorFont", GSF_XML_NO_CONTENT, NULL, NULL),
4945 GSF_XML_IN_NODE (MAJOR_FONT, FONT_CS, XL_NS_DRAW, "cs", GSF_XML_NO_CONTENT, NULL, NULL),
4946 GSF_XML_IN_NODE (MAJOR_FONT, FONT_EA, XL_NS_DRAW, "ea", GSF_XML_NO_CONTENT, NULL, NULL),
4947 GSF_XML_IN_NODE (MAJOR_FONT, FONT_FONT, XL_NS_DRAW, "font", GSF_XML_NO_CONTENT, NULL, NULL),
4948 GSF_XML_IN_NODE (MAJOR_FONT, FONT_LATIN, XL_NS_DRAW, "latin", GSF_XML_NO_CONTENT, NULL, NULL),
4949 GSF_XML_IN_NODE (FONT_SCHEME, MINOR_FONT, XL_NS_DRAW, "minorFont", GSF_XML_NO_CONTENT, NULL, NULL),
4950 GSF_XML_IN_NODE (MINOR_FONT, FONT_CS, XL_NS_DRAW, "cs", GSF_XML_NO_CONTENT, NULL, NULL),
4951 GSF_XML_IN_NODE (MINOR_FONT, FONT_EA, XL_NS_DRAW, "ea", GSF_XML_NO_CONTENT, NULL, NULL),
4952 GSF_XML_IN_NODE (MINOR_FONT, FONT_FONT, XL_NS_DRAW, "font", GSF_XML_NO_CONTENT, NULL, NULL),
4953 GSF_XML_IN_NODE (MINOR_FONT, FONT_LATIN, XL_NS_DRAW, "latin", GSF_XML_NO_CONTENT, NULL, NULL),
4955 GSF_XML_IN_NODE (ELEMENTS, FORMAT_SCHEME, XL_NS_DRAW, "fmtScheme", GSF_XML_NO_CONTENT, NULL, NULL),
4956 GSF_XML_IN_NODE (FORMAT_SCHEME, FILL_STYLE_LIST, XL_NS_DRAW, "fillStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
4957 GSF_XML_IN_NODE (FILL_STYLE_LIST, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_NO_CONTENT, NULL, NULL),
4958 GSF_XML_IN_NODE (SOLID_FILL, SCHEME_COLOR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),
4959 GSF_XML_IN_NODE (SCHEME_COLOR, COLOR_TINT, XL_NS_DRAW, "tint", GSF_XML_NO_CONTENT, NULL, NULL),
4960 GSF_XML_IN_NODE (SCHEME_COLOR, COLOR_LUM, XL_NS_DRAW, "lumMod", GSF_XML_NO_CONTENT, NULL, NULL),
4961 GSF_XML_IN_NODE (SCHEME_COLOR, COLOR_SAT, XL_NS_DRAW, "satMod", GSF_XML_NO_CONTENT, NULL, NULL),
4962 GSF_XML_IN_NODE (SCHEME_COLOR, COLOR_SHADE, XL_NS_DRAW, "shade", GSF_XML_NO_CONTENT, NULL, NULL),
4963 GSF_XML_IN_NODE (FILL_STYLE_LIST, GRAD_FILL, XL_NS_DRAW, "gradFill", GSF_XML_NO_CONTENT, NULL, NULL),
4964 GSF_XML_IN_NODE (GRAD_FILL, GRAD_PATH, XL_NS_DRAW, "path", GSF_XML_NO_CONTENT, NULL, NULL),
4965 GSF_XML_IN_NODE (GRAD_PATH, GRAD_PATH_RECT, XL_NS_DRAW, "fillToRect", GSF_XML_NO_CONTENT, NULL, NULL),
4966 GSF_XML_IN_NODE (GRAD_FILL, GRAD_LIST, XL_NS_DRAW, "gsLst", GSF_XML_NO_CONTENT, NULL, NULL),
4967 GSF_XML_IN_NODE (GRAD_LIST, GRAD_LIST_ITEM, XL_NS_DRAW, "gs", GSF_XML_NO_CONTENT, NULL, NULL),
4968 GSF_XML_IN_NODE (GRAD_LIST_ITEM, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4969 GSF_XML_IN_NODE (GRAD_LIST_ITEM, SCHEME_COLOR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4970 GSF_XML_IN_NODE (GRAD_FILL, GRAD_LINE, XL_NS_DRAW, "lin", GSF_XML_NO_CONTENT, NULL, NULL),
4972 GSF_XML_IN_NODE (FORMAT_SCHEME, BG_FILL_STYLE_LIST, XL_NS_DRAW, "bgFillStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
4973 GSF_XML_IN_NODE (BG_FILL_STYLE_LIST, GRAD_FILL, XL_NS_DRAW, "gradFill", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4974 GSF_XML_IN_NODE (BG_FILL_STYLE_LIST, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4975 GSF_XML_IN_NODE (FORMAT_SCHEME, LINE_STYLE_LIST, XL_NS_DRAW, "lnStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
4976 GSF_XML_IN_NODE (LINE_STYLE_LIST, LINE_STYLE, XL_NS_DRAW, "ln", GSF_XML_NO_CONTENT, NULL, NULL),
4977 GSF_XML_IN_NODE (LINE_STYLE, LN_NOFILL, XL_NS_DRAW, "noFill", GSF_XML_NO_CONTENT, NULL, NULL),
4978 GSF_XML_IN_NODE (LINE_STYLE, LN_DASH, XL_NS_DRAW, "prstDash", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4979 GSF_XML_IN_NODE (LINE_STYLE, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4980 GSF_XML_IN_NODE (LINE_STYLE, FILL_PATT, XL_NS_DRAW, "pattFill", GSF_XML_NO_CONTENT, NULL, NULL),
4981 GSF_XML_IN_NODE (FORMAT_SCHEME, EFFECT_STYLE_LIST, XL_NS_DRAW, "effectStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
4982 GSF_XML_IN_NODE (EFFECT_STYLE_LIST, EFFECT_STYLE, XL_NS_DRAW, "effectStyle", GSF_XML_NO_CONTENT, NULL, NULL),
4983 GSF_XML_IN_NODE (EFFECT_STYLE, EFFECT_PROP, XL_NS_DRAW, "sp3d", GSF_XML_NO_CONTENT, NULL, NULL),
4984 GSF_XML_IN_NODE (EFFECT_PROP, CONTOUR_CLR, XL_NS_DRAW, "contourClr", GSF_XML_NO_CONTENT, NULL, NULL),
4985 GSF_XML_IN_NODE (CONTOUR_CLR, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),
4986 GSF_XML_IN_NODE (EFFECT_PROP, PROP_BEVEL, XL_NS_DRAW, "bevelT", GSF_XML_NO_CONTENT, NULL, NULL),
4987 GSF_XML_IN_NODE (EFFECT_STYLE, EFFECT_LIST, XL_NS_DRAW, "effectLst", GSF_XML_NO_CONTENT, NULL, NULL),
4988 GSF_XML_IN_NODE (EFFECT_LIST, REFLECTION, XL_NS_DRAW, "reflection", GSF_XML_NO_CONTENT, NULL, NULL),
4989 GSF_XML_IN_NODE (EFFECT_LIST, OUTER_SHADOW, XL_NS_DRAW, "outerShdw", GSF_XML_NO_CONTENT, NULL, NULL),
4990 GSF_XML_IN_NODE (OUTER_SHADOW, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */
4991 GSF_XML_IN_NODE (EFFECT_STYLE, EFFECT_SCENE_3D, XL_NS_DRAW, "scene3d", GSF_XML_NO_CONTENT, NULL, NULL),
4992 GSF_XML_IN_NODE (EFFECT_SCENE_3D, 3D_CAMERA, XL_NS_DRAW, "camera", GSF_XML_NO_CONTENT, NULL, NULL),
4993 GSF_XML_IN_NODE (3D_CAMERA, 3D_ROT, XL_NS_DRAW, "rot", GSF_XML_NO_CONTENT, NULL, NULL),
4994 GSF_XML_IN_NODE (EFFECT_SCENE_3D, 3D_LIGHT, XL_NS_DRAW, "lightRig", GSF_XML_NO_CONTENT, NULL, NULL),
4995 GSF_XML_IN_NODE (3D_LIGHT, 3D_ROT, XL_NS_DRAW, "rot", GSF_XML_NO_CONTENT, NULL, NULL),
4997 GSF_XML_IN_NODE (THEME, OBJ_DEFAULTS, XL_NS_DRAW, "objectDefaults", GSF_XML_NO_CONTENT, NULL, NULL),
4998 GSF_XML_IN_NODE (OBJ_DEFAULTS, SP_DEF, XL_NS_DRAW, "spDef", GSF_XML_NO_CONTENT, NULL, NULL),
4999 GSF_XML_IN_NODE (SP_DEF, SHAPE_PR, XL_NS_DRAW, "spPr", GSF_XML_NO_CONTENT, NULL, NULL),
5000 GSF_XML_IN_NODE (SHAPE_PR, XFRM, XL_NS_DRAW, "xfrm", GSF_XML_NO_CONTENT, NULL, NULL),
5001 GSF_XML_IN_NODE (SHAPE_PR, CUST_GEOM, XL_NS_DRAW, "custGeom", GSF_XML_NO_CONTENT, NULL, NULL),
5002 GSF_XML_IN_NODE (SHAPE_PR, EXTLST, XL_NS_DRAW, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
5003 GSF_XML_IN_NODE (SHAPE_PR, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_NO_CONTENT, NULL, NULL),
5004 GSF_XML_IN_NODE (SP_DEF, BODY_PR, XL_NS_DRAW, "bodyPr", GSF_XML_NO_CONTENT, NULL, NULL),
5005 GSF_XML_IN_NODE (SP_DEF, LST_STYLE, XL_NS_DRAW, "lstStyle", GSF_XML_NO_CONTENT, NULL, NULL),
5006 GSF_XML_IN_NODE (SP_DEF, STYLE, XL_NS_DRAW, "style", GSF_XML_NO_CONTENT, NULL, NULL),
5007 GSF_XML_IN_NODE (STYLE, EFFECT_REF, XL_NS_DRAW, "effectRef", GSF_XML_NO_CONTENT, NULL, NULL),
5008 GSF_XML_IN_NODE (EFFECT_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_NO_CONTENT, NULL, NULL),
5009 GSF_XML_IN_NODE (EFFECT_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_NO_CONTENT, NULL, NULL),
5010 GSF_XML_IN_NODE (EFFECT_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),
5011 GSF_XML_IN_NODE (EFFECT_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_NO_CONTENT, NULL, NULL),
5012 GSF_XML_IN_NODE (EFFECT_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL),
5013 GSF_XML_IN_NODE (EFFECT_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL),
5014 GSF_XML_IN_NODE (STYLE, FILL_REF, XL_NS_DRAW, "fillRef", GSF_XML_NO_CONTENT, NULL, NULL),
5015 GSF_XML_IN_NODE (FILL_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5016 GSF_XML_IN_NODE (FILL_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5017 GSF_XML_IN_NODE (FILL_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5018 GSF_XML_IN_NODE (FILL_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5019 GSF_XML_IN_NODE (FILL_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5020 GSF_XML_IN_NODE (FILL_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5021 GSF_XML_IN_NODE (STYLE, FONT_REF, XL_NS_DRAW, "fontRef", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5022 GSF_XML_IN_NODE (FONT_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5023 GSF_XML_IN_NODE (FONT_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5024 GSF_XML_IN_NODE (FONT_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5025 GSF_XML_IN_NODE (FONT_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5026 GSF_XML_IN_NODE (FONT_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5027 GSF_XML_IN_NODE (FONT_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5028 GSF_XML_IN_NODE (STYLE, LN_REF, XL_NS_DRAW, "lnRef", GSF_XML_NO_CONTENT, NULL, NULL),
5029 GSF_XML_IN_NODE (LN_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5030 GSF_XML_IN_NODE (LN_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5031 GSF_XML_IN_NODE (LN_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5032 GSF_XML_IN_NODE (LN_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5033 GSF_XML_IN_NODE (LN_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5034 GSF_XML_IN_NODE (LN_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL),/* 2nd */
5035 GSF_XML_IN_NODE (SP_DEF, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd */
5036 GSF_XML_IN_NODE (OBJ_DEFAULTS, LN_DEF, XL_NS_DRAW, "lnDef", GSF_XML_NO_CONTENT, NULL, NULL),
5037 GSF_XML_IN_NODE (LN_DEF, BODY_PR, XL_NS_DRAW, "bodyPr", GSF_XML_NO_CONTENT, NULL, NULL),
5038 GSF_XML_IN_NODE (LN_DEF, LST_STYLE, XL_NS_DRAW, "lstStyle", GSF_XML_NO_CONTENT, NULL, NULL),
5039 GSF_XML_IN_NODE (LN_DEF, SP_PR, XL_NS_DRAW, "spPr", GSF_XML_NO_CONTENT, NULL, NULL),
5040 GSF_XML_IN_NODE (LN_DEF, STYLE, XL_NS_DRAW, "style", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd */
5041 GSF_XML_IN_NODE (LN_DEF, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd */
5042 GSF_XML_IN_NODE (OBJ_DEFAULTS, TX_DEF, XL_NS_DRAW, "txDef", GSF_XML_NO_CONTENT, NULL, NULL),
5043 GSF_XML_IN_NODE (OBJ_DEFAULTS, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd */
5044 GSF_XML_IN_NODE (THEME, EXTRA_COLOR_SCHEME, XL_NS_DRAW, "extraClrSchemeLst", GSF_XML_NO_CONTENT, NULL, NULL),
5046 GSF_XML_IN_NODE_END
5049 /****************************************************************************/
5051 G_MODULE_EXPORT gboolean
5052 xlsx_file_probe (GOFileOpener const *fo, GsfInput *input, GOFileProbeLevel pl);
5054 gboolean
5055 xlsx_file_probe (G_GNUC_UNUSED GOFileOpener const *fo, GsfInput *input, G_GNUC_UNUSED GOFileProbeLevel pl)
5057 GsfInfile *zip;
5058 GsfInput *stream;
5059 gboolean res = FALSE;
5061 if (NULL != (zip = gsf_infile_zip_new (input, NULL))) {
5062 if (NULL != (stream = gsf_infile_child_by_vname (zip, "xl", "workbook.xml", NULL))) {
5063 g_object_unref (stream);
5064 res = TRUE;
5066 g_object_unref (zip);
5068 return res;
5071 static void
5072 xlsx_style_array_free (GPtrArray *styles)
5074 if (styles != NULL) {
5075 unsigned i = styles->len;
5076 GnmStyle *style;
5077 while (i-- > 0)
5078 if (NULL != (style = g_ptr_array_index (styles, i)))
5079 gnm_style_unref (style);
5081 g_ptr_array_free (styles, TRUE);
5085 #include "xlsx-read-docprops.c"
5087 G_MODULE_EXPORT void
5088 xlsx_file_open (GOFileOpener const *fo, GOIOContext *context,
5089 WorkbookView *wb_view, GsfInput *input);
5091 void
5092 xlsx_file_open (G_GNUC_UNUSED GOFileOpener const *fo, GOIOContext *context,
5093 WorkbookView *wb_view, GsfInput *input)
5095 XLSXReadState state;
5096 GnmLocale *locale;
5098 memset (&state, 0, sizeof (XLSXReadState));
5099 state.version = ECMA_376_2006;
5100 state.context = context;
5101 state.wb_view = wb_view;
5102 state.wb = wb_view_get_workbook (wb_view);
5103 state.sheet = NULL;
5104 state.run_attrs = NULL;
5105 state.rich_attrs = NULL;
5106 state.sst = g_array_new (FALSE, TRUE, sizeof (XLSXStr));
5107 state.shared_exprs = g_hash_table_new_full (g_str_hash, g_str_equal,
5108 (GDestroyNotify)g_free, (GDestroyNotify) gnm_expr_top_unref);
5109 state.cell_styles = g_hash_table_new_full (g_str_hash, g_str_equal,
5110 (GDestroyNotify)g_free, (GDestroyNotify) gnm_style_unref);
5111 state.num_fmts = g_hash_table_new_full (g_str_hash, g_str_equal,
5112 (GDestroyNotify)g_free, (GDestroyNotify) go_format_unref);
5113 state.date_fmt = xlsx_pivot_date_fmt ();
5114 state.convs = xlsx_conventions_new (FALSE);
5115 state.theme_colors_by_name = g_hash_table_new_full (g_str_hash, g_str_equal,
5116 (GDestroyNotify)g_free, NULL);
5117 /* fill in some default colors (when theme is absent */
5118 g_hash_table_replace (state.theme_colors_by_name, g_strdup ("bg1"), GUINT_TO_POINTER (GO_COLOR_WHITE));
5119 state.pivot.cache_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
5120 (GDestroyNotify)g_free, (GDestroyNotify) g_object_unref);
5121 state.zorder = g_hash_table_new (g_direct_hash, g_direct_equal);
5123 locale = gnm_push_C_locale ();
5125 if (NULL != (state.zip = gsf_infile_zip_new (input, NULL))) {
5126 /* optional */
5127 GsfInput *wb_part = gsf_open_pkg_open_rel_by_type (GSF_INPUT (state.zip),
5128 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", NULL);
5130 if (NULL != wb_part) {
5131 GsfInput *in;
5133 in = gsf_open_pkg_open_rel_by_type (wb_part,
5134 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", NULL);
5135 if (in != NULL) {
5136 start_update_progress (&state, in, _("Reading shared strings..."),
5137 0., 0.05);
5138 xlsx_parse_stream (&state, in, xlsx_shared_strings_dtd);
5139 end_update_progress (&state);
5142 in = gsf_open_pkg_open_rel_by_type (wb_part,
5143 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", NULL);
5144 if (in) {
5145 start_update_progress (&state, in, _("Reading theme..."),
5146 0.05, 0.1);
5147 xlsx_parse_stream (&state, in, xlsx_theme_dtd);
5148 end_update_progress (&state);
5151 in = gsf_open_pkg_open_rel_by_type (wb_part,
5152 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", NULL);
5153 if (in != NULL) {
5154 start_update_progress (&state, in, _("Reading styles..."), 0.1, 0.2);
5155 xlsx_parse_stream (&state, in, xlsx_styles_dtd);
5156 end_update_progress (&state);
5159 start_update_progress (&state, wb_part, _("Reading workbook..."),
5160 0.2, 0.3);
5161 xlsx_parse_stream (&state, wb_part, xlsx_workbook_dtd);
5162 /* end_update_progress (&state); moved into xlsx_wb_end */
5163 /* MW 20111121: why? If parsing fails, I don't think that will ever be called. */
5165 xlsx_read_docprops (&state);
5167 } else
5168 go_cmd_context_error_import (GO_CMD_CONTEXT (context),
5169 _("No workbook stream found."));
5171 g_object_unref (state.zip);
5174 gnm_pop_C_locale (locale);
5176 if (NULL != state.sst) {
5177 unsigned i = state.sst->len;
5178 XLSXStr *entry;
5179 while (i-- > 0) {
5180 entry = &g_array_index (state.sst, XLSXStr, i);
5181 go_string_unref (entry->str);
5182 go_format_unref (entry->markup);
5184 g_array_free (state.sst, TRUE);
5186 g_hash_table_destroy (state.pivot.cache_by_id);
5187 xlsx_conventions_free (state.convs);
5188 go_format_unref (state.date_fmt);
5189 g_hash_table_destroy (state.num_fmts);
5190 g_hash_table_destroy (state.cell_styles);
5191 g_hash_table_destroy (state.shared_exprs);
5192 xlsx_style_array_free (state.fonts);
5193 xlsx_style_array_free (state.fills);
5194 xlsx_style_array_free (state.borders);
5195 xlsx_style_array_free (state.xfs);
5196 xlsx_style_array_free (state.style_xfs);
5197 xlsx_style_array_free (state.dxfs);
5198 xlsx_style_array_free (state.table_styles);
5199 g_hash_table_destroy (state.theme_colors_by_name);
5200 g_hash_table_destroy (state.zorder);
5201 value_release (state.val);
5202 if (state.texpr) gnm_expr_top_unref (state.texpr);
5203 if (state.comment) g_object_unref (state.comment);
5204 if (state.cur_style) g_object_unref (state.cur_style);
5206 workbook_set_saveinfo (state.wb, GO_FILE_FL_AUTO,
5207 go_file_saver_for_id ((state.version == ECMA_376_2006) ?
5208 "Gnumeric_Excel:xlsx" :
5209 "Gnumeric_Excel:xlsx2"));
5212 /* TODO * TODO * TODO
5214 * IMPROVE
5215 * - column widths : Don't use hard coded font size
5216 * - share colours
5217 * - conditional formats
5218 * : other condition types
5219 * : check binary operators
5221 * ".xlam", "application/vnd.ms-excel.addin.macroEnabled.12" ,
5222 * ".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12" ,
5223 * ".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12" ,
5224 * ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ,
5225 * ".xltm", "application/vnd.ms-excel.template.macroEnabled.12" ,
5226 * ".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"