Code cleanup
[gnumeric.git] / plugins / excel / xlsx-read.c
blob0bc9d5d6794a58f767accd7fd8e8cbd89841d86b
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 XLSX_AXIS_SER
114 } XLSXAxisType;
115 typedef struct {
116 char *id;
117 GogAxis *axis;
118 GSList *plots;
119 XLSXAxisType type;
120 GogObjectPosition compass;
121 GogAxisPosition cross;
122 char *cross_id;
123 gnm_float cross_value;
124 gboolean invert_axis;
125 double logbase;
127 double axis_elements[GOG_AXIS_ELEM_MAX_ENTRY];
128 guint8 axis_element_set[GOG_AXIS_ELEM_MAX_ENTRY];
130 gboolean deleted;
131 } XLSXAxisInfo;
133 typedef struct {
134 GsfInfile *zip;
136 int version;
138 GOIOContext *context; /* The IOcontext managing things */
139 WorkbookView *wb_view; /* View for the new workbook */
140 Workbook *wb; /* The new workbook */
142 Sheet *sheet; /* current sheet */
143 GnmCellPos pos; /* current cell */
144 XLSXValueType pos_type;
145 GnmValue *val;
146 GnmExprTop const *texpr;
147 GnmRange array;
148 char *shared_id;
149 GHashTable *shared_exprs;
150 GnmConventions *convs;
152 SheetView *sv; /* current sheetview */
154 GArray *sst;
156 GHashTable *num_fmts;
157 GOFormat *date_fmt;
158 GHashTable *cell_styles;
159 GPtrArray *fonts;
160 GPtrArray *fills;
161 GPtrArray *borders;
162 GPtrArray *xfs;
163 GPtrArray *style_xfs;
164 GPtrArray *dxfs;
165 GPtrArray *table_styles;
166 GnmStyle *style_accum;
167 gboolean style_accum_partial;
168 GnmStyleBorderType border_style;
169 GnmColor *border_color;
171 GHashTable *theme_colors_by_name;
173 GPtrArray *collection; /* utility for the shared collection handlers */
174 unsigned count;
175 XLSXPanePos pane_pos;
177 GnmStyleConditions *conditions;
178 GSList *cond_regions;
179 GnmStyleCond *cond;
181 GnmFilter *filter;
182 int filter_cur_field;
183 GSList *filter_items; /* an accumulator */
185 GSList *validation_regions;
186 GnmValidation *validation;
187 GnmInputMsg *input_msg;
189 GnmPageBreaks *page_breaks;
191 /* Rows/Cols state */
192 GnmStyle *pending_rowcol_style;
193 GnmRange pending_rowcol_range;
195 /* Drawing state */
196 SheetObject *so;
197 gint64 drawing_pos[8];
198 int drawing_pos_flags;
199 GODrawingAnchorDir so_direction;
200 GnmSOAnchorMode so_anchor_mode;
201 GnmExprTop const *link_texpr;
203 /* Legacy drawing state */
204 double grp_offset[4];
205 GSList *grp_stack;
207 /* Charting state */
208 GogGraph *graph;
209 GogChart *chart;
210 GogPlot *plot;
211 GogSeries *series;
212 int dim_type;
213 GogObject *series_pt;
214 gboolean series_pt_has_index;
215 GOStyle *cur_style;
216 int gradient_count;
217 guint32 chart_color_state;
218 GOColor color;
219 GOMarker *marker;
220 GogObject *cur_obj;
221 GSList *obj_stack;
222 GSList *style_stack;
223 unsigned int sp_type;
224 char *chart_tx;
225 gboolean inhibit_text_pop;
226 gnm_float chart_pos[4]; /* x, w, y, h */
227 gboolean chart_pos_mode[4]; /* false: "factor", true: "edge" */
228 gboolean chart_pos_target; /* true if "inner" */
229 int radio_value;
230 int zindex;
232 struct {
233 GogAxis *obj;
234 int type;
235 GHashTable *by_id;
236 GHashTable *by_obj;
237 XLSXAxisInfo *info;
238 } axis;
240 char *defined_name;
241 Sheet *defined_name_sheet;
242 GList *delayed_names;
244 GSList *pending_objects;
245 GHashTable *zorder;
247 /* external refs */
248 Workbook *external_ref;
249 Sheet *external_ref_sheet;
251 /* Pivot state */
252 struct {
253 GnmSheetSlicer *slicer;
254 GODataSlicerField *slicer_field;
256 GHashTable *cache_by_id;
257 GODataCache *cache;
258 GODataCacheSource *cache_src;
259 GODataCacheField *cache_field;
260 GPtrArray *cache_field_values;
262 unsigned int field_count, record_count;
263 char *cache_record_part_id;
264 } pivot;
266 /* Comment state */
267 GPtrArray *authors;
268 GObject *comment;
270 /* Document Properties */
271 GsfDocMetaData *metadata;
272 char *meta_prop_name;
274 /* Rich Text handling */
275 GString *r_text;
276 PangoAttrList *rich_attrs;
277 PangoAttrList *run_attrs;
278 } XLSXReadState;
279 typedef struct {
280 GOString *str;
281 GOFormat *markup;
282 } XLSXStr;
284 static GsfXMLInNS const xlsx_ns[] = {
285 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.openxmlformats.org/spreadsheetml/2006/main"), /* Office 12 */
286 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.openxmlformats.org/spreadsheetml/2006/7/main"), /* Office 12 BETA-2 Technical Refresh */
287 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.openxmlformats.org/spreadsheetml/2006/5/main"), /* Office 12 BETA-2 */
288 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.microsoft.com/office/excel/2006/2"), /* Office 12 BETA-1 Technical Refresh */
289 GSF_XML_IN_NS (XL_NS_SS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"), /* Office 12 BETA-2 */
290 GSF_XML_IN_NS (XL_NS_SS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/3/spreadsheetDrawing"), /* Office 12 BETA-2 Technical Refresh */
291 GSF_XML_IN_NS (XL_NS_CHART, "http://schemas.openxmlformats.org/drawingml/2006/3/chart"), /* Office 12 BETA-2 */
292 GSF_XML_IN_NS (XL_NS_CHART, "http://schemas.openxmlformats.org/drawingml/2006/chart"), /* Office 12 BETA-2 Technical Refresh */
293 GSF_XML_IN_NS (XL_NS_CHART_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"),
294 GSF_XML_IN_NS (XL_NS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/3/main"), /* Office 12 BETA-2 */
295 GSF_XML_IN_NS (XL_NS_DRAW, "http://schemas.openxmlformats.org/drawingml/2006/main"), /* Office 12 BETA-2 Technical Refresh */
296 GSF_XML_IN_NS (XL_NS_GNM_EXT, "http://www.gnumeric.org/ext/spreadsheetml"),
297 GSF_XML_IN_NS (XL_NS_DOC_REL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships"),
298 GSF_XML_IN_NS (XL_NS_PKG_REL, "http://schemas.openxmlformats.org/package/2006/relationships"),
299 GSF_XML_IN_NS (XL_NS_LEG_OFF, "urn:schemas-microsoft-com:office:office"),
300 GSF_XML_IN_NS (XL_NS_LEG_XL, "urn:schemas-microsoft-com:office:excel"),
301 GSF_XML_IN_NS (XL_NS_LEG_VML, "urn:schemas-microsoft-com:vml"),
302 GSF_XML_IN_NS (XL_NS_PROP_CP, "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"),
303 GSF_XML_IN_NS (XL_NS_PROP_DC, "http://purl.org/dc/elements/1.1/"),
304 GSF_XML_IN_NS (XL_NS_PROP_DCMITYPE, "http://purl.org/dc/dcmitype"),
305 GSF_XML_IN_NS (XL_NS_PROP_DCTERMS, "http://purl.org/dc/terms/"),
306 GSF_XML_IN_NS (XL_NS_PROP_XSI, "http://www.w3.org/2001/XMLSchema-instance"),
307 GSF_XML_IN_NS (XL_NS_PROP, "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"),
308 GSF_XML_IN_NS (XL_NS_PROP_VT, "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"),
309 GSF_XML_IN_NS (XL_NS_PROP_CUSTOM, "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"),
310 { NULL, 0 }
313 typedef struct {
314 int code;
315 gdouble width;
316 gdouble height;
317 GtkUnit unit;
318 gchar const *name;
319 } XLSXPaperDefs;
322 static Sheet *
323 wrap_sheet_new (Workbook *wb, char const *name, int columns, int rows)
325 Sheet *sheet = sheet_new_with_type (wb, name, GNM_SHEET_DATA, columns, rows);
326 GnmPrintInformation *pi = sheet->print_info;
328 // Force a load of defaults here.
329 gnm_print_info_load_defaults (pi);
331 // We have different defaults for header and footer (namely blank)
332 xls_header_footer_import (&pi->header, NULL);
333 xls_header_footer_import (&pi->footer, NULL);
335 return sheet;
339 static void
340 maybe_update_progress (GsfXMLIn *xin)
342 XLSXReadState *state = (XLSXReadState *)xin->user_state;
343 GsfInput *input = gsf_xml_in_get_input (xin);
344 gsf_off_t pos = gsf_input_tell (input);
346 go_io_value_progress_update (state->context, pos);
349 static void
350 start_update_progress (XLSXReadState *state, GsfInput *xin,
351 char const *message, double min, double max)
353 go_io_progress_range_push (state->context, min, max);
354 if (xin) {
355 go_io_value_progress_set (state->context,
356 gsf_input_size (xin), 10000);
357 go_io_progress_message (state->context, message);
361 static void
362 end_update_progress (XLSXReadState *state)
364 go_io_progress_range_pop (state->context);
367 static gboolean
368 xlsx_parse_stream (XLSXReadState *state, GsfInput *in, GsfXMLInNode const *dtd)
370 gboolean success = FALSE;
372 if (NULL != in) {
373 GsfXMLInDoc *doc = gsf_xml_in_doc_new (dtd, xlsx_ns);
375 success = gsf_xml_in_doc_parse (doc, in, state);
377 if (!success)
378 go_io_warning (state->context,
379 _("'%s' is corrupt!"),
380 gsf_input_name (in));
382 gsf_xml_in_doc_free (doc);
383 g_object_unref (in);
385 return success;
388 static void
389 xlsx_parse_rel_by_id (GsfXMLIn *xin, char const *part_id,
390 GsfXMLInNode const *dtd,
391 GsfXMLInNS const *ns)
393 GError *err;
394 gboolean debug = gnm_debug_flag ("xlsx-parsing");
396 if (debug)
397 g_printerr ("{ /* Parsing : %s :: %s */\n",
398 gsf_input_name (gsf_xml_in_get_input (xin)), part_id);
400 err = gsf_open_pkg_parse_rel_by_id (xin, part_id, dtd, ns);
401 if (NULL != err) {
402 XLSXReadState *state = (XLSXReadState *)xin->user_state;
403 go_io_warning (state->context, "%s", err->message);
404 g_error_free (err);
407 if (debug)
408 g_printerr ("} /* DONE : %s :: %s */\n",
409 gsf_input_name (gsf_xml_in_get_input (xin)), part_id);
412 /****************************************************************************/
414 static gboolean xlsx_warning (GsfXMLIn *xin, char const *fmt, ...)
415 G_GNUC_PRINTF (2, 3);
417 static gboolean
418 xlsx_warning (GsfXMLIn *xin, char const *fmt, ...)
420 XLSXReadState *state = (XLSXReadState *)xin->user_state;
421 char *msg;
422 va_list args;
424 va_start (args, fmt);
425 msg = g_strdup_vprintf (fmt, args);
426 va_end (args);
428 if (IS_SHEET (state->sheet)) {
429 char *tmp;
430 if (state->pos.col >= 0 && state->pos.row >= 0)
431 tmp = g_strdup_printf ("%s!%s : %s",
432 state->sheet->name_quoted,
433 cellpos_as_string (&state->pos), msg);
434 else
435 tmp = g_strdup_printf ("%s : %s",
436 state->sheet->name_quoted, msg);
437 g_free (msg);
438 msg = tmp;
441 go_io_warning (state->context, "%s", msg);
442 g_printerr ("%s\n", msg);
443 g_free (msg);
445 return FALSE; /* convenience */
448 typedef struct {
449 char const * const name;
450 int val;
451 } EnumVal;
453 static gboolean
454 attr_enum (GsfXMLIn *xin, xmlChar const **attrs,
455 char const *target, EnumVal const *enums,
456 int *res)
458 g_return_val_if_fail (attrs != NULL, FALSE);
459 g_return_val_if_fail (attrs[0] != NULL, FALSE);
460 g_return_val_if_fail (attrs[1] != NULL, FALSE);
462 if (strcmp (attrs[0], target))
463 return FALSE;
465 for (; enums->name != NULL ; enums++)
466 if (!strcmp (enums->name, attrs[1])) {
467 *res = enums->val;
468 return TRUE;
470 return xlsx_warning (xin,
471 _("Unknown enum value '%s' for attribute %s"),
472 attrs[1], target);
476 * Take an _int_ as a result to allow the caller to use -1 as an undefined state.
478 static gboolean
479 attr_bool (G_GNUC_UNUSED GsfXMLIn *xin, xmlChar const **attrs,
480 char const *target,
481 int *res)
483 g_return_val_if_fail (attrs != NULL, FALSE);
484 g_return_val_if_fail (attrs[0] != NULL, FALSE);
485 g_return_val_if_fail (attrs[1] != NULL, FALSE);
487 if (strcmp (attrs[0], target))
488 return FALSE;
490 *res = (0 == strcmp (attrs[1], "1") || 0 == strcmp (attrs[1], "true")) ;
492 return TRUE;
495 static gboolean
496 attr_int (GsfXMLIn *xin, xmlChar const **attrs,
497 char const *target,
498 int *res)
500 char *end;
501 long tmp;
503 g_return_val_if_fail (attrs != NULL, FALSE);
504 g_return_val_if_fail (attrs[0] != NULL, FALSE);
505 g_return_val_if_fail (attrs[1] != NULL, FALSE);
507 if (strcmp (attrs[0], target))
508 return FALSE;
510 errno = 0;
511 tmp = strtol (attrs[1], &end, 10);
512 if (errno == ERANGE || tmp > G_MAXINT || tmp < G_MININT)
513 return xlsx_warning (xin,
514 _("Integer '%s' is out of range, for attribute %s"),
515 attrs[1], target);
516 if (*end)
517 return xlsx_warning (xin,
518 _("Invalid integer '%s' for attribute %s"),
519 attrs[1], target);
521 *res = tmp;
522 return TRUE;
525 static gboolean
526 attr_uint (GsfXMLIn *xin, xmlChar const **attrs,
527 char const *target, unsigned *res)
529 char *end;
530 unsigned long tmp;
532 g_return_val_if_fail (attrs != NULL, FALSE);
533 g_return_val_if_fail (attrs[0] != NULL, FALSE);
534 g_return_val_if_fail (attrs[1] != NULL, FALSE);
536 if (strcmp (attrs[0], target))
537 return FALSE;
539 errno = 0;
540 tmp = strtoul (attrs[1], &end, 10);
541 if (errno == ERANGE || tmp != (unsigned)tmp)
542 return xlsx_warning (xin,
543 _("Unsigned integer '%s' is out of range, for attribute %s"),
544 attrs[1], target);
545 if (*end)
546 return xlsx_warning (xin,
547 _("Invalid unsigned integer '%s' for attribute %s"),
548 attrs[1], target);
550 *res = tmp;
551 return TRUE;
554 static gboolean
555 attr_int64 (GsfXMLIn *xin, xmlChar const **attrs,
556 char const *target,
557 gint64 *res)
559 char *end;
560 gint64 tmp;
562 g_return_val_if_fail (attrs != NULL, FALSE);
563 g_return_val_if_fail (attrs[0] != NULL, FALSE);
564 g_return_val_if_fail (attrs[1] != NULL, FALSE);
566 if (strcmp (attrs[0], target))
567 return FALSE;
569 errno = 0;
570 tmp = g_ascii_strtoll (attrs[1], &end, 10);
571 if (errno == ERANGE)
572 return xlsx_warning (xin,
573 _("Integer '%s' is out of range, for attribute %s"),
574 attrs[1], target);
575 if (*end)
576 return xlsx_warning (xin,
577 _("Invalid integer '%s' for attribute %s"),
578 attrs[1], target);
580 *res = tmp;
581 return TRUE;
584 static gboolean
585 attr_gocolor (GsfXMLIn *xin, xmlChar const **attrs,
586 char const *target,
587 GOColor *res)
589 char *end;
590 unsigned long rgb;
592 g_return_val_if_fail (attrs != NULL, FALSE);
593 g_return_val_if_fail (attrs[0] != NULL, FALSE);
594 g_return_val_if_fail (attrs[1] != NULL, FALSE);
596 if (strcmp (attrs[0], target))
597 return FALSE;
599 errno = 0;
600 rgb = strtoul (attrs[1], &end, 16);
601 if (errno == ERANGE || *end)
602 return xlsx_warning (xin,
603 _("Invalid RRGGBB color '%s' for attribute %s"),
604 attrs[1], target);
607 guint8 const r = (rgb >> 16) & 0xff;
608 guint8 const g = (rgb >> 8) & 0xff;
609 guint8 const b = (rgb >> 0) & 0xff;
610 *res = GO_COLOR_FROM_RGB (r, g, b);
613 return TRUE;
616 static gboolean
617 attr_float (GsfXMLIn *xin, xmlChar const **attrs,
618 char const *target,
619 gnm_float *res)
621 char *end;
622 double tmp;
624 g_return_val_if_fail (attrs != NULL, FALSE);
625 g_return_val_if_fail (attrs[0] != NULL, FALSE);
626 g_return_val_if_fail (attrs[1] != NULL, FALSE);
628 if (strcmp (attrs[0], target))
629 return FALSE;
631 tmp = gnm_strto (attrs[1], &end);
632 if (*end)
633 return xlsx_warning (xin,
634 _("Invalid number '%s' for attribute %s"),
635 attrs[1], target);
636 *res = tmp;
637 return TRUE;
641 * Either an integer scaled so 100000 means 100%, or something like "50%"
642 * which we'll return as 50*1000.
644 * The first seems off-spec, but is what Excel produces.
646 static gboolean
647 attr_percent (GsfXMLIn *xin, xmlChar const **attrs,
648 char const *target, int *res)
650 char *end;
651 long tmp;
653 g_return_val_if_fail (attrs != NULL, FALSE);
654 g_return_val_if_fail (attrs[0] != NULL, FALSE);
655 g_return_val_if_fail (attrs[1] != NULL, FALSE);
657 if (strcmp (attrs[0], target))
658 return FALSE;
660 errno = 0;
661 tmp = strtol (attrs[1], &end, 10);
662 if (errno == ERANGE || tmp > G_MAXINT / 1000 || tmp < G_MININT / 1000)
663 return xlsx_warning (xin,
664 _("Integer '%s' is out of range, for attribute %s"),
665 attrs[1], target);
666 if (*end == 0)
667 *res = tmp;
668 else if (strcmp (end, "%") == 0)
669 *res = tmp * 1000;
670 else
671 return xlsx_warning (xin,
672 _("Invalid integer '%s' for attribute %s"),
673 attrs[1], target);
675 return TRUE;
679 static gboolean
680 attr_pos (GsfXMLIn *xin, xmlChar const **attrs,
681 char const *target,
682 GnmCellPos *res)
684 XLSXReadState *state = (XLSXReadState *)xin->user_state;
685 char const *end;
686 GnmCellPos tmp;
688 g_return_val_if_fail (attrs != NULL, FALSE);
689 g_return_val_if_fail (attrs[0] != NULL, FALSE);
690 g_return_val_if_fail (attrs[1] != NULL, FALSE);
692 if (strcmp (attrs[0], target))
693 return FALSE;
695 end = cellpos_parse (attrs[1], gnm_sheet_get_size (state->sheet), &tmp, TRUE);
696 if (NULL == end || *end != '\0')
697 return xlsx_warning (xin,
698 _("Invalid cell position '%s' for attribute %s"),
699 attrs[1], target);
700 *res = tmp;
701 return TRUE;
704 static gboolean
705 attr_range (GsfXMLIn *xin, xmlChar const **attrs,
706 char const *target,
707 GnmRange *res)
709 static const GnmSheetSize xlsx_size = {
710 XLSX_MaxCol, XLSX_MaxRow
713 g_return_val_if_fail (attrs != NULL, FALSE);
714 g_return_val_if_fail (attrs[0] != NULL, FALSE);
715 g_return_val_if_fail (attrs[1] != NULL, FALSE);
717 if (strcmp (attrs[0], target))
718 return FALSE;
720 if (!range_parse (res, attrs[1], &xlsx_size))
721 xlsx_warning (xin, _("Invalid range '%s' for attribute %s"),
722 attrs[1], target);
723 return TRUE;
726 static GnmValue *
727 attr_datetime (GsfXMLIn *xin, xmlChar const **attrs,
728 char const *target)
730 unsigned y, m, d, h, mi, n;
731 GnmValue *res = NULL;
732 gnm_float s;
734 g_return_val_if_fail (attrs != NULL, NULL);
735 g_return_val_if_fail (attrs[0] != NULL, NULL);
736 g_return_val_if_fail (attrs[1] != NULL, NULL);
738 if (strcmp (attrs[0], target))
739 return NULL;
741 n = sscanf (attrs[1], "%u-%u-%uT%u:%u:%" GNM_SCANF_g,
742 &y, &m, &d, &h, &mi, &s);
744 if (n >= 3) {
745 GDate date;
746 g_date_set_dmy (&date, d, m, y);
747 if (g_date_valid (&date)) {
748 XLSXReadState *state = (XLSXReadState *)xin->user_state;
749 unsigned d_serial = go_date_g_to_serial (&date,
750 workbook_date_conv (state->wb));
751 if (n >= 6) {
752 double time_frac = h + (gnm_float)mi / 60 + s / 3600;
753 res = value_new_float (d_serial + time_frac / 24.);
754 value_set_fmt (res, state->date_fmt);
755 } else {
756 res = value_new_int (d_serial);
757 value_set_fmt (res, go_format_default_date ());
762 return res;
765 /* returns pts */
766 static gboolean
767 xlsx_parse_distance (GsfXMLIn *xin, xmlChar const *str,
768 char const *name, gnm_float *pts)
770 double num;
771 char *end = NULL;
773 g_return_val_if_fail (str != NULL, FALSE);
775 num = go_strtod (CXML2C (str), &end);
776 if (CXML2C (str) != end) {
777 if (0 == strncmp (end, "mm", 2)) {
778 num = GO_CM_TO_PT (num/10.);
779 end += 2;
780 } else if (0 == strncmp (end, "cm", 2)) {
781 num = GO_CM_TO_PT (num);
782 end += 2;
783 } else if (0 == strncmp (end, "pt", 2)) {
784 end += 2;
785 } else if (0 == strncmp (end, "pc", 2)) { /* pica 12pt == 1 pica */
786 num /= 12.;
787 end += 2;
788 } else if (0 == strncmp (end, "pi", 2)) { /* pica 12pt == 1 pica */
789 num /= 12.;
790 end += 2;
791 } else if (0 == strncmp (end, "in", 2)) {
792 num = GO_IN_TO_PT (num);
793 end += 2;
794 } else {
795 xlsx_warning (xin, _("Invalid attribute '%s', unknown unit '%s'"),
796 name, str);
797 return FALSE;
799 } else {
800 xlsx_warning (xin, _("Invalid attribute '%s', expected distance, received '%s'"),
801 name, str);
802 return FALSE;
805 if (*end) {
806 return xlsx_warning (xin,
807 _("Invalid attribute '%s', expected distance, received '%s'"),
808 name, str);
809 return FALSE;
812 *pts = num;
813 return TRUE;
816 /* returns pts */
817 static gboolean
818 attr_distance (GsfXMLIn *xin, xmlChar const **attrs,
819 char const *target, gnm_float *pts)
821 g_return_val_if_fail (attrs != NULL, FALSE);
822 g_return_val_if_fail (attrs[0] != NULL, FALSE);
823 g_return_val_if_fail (attrs[1] != NULL, FALSE);
825 if (strcmp (attrs[0], target))
826 return FALSE;
828 return xlsx_parse_distance (xin, attrs[1], target, pts);
831 /***********************************************************************/
833 static gboolean
834 simple_bool (GsfXMLIn *xin, xmlChar const **attrs, int *res)
836 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
837 if (attr_bool (xin, attrs, "val", res))
838 return TRUE;
839 return FALSE;
842 static gboolean
843 simple_int (GsfXMLIn *xin, xmlChar const **attrs, int *res)
845 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
846 if (attr_int (xin, attrs, "val", res))
847 return TRUE;
848 return FALSE;
851 static gboolean
852 simple_uint (GsfXMLIn *xin, xmlChar const **attrs, unsigned *res)
854 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
855 if (attr_uint (xin, attrs, "val", res))
856 return TRUE;
857 return FALSE;
860 static gboolean
861 simple_float (GsfXMLIn *xin, xmlChar const **attrs, gnm_float *res)
863 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
864 if (attr_float (xin, attrs, "val", res))
865 return TRUE;
866 return FALSE;
869 static gboolean
870 simple_enum (GsfXMLIn *xin, xmlChar const **attrs, EnumVal const *enums, int *res)
872 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
873 if (attr_enum (xin, attrs, "val", enums, res))
874 return TRUE;
875 return FALSE;
878 static const char *
879 simple_string (G_GNUC_UNUSED GsfXMLIn *xin, xmlChar const **attrs)
881 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
882 if (strcmp (attrs[0], "val") == 0)
883 return CXML2C (attrs[1]);
884 return NULL;
887 /***********************************************************************
888 * These indexes look like the values in xls. Dup some code from there.
889 * TODO : Can we merge the code ?
890 * Will the 'indexedColors' look like a palette ?
892 static struct {
893 guint8 r, g, b;
894 } xlsx_default_palette_v8 [] = {
895 { 0, 0, 0}, {255,255,255}, {255, 0, 0}, { 0,255, 0},
896 { 0, 0,255}, {255,255, 0}, {255, 0,255}, { 0,255,255},
898 {128, 0, 0}, { 0,128, 0}, { 0, 0,128}, {128,128, 0},
899 {128, 0,128}, { 0,128,128}, {192,192,192}, {128,128,128},
901 {153,153,255}, {153, 51,102}, {255,255,204}, {204,255,255},
902 {102, 0,102}, {255,128,128}, { 0,102,204}, {204,204,255},
904 { 0, 0,128}, {255, 0,255}, {255,255, 0}, { 0,255,255},
905 {128, 0,128}, {128, 0, 0}, { 0,128,128}, { 0, 0,255},
907 { 0,204,255}, {204,255,255}, {204,255,204}, {255,255,153},
908 {153,204,255}, {255,153,204}, {204,153,255}, {255,204,153},
910 { 51,102,255}, { 51,204,204}, {153,204, 0}, {255,204, 0},
911 {255,153, 0}, {255,102, 0}, {102,102,153}, {150,150,150},
913 { 0, 51,102}, { 51,153,102}, { 0, 51, 0}, { 51, 51, 0},
914 {153, 51, 0}, {153, 51,102}, { 51, 51,153}, { 51, 51, 51}
917 static GOColor
918 indexed_color (G_GNUC_UNUSED XLSXReadState *state, gint idx)
920 /* NOTE: not documented but seems close
921 * If you find a normative reference please forward it.
923 * The color index field seems to use
924 * 8-63 = Palette index 0-55
925 * 64 = auto pattern, auto border
926 * 65 = auto background
927 * 127 = auto font
929 * 65 is always white, and 127 always black. 64 is black
930 * if the fDefaultHdr flag in WINDOW2 is unset, otherwise it's
931 * the grid color from WINDOW2.
934 if (idx == 1 || idx == 65)
935 return GO_COLOR_WHITE;
936 switch (idx) {
937 case 0: /* black */
938 case 64 : /* system text ? */
939 case 81 : /* tooltip text */
940 case 0x7fff : /* system text ? */
941 return GO_COLOR_BLACK;
943 case 1 : /* white */
944 case 65 : /* system back ? */
945 return GO_COLOR_WHITE;
947 case 80 : /* tooltip background */
948 return GO_COLOR_YELLOW;
950 case 2 : return GO_COLOR_RED;
951 case 3 : return GO_COLOR_GREEN;
952 case 4 : return GO_COLOR_BLUE;
953 case 5 : return GO_COLOR_YELLOW;
954 case 6 : return GO_COLOR_VIOLET;
955 case 7 : return GO_COLOR_CYAN;
957 default :
958 break;
961 idx -= 8;
962 if (idx < 0 || (int) G_N_ELEMENTS (xlsx_default_palette_v8) <= idx) {
963 g_warning ("EXCEL: color index (%d) is out of range (8..%d). Defaulting to black",
964 idx + 8, (int)G_N_ELEMENTS (xlsx_default_palette_v8) + 8);
965 return GO_COLOR_BLACK;
968 /* TODO cache and ref */
969 return GO_COLOR_FROM_RGB (xlsx_default_palette_v8[idx].r,
970 xlsx_default_palette_v8[idx].g,
971 xlsx_default_palette_v8[idx].b);
974 static gboolean
975 themed_color_from_name (XLSXReadState *state, const char *name, GOColor *color)
977 gpointer val;
978 gboolean dark = FALSE; // FIXME: refers to theme; from where?
979 static const struct {
980 const char *name;
981 const char *dark; // Color name when theme is dark
982 const char *light; // Color name when theme is light
983 } aliases[] = {
984 { "tx1", "lt1", "dk1" },
985 { "tx2", "lt2", "dk2" },
986 { "bg1", "dk1", "lt1" },
987 { "bg2", "dk2", "lt2" }
989 unsigned ui;
991 if (g_hash_table_lookup_extended (state->theme_colors_by_name, name, NULL, &val)) {
992 *color = GPOINTER_TO_UINT (val);
993 return TRUE;
996 for (ui = 0; ui < G_N_ELEMENTS (aliases); ui++) {
997 if (strcmp (name, aliases[ui].name) == 0) {
998 name = dark ? aliases[ui].dark : aliases[ui].light;
999 return themed_color_from_name (state, name, color);
1003 return FALSE;
1007 static GOColor
1008 themed_color (GsfXMLIn *xin, gint idx)
1010 static char const * const theme_elements [] = {
1011 "lt1", "dk1", "lt2", "dk2",
1012 "accent1", "accent2", "accent3", "accent4", "accent5", "accent6",
1013 "hlink", "folHlink"
1015 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1017 /* MAGIC :
1018 * looks like the indicies map to hard coded names rather than the
1019 * order in the file. Indeed the order in the file seems wrong
1020 * it inverts the first to pairs
1021 * 1,0,3,2, 4,5,6.....
1022 * see: http://openxmldeveloper.org/forums/thread/1306.aspx
1023 * OOo seems to do something similar
1025 * I'll make the assumption we should work by name rather than
1026 * index. */
1027 if (idx >= 0 && idx < (int) G_N_ELEMENTS (theme_elements)) {
1028 GOColor color;
1029 if (themed_color_from_name (state, theme_elements[idx], &color))
1030 return color;
1032 xlsx_warning (xin, _("Unknown theme color %d"), idx);
1033 } else {
1034 xlsx_warning (xin, "Color index (%d) is out of range (0..%d). Defaulting to black",
1035 idx, (int) G_N_ELEMENTS (theme_elements));
1038 return GO_COLOR_BLACK;
1041 static GOFormat *
1042 xlsx_get_num_fmt (GsfXMLIn *xin, char const *id)
1044 static char const * const std_builtins[] = {
1045 /* 0 */ "General",
1046 /* 1 */ "0",
1047 /* 2 */ "0.00",
1048 /* 3 */ "#,##0",
1049 /* 4 */ "#,##0.00",
1050 /* 5 */ NULL,
1051 /* 6 */ NULL,
1052 /* 7 */ NULL,
1053 /* 8 */ NULL,
1054 /* 9 */ "0%",
1055 /* 10 */ "0.00%",
1056 /* 11 */ "0.00E+00",
1057 /* 12 */ "# ?/?",
1058 /* 13 */ "# ?""?/?""?", /* silly trick to avoid using a trigraph */
1059 /* 14 */ "mm-dd-yy",
1060 /* 15 */ "d-mmm-yy",
1061 /* 16 */ "d-mmm",
1062 /* 17 */ "mmm-yy",
1063 /* 18 */ "h:mm AM/PM",
1064 /* 19 */ "h:mm:ss AM/PM",
1065 /* 20 */ "h:mm",
1066 /* 21 */ "h:mm:ss",
1067 /* 22 */ "m/d/yy h:mm",
1068 /* 23 */ NULL,
1069 /* 24 */ NULL,
1070 /* 25 */ NULL,
1071 /* 26 */ NULL,
1072 /* 27 */ NULL,
1073 /* 28 */ NULL,
1074 /* 29 */ NULL,
1075 /* 30 */ NULL,
1076 /* 31 */ NULL,
1077 /* 32 */ NULL,
1078 /* 33 */ NULL,
1079 /* 34 */ NULL,
1080 /* 35 */ NULL,
1081 /* 36 */ NULL,
1082 /* 37 */ "#,##0 ;(#,##0)",
1083 /* 38 */ "#,##0 ;[Red](#,##0)",
1084 /* 39 */ "#,##0.00;(#,##0.00)",
1085 /* 40 */ "#,##0.00;[Red](#,##0.00)",
1086 /* 41 */ NULL,
1087 /* 42 */ NULL,
1088 /* 43 */ NULL,
1089 /* 44 */ NULL,
1090 /* 45 */ "mm:ss",
1091 /* 46 */ "[h]:mm:ss",
1092 /* 47 */ "mmss.0",
1093 /* 48 */ "##0.0E+0",
1094 /* 49 */ "@"
1097 #if 0
1098 CHT CHS
1099 27 [$-404]e/m/d yyyy"5E74"m"6708"
1100 28 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1101 29 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1102 30 m/d/yy m-d-yy
1103 31 yyyy"5E74"m"6708"d"65E5" yyyy"5E74"m"6708"d"65E5"
1104 32 hh"6642"mm"5206" h"65F6"mm"5206"
1105 33 hh"6642"mm"5206"ss"79D2" h"65F6"mm"5206"ss"79D2"
1106 34 4E0A5348/4E0B5348hh"6642"mm"5206" 4E0A5348/4E0B5348h"65F6"mm"5206"
1107 35 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2" 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2"
1108 36 [$-404]e/m/d yyyy"5E74"m"6708"
1109 50 [$-404]e/m/d yyyy"5E74"m"6708"
1110 51 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1111 52 4E0A5348/4E0B5348hh"6642"mm"5206" yyyy"5E74"m"6708"
1112 53 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2" m"6708"d"65E5"
1113 54 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1114 55 4E0A5348/4E0B5348hh"6642"mm"5206" 4E0A5348/4E0B5348h"65F6"mm"5206"
1115 56 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2" 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2"
1116 57 [$-404]e/m/d yyyy"5E74"m"6708"
1117 58 [$-404]e"5E74"m"6708"d"65E5" m"6708"d"65E5"
1119 JPN KOR
1120 27 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1121 28 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1122 29 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1123 30 m/d/yy mm-dd-yy
1124 31 yyyy"5E74"m"6708"d"65E5" yyyy"B144" mm"C6D4" dd"C77C"
1125 32 h"6642"mm"5206" h"C2DC" mm"BD84"
1126 33 h"6642"mm"5206"ss"79D2" h"C2DC" mm"BD84" ss"CD08"
1127 34 yyyy"5E74"m"6708" yyyy-mm-dd
1128 35 m"6708"d"65E5" yyyy-mm-dd
1129 36 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1130 50 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1131 51 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1132 52 yyyy"5E74"m"6708" yyyy-mm-dd
1133 53 m"6708"d"65E5" yyyy-mm-dd
1134 54 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1135 55 yyyy"5E74"m"6708" yyyy-mm-dd
1136 56 m"6708"d"65E5" yyyy-mm-dd
1137 57 [$-411]ge.m.d yyyy"5E74" mm"6708" dd"65E5"
1138 58 [$-411]ggge"5E74"m"6708"d"65E5" mm-dd
1141 59 "t0"
1142 60 "t0.00"
1143 61 "t#,##0"
1144 62 "t#,##0.00"
1145 67 "t0%"
1146 68 "t0.00%"
1147 69 "t# ?/?"
1148 70 "t# ?""?/?""?" /* silly trick to avoid using a trigraph */
1149 71 0E27/0E14/0E1B0E1B0E1B0E1B
1150 72 0E27-0E140E140E14-0E1B0E1B
1151 73 0E27-0E140E140E14
1152 74 0E140E140E14-0E1B0E1B
1153 75 0E0A:0E190E19
1154 76 0E0A:0E190E19:0E170E17
1155 77 0E27/0E14/0E1B0E1B0E1B0E1B 0E0A:0E190E19
1156 78 0E190E19:0E170E17
1157 79 [0E0A]:0E190E19:0E170E17
1158 80 0E190E19:0E170E17.0
1159 81 d/m/bb
1160 #endif
1162 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1163 GOFormat *res = g_hash_table_lookup (state->num_fmts, id);
1164 char *end;
1165 long i;
1167 if (NULL != res)
1168 return res;
1170 /* builtins */
1171 i = strtol (id, &end, 10);
1172 if (end != id && *end == '\0' &&
1173 i >= 0 && i < (int) G_N_ELEMENTS (std_builtins) &&
1174 std_builtins[i] != NULL) {
1175 res = go_format_new_from_XL (std_builtins[i]);
1176 g_hash_table_replace (state->num_fmts, g_strdup (id), res);
1177 } else
1178 xlsx_warning (xin, _("Undefined number format id '%s'"), id);
1179 return res;
1182 static GnmExprTop const *
1183 xlsx_parse_expr (GsfXMLIn *xin, xmlChar const *expr_str,
1184 GnmParsePos const *pp)
1186 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1187 GnmParseError err;
1188 GnmExprTop const *texpr;
1190 /* Odd, some time IF and CHOOSE show up with leading spaces ??
1191 * = IF(....
1192 * = CHOOSE(...
1193 * I wonder if it is related to some of the funky old
1194 * optimizations in * xls ? */
1195 while (' ' == *expr_str)
1196 expr_str++;
1198 texpr = gnm_expr_parse_str (expr_str, pp,
1199 GNM_EXPR_PARSE_DEFAULT, state->convs,
1200 parse_error_init (&err));
1201 if (NULL == texpr)
1202 xlsx_warning (xin, "At %s: '%s' %s",
1203 parsepos_as_string (pp),
1204 expr_str, err.err->message);
1205 parse_error_free (&err);
1207 return texpr;
1210 /* Returns: a GSList of GnmRange in _reverse_ order
1211 * caller frees the list and the content */
1212 static GSList *
1213 xlsx_parse_sqref (GsfXMLIn *xin, xmlChar const *refs)
1215 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1216 GnmRange r;
1217 xmlChar const *tmp;
1218 GSList *res = NULL;
1220 while (NULL != refs && *refs) {
1221 if (NULL == (tmp = cellpos_parse (refs, gnm_sheet_get_size (state->sheet), &r.start, FALSE))) {
1222 xlsx_warning (xin, "unable to parse reference list '%s'", refs);
1223 return res;
1226 refs = tmp;
1227 if (*refs == '\0' || *refs == ' ')
1228 r.end = r.start;
1229 else if (*refs != ':' ||
1230 NULL == (tmp = cellpos_parse (refs + 1, gnm_sheet_get_size (state->sheet), &r.end, FALSE))) {
1231 xlsx_warning (xin, "unable to parse reference list '%s'", refs);
1232 return res;
1235 range_normalize (&r); /* be anal */
1236 res = g_slist_prepend (res, gnm_range_dup (&r));
1238 for (refs = tmp ; *refs == ' ' ; refs++ ) ;
1241 return res;
1244 /***********************************************************************/
1246 #include "xlsx-read-pivot.c"
1248 /***********************************************************************/
1250 static void xlsx_ext_begin (GsfXMLIn *xin, xmlChar const **attrs);
1251 static void xlsx_ext_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob);
1253 #include "xlsx-read-color.c"
1254 #include "xlsx-read-drawing.c"
1256 /***********************************************************************/
1258 static GnmColor *
1259 elem_color (GsfXMLIn *xin, xmlChar const **attrs, gboolean allow_alpha)
1261 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1262 int indx;
1263 GOColor c = GO_COLOR_BLACK;
1264 gnm_float tint = 0.;
1265 gboolean has_color = FALSE;
1267 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1268 if (0 == strcmp (attrs[0], "rgb")) {
1269 guint a, r, g, b;
1270 if (4 != sscanf (attrs[1], "%02x%02x%02x%02x", &a, &r, &g, &b)) {
1271 xlsx_warning (xin,
1272 _("Invalid color '%s' for attribute rgb"),
1273 attrs[1]);
1274 return NULL;
1276 has_color = TRUE;
1277 c = GO_COLOR_FROM_RGBA (r,g,b,a);
1278 } else if (attr_int (xin, attrs, "indexed", &indx)) {
1279 has_color = TRUE;
1280 c = indexed_color (state, indx);
1281 } else if (attr_int (xin, attrs, "theme", &indx)) {
1282 has_color = TRUE;
1283 c = themed_color (xin, indx);
1284 } else if (attr_float (xin, attrs, "tint", &tint))
1285 ; /* Nothing */
1288 if (!has_color)
1289 return NULL;
1290 c = gnm_go_color_apply_tint (c, tint);
1291 if (!allow_alpha)
1292 c = GO_COLOR_CHANGE_A (c, 0xFF);
1293 return gnm_color_new_go (c);
1296 static GnmStyle *
1297 xlsx_get_style_xf (GsfXMLIn *xin, int xf)
1299 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1300 if (0 <= xf && NULL != state->style_xfs && xf < (int)state->style_xfs->len)
1301 return g_ptr_array_index (state->style_xfs, xf);
1302 xlsx_warning (xin, _("Undefined style record '%d'"), xf);
1303 return NULL;
1305 static GnmStyle *
1306 xlsx_get_xf (GsfXMLIn *xin, int xf)
1308 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1309 if (0 <= xf && NULL != state->xfs && xf < (int)state->xfs->len)
1310 return g_ptr_array_index (state->xfs, xf);
1311 xlsx_warning (xin, _("Undefined style record '%d'"), xf);
1312 return NULL;
1314 static GnmStyle *
1315 xlsx_get_dxf (GsfXMLIn *xin, int dxf)
1317 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1318 if (0 <= dxf && NULL != state->dxfs && dxf < (int)state->dxfs->len)
1319 return g_ptr_array_index (state->dxfs, dxf);
1320 xlsx_warning (xin, _("Undefined partial style record '%d'"), dxf);
1321 return NULL;
1324 /****************************************************************************/
1326 static void
1327 xlsx_cell_val_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1329 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1330 XLSXStr const *entry;
1331 char *end;
1332 long i;
1334 switch (state->pos_type) {
1335 case XLXS_TYPE_NUM :
1336 if (*xin->content->str)
1337 state->val = value_new_float (gnm_strto (xin->content->str, &end));
1338 break;
1339 case XLXS_TYPE_SST_STR :
1340 i = xlsx_relaxed_strtol (xin->content->str, &end, 10);
1341 if (end != xin->content->str && *end == '\0' &&
1342 0 <= i && i < (int)state->sst->len) {
1343 entry = &g_array_index (state->sst, XLSXStr, i);
1344 go_string_ref (entry->str);
1345 state->val = value_new_string_str (entry->str);
1346 if (NULL != entry->markup)
1347 value_set_fmt (state->val, entry->markup);
1348 } else {
1349 xlsx_warning (xin, _("Invalid sst ref '%s'"), xin->content->str);
1351 break;
1352 case XLXS_TYPE_BOOL :
1353 if (*xin->content->str)
1354 state->val = value_new_bool (*xin->content->str != '0');
1355 break;
1356 case XLXS_TYPE_ERR :
1357 if (*xin->content->str)
1358 state->val = value_new_error (NULL, xin->content->str);
1359 break;
1361 case XLXS_TYPE_STR2 : /* What is this ? */
1362 case XLXS_TYPE_INLINE_STR :
1363 state->val = value_new_string (xin->content->str);
1364 break;
1365 default :
1366 g_warning ("Unknown val type %d", state->pos_type);
1370 static void
1371 xlsx_cell_inline_text_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1373 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1374 go_string_append_gstring (state->r_text, xin->content);
1378 static void
1379 xlsx_cell_inline_begin (GsfXMLIn *xin, xmlChar const **attrs)
1381 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1383 state->r_text = g_string_new ("");
1386 static void
1387 xlsx_cell_inline_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1389 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1391 state->val = value_new_string_nocopy (g_string_free (state->r_text, FALSE));
1392 state->r_text = NULL;
1394 if (state->rich_attrs) {
1395 GOFormat *fmt = go_format_new_markup (state->rich_attrs, FALSE);
1396 state->rich_attrs = NULL;
1397 value_set_fmt (state->val, fmt);
1398 go_format_unref (fmt);
1403 static void
1404 xlsx_cell_expr_begin (GsfXMLIn *xin, xmlChar const **attrs)
1406 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1407 gboolean has_range = FALSE, is_array = FALSE, is_shared = FALSE;
1408 GnmRange range;
1409 xmlChar const *shared_id = NULL;
1411 /* See https://bugzilla.gnome.org/show_bug.cgi?id=642850 */
1412 /* for some of the issues surrounding shared formulas. */
1414 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1415 if (0 == strcmp (attrs[0], "t")) {
1416 if (0 == strcmp (attrs[1], "array"))
1417 is_array = TRUE;
1418 else if (0 == strcmp (attrs[1], "shared"))
1419 is_shared = TRUE;
1420 } else if (0 == strcmp (attrs[0], "si"))
1421 shared_id = attrs[1];
1422 else if (attr_range (xin, attrs, "ref", &range))
1423 has_range = TRUE;
1425 state->shared_id = NULL;
1426 if (is_shared && NULL != shared_id) {
1427 if (!has_range)
1428 state->texpr = g_hash_table_lookup (state->shared_exprs, shared_id);
1429 if (NULL != state->texpr)
1430 gnm_expr_top_ref (state->texpr);
1431 else
1432 state->shared_id = g_strdup (shared_id);
1433 } else
1434 state->texpr = NULL;
1436 /* if the shared expr is already parsed expression do not even collect content */
1437 ((GsfXMLInNode *)(xin->node))->has_content =
1438 (NULL != state->texpr) ? GSF_XML_NO_CONTENT : GSF_XML_CONTENT;
1440 if (is_array && has_range)
1441 state->array = range;
1444 static void
1445 xlsx_cell_expr_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1447 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1448 GnmParsePos pp;
1450 if (NULL == state->texpr) {
1451 parse_pos_init (&pp, NULL, state->sheet,
1452 state->pos.col, state->pos.row);
1453 state->texpr = xlsx_parse_expr (xin, xin->content->str, &pp);
1454 if (NULL != state->texpr &&
1455 NULL != state->shared_id) {
1456 gnm_expr_top_ref (state->texpr);
1457 g_hash_table_replace (state->shared_exprs,
1458 state->shared_id, (gpointer)state->texpr);
1459 state->shared_id = NULL;
1462 g_free (state->shared_id);
1463 state->shared_id = NULL;
1466 static void
1467 xlsx_cell_begin (GsfXMLIn *xin, xmlChar const **attrs)
1469 static EnumVal const types[] = {
1470 { "n", XLXS_TYPE_NUM },
1471 { "s", XLXS_TYPE_SST_STR },
1472 { "str", XLXS_TYPE_STR2 },
1473 { "b", XLXS_TYPE_BOOL },
1474 { "inlineStr", XLXS_TYPE_INLINE_STR },
1475 { "e", XLXS_TYPE_ERR },
1476 { NULL, 0 }
1478 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1479 int tmp;
1480 GnmStyle *style = NULL;
1482 state->pos.col = state->pos.row = -1;
1483 state->pos_type = XLXS_TYPE_NUM; /* the default */
1484 state->val = NULL;
1485 state->texpr = NULL;
1486 range_init (&state->array, -1, -1, -1, -1); /* invalid */
1488 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1489 if (attr_pos (xin, attrs, "r", &state->pos)) ;
1490 else if (attr_enum (xin, attrs, "t", types, &tmp))
1491 state->pos_type = tmp;
1492 else if (attr_int (xin, attrs, "s", &tmp))
1493 style = xlsx_get_xf (xin, tmp);
1495 if (NULL != style) {
1496 gnm_style_ref (style);
1497 /* There may already be a row style set!*/
1498 sheet_style_apply_pos (state->sheet,
1499 state->pos.col, state->pos.row, style);
1502 static void
1503 xlsx_cell_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1505 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1506 GnmCell *cell;
1508 if (state->texpr == NULL && state->val == NULL) {
1509 /* A cell with only style. */
1510 return;
1513 cell = sheet_cell_fetch (state->sheet, state->pos.col, state->pos.row);
1515 if (NULL == cell) {
1516 xlsx_warning (xin, _("Invalid cell %s"),
1517 cellpos_as_string (&state->pos));
1518 value_release (state->val);
1519 if (NULL != state->texpr)
1520 gnm_expr_top_unref (state->texpr);
1521 } else if (NULL != state->texpr) {
1522 if (state->array.start.col >= 0) {
1523 gnm_cell_set_array (state->sheet,
1524 &state->array,
1525 state->texpr);
1526 gnm_expr_top_unref (state->texpr);
1527 if (NULL != state->val)
1528 gnm_cell_assign_value (cell, state->val);
1529 } else if (NULL != state->val) {
1530 gnm_cell_set_expr_and_value (cell,
1531 state->texpr, state->val, TRUE);
1532 gnm_expr_top_unref (state->texpr);
1533 } else {
1534 gnm_cell_set_expr (cell, state->texpr);
1535 gnm_expr_top_unref (state->texpr);
1537 } else if (NULL != state->val)
1538 gnm_cell_assign_value (cell, state->val);
1540 state->texpr = NULL;
1541 state->val = NULL;
1544 static void
1545 xlsx_CT_Row (GsfXMLIn *xin, xmlChar const **attrs)
1547 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1548 int row = -1, xf_index;
1549 gnm_float h = -1.;
1550 int cust_fmt = FALSE, cust_height = FALSE, collapsed = FALSE;
1551 int hidden = -1;
1552 int outline = -1;
1553 GnmStyle *style = NULL;
1555 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1556 if (attr_int (xin, attrs, "r", &row))
1558 else if (attr_float (xin, attrs, "ht", &h))
1560 else if (attr_bool (xin, attrs, "customFormat", &cust_fmt))
1562 else if (attr_bool (xin, attrs, "customHeight", &cust_height))
1564 else if (attr_int (xin, attrs, "s", &xf_index))
1565 style = xlsx_get_xf (xin, xf_index);
1566 else if (attr_int (xin, attrs, "outlineLevel", &outline))
1568 else if (attr_bool (xin, attrs, "hidden", &hidden))
1570 else if (attr_bool (xin, attrs, "collapsed", &collapsed))
1574 if (row > 0) {
1575 row--;
1576 if (h >= 0.)
1577 sheet_row_set_size_pts (state->sheet, row, h, cust_height);
1578 if (hidden > 0)
1579 colrow_set_visibility (state->sheet, FALSE, FALSE, row, row);
1580 if (outline >= 0)
1581 col_row_info_set_outline (sheet_row_fetch (state->sheet, row),
1582 outline, collapsed);
1584 if (NULL != style && cust_fmt) {
1585 GnmRange r;
1586 r.start.row = r.end.row = row;
1587 r.start.col = 0;
1588 r.end.col = gnm_sheet_get_max_cols (state->sheet) - 1;
1589 gnm_style_ref (style);
1590 sheet_style_set_range (state->sheet, &r, style);
1594 maybe_update_progress (xin);
1597 static void
1598 xlsx_CT_RowsCols_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
1600 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1602 if (!state->pending_rowcol_style)
1603 return;
1605 sheet_style_set_range (state->sheet,
1606 &state->pending_rowcol_range,
1607 state->pending_rowcol_style);
1609 state->pending_rowcol_style = NULL;
1611 maybe_update_progress (xin);
1614 static void
1615 xlsx_CT_Col (GsfXMLIn *xin, xmlChar const **attrs)
1617 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1618 int first = -1, last = -1, xf_index;
1619 double width = -1.;
1620 gboolean cust_width = FALSE, best_fit = FALSE, collapsed = FALSE;
1621 int i, hidden = -1;
1622 int outline = -1;
1623 GnmStyle *style = NULL;
1625 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1626 if (attr_int (xin, attrs, "min", &first))
1628 else if (attr_int (xin, attrs, "max", &last))
1630 else if (attr_float (xin, attrs, "width", &width))
1631 /* FIXME FIXME FIXME arbitrary map from 130 pixels to
1632 * the value stored for a column with 130 pixel width*/
1633 width *= (130. / 18.5703125) * (72./96.);
1634 else if (attr_bool (xin, attrs, "customWidth", &cust_width))
1636 else if (attr_bool (xin, attrs, "bestFit", &best_fit))
1638 else if (attr_int (xin, attrs, "style", &xf_index))
1639 style = xlsx_get_xf (xin, xf_index);
1640 else if (attr_int (xin, attrs, "outlineLevel", &outline))
1642 else if (attr_bool (xin, attrs, "hidden", &hidden))
1644 else if (attr_bool (xin, attrs, "collapsed", &collapsed))
1648 if (first < 0) {
1649 if (last < 0) {
1650 xlsx_warning (xin, _("Ignoring column information that does not specify first or last."));
1651 return;
1653 first = --last;
1654 } else if (last < 0)
1655 last = --first;
1656 else {
1657 first--;
1658 last--;
1661 first = CLAMP (first, 0, gnm_sheet_get_last_col (state->sheet));
1662 last = CLAMP (last, 0, gnm_sheet_get_last_col (state->sheet));
1664 for (i = first; i <= last; i++) {
1665 if (width > 4)
1666 sheet_col_set_size_pts (state->sheet, i, width,
1667 cust_width && !best_fit);
1668 if (outline > 0)
1669 col_row_info_set_outline (sheet_col_fetch (state->sheet, i),
1670 outline, collapsed);
1672 if (NULL != style) {
1673 GnmRange r;
1674 range_init_cols (&r, state->sheet, first, last);
1677 * Sometimes we see a lot of columns with the same style.
1678 * We delay applying the style because applying column
1679 * by column leads to style fragmentation. #622365
1682 if (style != state->pending_rowcol_style ||
1683 state->pending_rowcol_range.start.row != r.start.row ||
1684 state->pending_rowcol_range.end.row != r.end.row ||
1685 state->pending_rowcol_range.end.col + 1 != r.start.col)
1686 xlsx_CT_RowsCols_end (xin, NULL);
1688 if (state->pending_rowcol_style)
1689 state->pending_rowcol_range.end.col = r.end.col;
1690 else {
1691 gnm_style_ref (style);
1692 state->pending_rowcol_style = style;
1693 state->pending_rowcol_range = r;
1696 if (hidden > 0)
1697 colrow_set_visibility (state->sheet, TRUE, FALSE, first, last);
1700 static void
1701 xlsx_CT_SheetPr (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
1703 #if 0
1704 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1705 <xsd:attribute name="syncHorizontal" type="xsd:boolean" use="optional" default="false">
1706 <xsd:attribute name="syncVertical" type="xsd:boolean" use="optional" default="false">
1707 <xsd:attribute name="syncRef" type="ST_Ref" use="optional">
1708 <xsd:attribute name="transitionEvaluation" type="xsd:boolean" use="optional" default="false">
1709 <xsd:attribute name="transitionEntry" type="xsd:boolean" use="optional" default="false">
1710 <xsd:attribute name="published" type="xsd:boolean" use="optional" default="true">
1711 <xsd:attribute name="codeName" type="xsd:string" use="optional">
1712 <xsd:attribute name="filterMode" type="xsd:boolean" use="optional" default="false">
1713 <xsd:attribute name="enableFormatConditionsCalculation" type="xsd:boolean" use="optional" default="true">
1714 #endif
1717 static void
1718 xlsx_sheet_tab_fgbg (GsfXMLIn *xin, xmlChar const **attrs, gboolean fg)
1720 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1721 GnmColor *color = elem_color (xin, attrs, TRUE);
1722 if (color) {
1723 g_object_set (state->sheet,
1724 (fg ? "tab-foreground" : "tab-background"), color,
1725 NULL);
1726 style_color_unref (color);
1730 static void
1731 xlsx_sheet_tabcolor (GsfXMLIn *xin, xmlChar const **attrs)
1733 xlsx_sheet_tab_fgbg (xin, attrs, FALSE);
1736 static void
1737 xlsx_ext_tabtextcolor (GsfXMLIn *xin, xmlChar const **attrs)
1739 xlsx_sheet_tab_fgbg (xin, attrs, TRUE);
1742 static void
1743 xlsx_sheet_page_setup (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
1745 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1746 GnmPrintInformation *pi = state->sheet->print_info;
1747 gboolean tmp;
1749 if (pi->page_setup == NULL)
1750 gnm_print_info_load_defaults (pi);
1752 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1753 if (attr_bool (xin, attrs, "fitToPage", &tmp))
1754 pi->scaling.type = tmp ? PRINT_SCALE_FIT_PAGES : PRINT_SCALE_PERCENTAGE;
1758 static void
1759 xlsx_CT_SheetFormatPr (GsfXMLIn *xin, xmlChar const **attrs)
1761 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1762 gnm_float h;
1763 int i;
1765 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1766 if (attr_float (xin, attrs, "defaultRowHeight", &h))
1767 sheet_row_set_default_size_pts (state->sheet, h);
1768 else if (attr_int (xin, attrs, "outlineLevelRow", &i)) {
1769 if (i > 0)
1770 sheet_colrow_gutter (state->sheet, FALSE, i);
1771 } else if (attr_int (xin, attrs, "outlineLevelCol", &i)) {
1772 if (i > 0)
1773 sheet_colrow_gutter (state->sheet, TRUE, i);
1778 static GtkPaperSize *
1779 xlsx_paper_size (gdouble width, gdouble height, GtkUnit unit, int code)
1781 GtkPaperSize *size;
1782 gchar *name;
1783 gchar *display_name;
1785 if (code == 0) {
1786 name = g_strdup_printf ("xlsx_%ix%i", (int)width, (int)height);
1787 display_name = g_strdup_printf (_("Paper from XLSX file: %ipt\xE2\xA8\x89%ipt"),
1788 (int)width, (int)height);
1789 } else {
1790 name = g_strdup_printf ("xlsx_%i", code);
1791 display_name = g_strdup_printf (_("Paper from XLSX file, #%i"), code);
1793 size = gtk_paper_size_new_custom (name, display_name, width, height, unit);
1794 g_free (name);
1795 g_free (display_name);
1796 return size;
1799 static gboolean
1800 xlsx_set_paper_from_code (GnmPrintInformation *pi, int code)
1802 XLSXPaperDefs paper[] =
1803 {{ 0 , 0 , 0 , GTK_UNIT_MM , NULL },
1804 { 1 , 8.5 , 11 , GTK_UNIT_INCH , GTK_PAPER_NAME_LETTER },
1805 { 2 , 8.5 , 11 , GTK_UNIT_INCH , GTK_PAPER_NAME_LETTER },
1806 { 3 , 11 , 17 , GTK_UNIT_INCH , "na_ledger_11x17in" },
1807 { 4 , 17 , 11 , GTK_UNIT_INCH , NULL },
1808 { 5 , 8.5 , 14 , GTK_UNIT_INCH , GTK_PAPER_NAME_LEGAL },
1809 { 6 , 5.5 , 8.5 , GTK_UNIT_INCH , "na_invoice_5.5x8.5in" },
1810 { 7 , 7.25 , 10.5 , GTK_UNIT_INCH , GTK_PAPER_NAME_EXECUTIVE },
1811 { 8 , 297 , 420 , GTK_UNIT_MM , GTK_PAPER_NAME_A3 },
1812 { 9 , 210 , 297 , GTK_UNIT_MM , GTK_PAPER_NAME_A4 },
1813 { 10 , 210 , 297 , GTK_UNIT_MM , GTK_PAPER_NAME_A4 },
1814 { 11 , 148 , 210 , GTK_UNIT_MM , GTK_PAPER_NAME_A5 },
1815 { 12 , 250 , 353 , GTK_UNIT_MM , "iso_b4_250x353mm" },
1816 { 13 , 176 , 250 , GTK_UNIT_MM , GTK_PAPER_NAME_B5 },
1817 { 14 , 8.5 , 13 , GTK_UNIT_INCH , "na_foolscap_8.5x13in" },
1818 { 15 , 215 , 275 , GTK_UNIT_MM , NULL },
1819 { 16 , 10 , 14 , GTK_UNIT_INCH , "na_10x14_10x14in" },
1820 { 17 , 11 , 17 , GTK_UNIT_INCH , "na_ledger_11x17in" },
1821 { 18 , 8.5 , 11 , GTK_UNIT_INCH , GTK_PAPER_NAME_LETTER },
1822 { 19 , 3.875 , 8.875 , GTK_UNIT_INCH , "na_number-9_3.875x8.875in" },
1823 { 20 , 4.125 , 9.5 , GTK_UNIT_INCH , "na_number-10_4.125x9.5in" },
1824 { 21 , 4.5 , 10.375 , GTK_UNIT_INCH , "na_number-11_4.5x10.375in" },
1825 { 22 , 4.75 , 11 , GTK_UNIT_INCH , "na_number-12_4.75x11in" },
1826 { 23 , 5 , 11.5 , GTK_UNIT_INCH , "na_number-14_5x11.5in" },
1827 { 24 , 17 , 22 , GTK_UNIT_INCH , "na_c_17x22in" },
1828 { 25 , 22 , 34 , GTK_UNIT_INCH , "na_d_22x34in" },
1829 { 26 , 34 , 44 , GTK_UNIT_INCH , "na_e_34x44in" },
1830 { 27 , 110 , 220 , GTK_UNIT_MM , "iso_dl_110x220mm" },
1831 { 28 , 162 , 229 , GTK_UNIT_MM , "iso_c5_162x229mm" },
1832 { 29 , 324 , 458 , GTK_UNIT_MM , "iso_c3_324x458mm" },
1833 { 30 , 229 , 324 , GTK_UNIT_MM , "iso_c4_229x324mm" },
1834 { 31 , 114 , 162 , GTK_UNIT_MM , "iso_c6_114x162mm" },
1835 { 32 , 114 , 229 , GTK_UNIT_MM , "iso_c6c5_114x229mm" },
1836 { 33 , 250 , 353 , GTK_UNIT_MM , "iso_b4_250x353mm" },
1837 { 34 , 176 , 250 , GTK_UNIT_MM , GTK_PAPER_NAME_B5 },
1838 { 35 , 176 , 125 , GTK_UNIT_MM , NULL },
1839 { 36 , 110 , 230 , GTK_UNIT_MM , "om_italian_110x230mm" },
1840 { 37 , 3.875 , 7.5 , GTK_UNIT_INCH , "na_monarch_3.875x7.5in" },
1841 { 38 , 3.625 , 6.5 , GTK_UNIT_INCH , "na_personal_3.625x6.5in" },
1842 { 39 , 14.875 , 11 , GTK_UNIT_INCH , NULL },
1843 { 40 , 8.5 , 12 , GTK_UNIT_INCH , "na_fanfold-eur_8.5x12in" },
1844 { 41 , 8.5 , 13 , GTK_UNIT_INCH , "na_foolscap_8.5x13in" },
1845 { 42 , 250 , 353 , GTK_UNIT_MM , "iso_b4_250x353mm" },
1846 { 43 , 200 , 148 , GTK_UNIT_MM , NULL },
1847 { 44 , 9 , 11 , GTK_UNIT_INCH , "na_9x11_9x11in" },
1848 { 45 , 10 , 11 , GTK_UNIT_INCH , "na_10x11_10x11in" },
1849 { 46 , 15 , 11 , GTK_UNIT_INCH , NULL },
1850 { 47 , 220 , 220 , GTK_UNIT_MM , "om_invite_220x220mm" },
1851 { 48 , 0 , 0 , GTK_UNIT_MM , NULL },
1852 { 49 , 0 , 0 , GTK_UNIT_MM , NULL },
1853 { 50 , 9.275 , 12 , GTK_UNIT_INCH , NULL },
1854 { 51 , 9.275 , 15 , GTK_UNIT_INCH , NULL },
1855 { 52 , 11.69 , 18 , GTK_UNIT_INCH , NULL },
1856 { 53 , 236 , 322 , GTK_UNIT_MM , "iso_a4-extra_235.5x322.3" },
1857 { 54 , 8.275 , 11 , GTK_UNIT_INCH , NULL },
1858 { 55 , 210 , 297 , GTK_UNIT_MM , GTK_PAPER_NAME_A4 },
1859 { 56 , 9.275 , 12 , GTK_UNIT_INCH , NULL },
1860 { 57 , 227 , 356 , GTK_UNIT_MM , NULL },
1861 { 58 , 305 , 487 , GTK_UNIT_MM , NULL },
1862 { 59 , 8.5 , 12.69 , GTK_UNIT_INCH , "na_letter-plus_8.5x12.69in" },
1863 { 60 , 210 , 330 , GTK_UNIT_MM , "om_folio_210x330mm" },
1864 { 61 , 148 , 210 , GTK_UNIT_MM , GTK_PAPER_NAME_A5 },
1865 { 62 , 182 , 257 , GTK_UNIT_MM , "jis_b5_182x257mm" },
1866 { 63 , 322 , 445 , GTK_UNIT_MM , "iso_a3-extra_322x445mm" },
1867 { 64 , 174 , 235 , GTK_UNIT_MM , "iso_a5-extra_174x235mm" },
1868 { 65 , 201 , 276 , GTK_UNIT_MM , "iso_b5-extra_201x276mm" },
1869 { 66 , 420 , 594 , GTK_UNIT_MM , "iso_a2_420x594mm" },
1870 { 67 , 297 , 420 , GTK_UNIT_MM , GTK_PAPER_NAME_A3 },
1871 { 68 , 322 , 445 , GTK_UNIT_MM , "iso_a3-extra_322x445mm" },
1872 { 69 , 200 , 148 , GTK_UNIT_MM , NULL },
1873 { 70 , 105 , 148 , GTK_UNIT_MM , "iso_a6_105x148mm" },
1874 { 71 , 240 , 332 , GTK_UNIT_MM , "jpn_kaku2_240x332mm" },
1875 { 72 , 216 , 277 , GTK_UNIT_MM , NULL },
1876 { 73 , 120 , 235 , GTK_UNIT_MM , "jpn_chou3_120x235mm" },
1877 { 74 , 90 , 205 , GTK_UNIT_MM , "jpn_chou4_90x205mm" },
1878 { 75 , 11 , 8.5 , GTK_UNIT_INCH , NULL },
1879 { 76 , 420 , 297 , GTK_UNIT_MM , NULL },
1880 { 77 , 297 , 210 , GTK_UNIT_MM , NULL },
1881 { 78 , 210 , 148 , GTK_UNIT_MM , NULL },
1882 { 79 , 364 , 257 , GTK_UNIT_MM , NULL },
1883 { 80 , 257 , 182 , GTK_UNIT_MM , NULL },
1884 { 81 , 148 , 100 , GTK_UNIT_MM , NULL },
1885 { 82 , 148 , 200 , GTK_UNIT_MM , "jpn_oufuku_148x200mm" },
1886 { 83 , 148 , 105 , GTK_UNIT_MM , NULL },
1887 { 84 , 332 , 240 , GTK_UNIT_MM , NULL },
1888 { 85 , 277 , 216 , GTK_UNIT_MM , NULL },
1889 { 86 , 235 , 120 , GTK_UNIT_MM , NULL },
1890 { 87 , 205 , 90 , GTK_UNIT_MM , NULL },
1891 { 88 , 128 , 182 , GTK_UNIT_MM , "jis_b6_128x182mm" },
1892 { 89 , 182 , 128 , GTK_UNIT_MM , NULL },
1893 { 90 , 12 , 11 , GTK_UNIT_INCH , NULL },
1894 { 91 , 235 , 105 , GTK_UNIT_MM , NULL },
1895 { 92 , 105 , 235 , GTK_UNIT_MM , "jpn_you4_105x235mm" },
1896 { 93 , 146 , 215 , GTK_UNIT_MM , "prc_16k_146x215mm" },
1897 { 94 , 97 , 151 , GTK_UNIT_MM , "prc_32k_97x151mm" },
1898 { 95 , 97 , 151 , GTK_UNIT_MM , "prc_32k_97x151mm" },
1899 { 96 , 102 , 165 , GTK_UNIT_MM , "prc_1_102x165mm" },
1900 { 97 , 102 , 176 , GTK_UNIT_MM , "prc_2_102x176mm" },
1901 { 98 , 125 , 176 , GTK_UNIT_MM , "prc_3_125x176mm" },
1902 { 99 , 110 , 208 , GTK_UNIT_MM , "prc_4_110x208mm" },
1903 { 100 , 110 , 220 , GTK_UNIT_MM , "prc_5_110x220mm" },
1904 { 101 , 120 , 230 , GTK_UNIT_MM , "prc_6_120x230mm" },
1905 { 102 , 160 , 230 , GTK_UNIT_MM , "prc_7_160x230mm" },
1906 { 103 , 120 , 309 , GTK_UNIT_MM , "prc_8_120x309mm" },
1907 { 104 , 229 , 324 , GTK_UNIT_MM , "iso_c4_229x324mm" },
1908 { 105 , 324 , 458 , GTK_UNIT_MM , "prc_10_324x458mm" },
1909 { 106 , 215 , 146 , GTK_UNIT_MM , NULL },
1910 { 107 , 151 , 97 , GTK_UNIT_MM , NULL },
1911 { 108 , 151 , 97 , GTK_UNIT_MM , NULL },
1912 { 109 , 165 , 102 , GTK_UNIT_MM , NULL },
1913 { 110 , 176 , 102 , GTK_UNIT_MM , NULL },
1914 { 111 , 176 , 125 , GTK_UNIT_MM , NULL },
1915 { 112 , 208 , 110 , GTK_UNIT_MM , NULL },
1916 { 113 , 220 , 110 , GTK_UNIT_MM , NULL },
1917 { 114 , 230 , 120 , GTK_UNIT_MM , NULL },
1918 { 115 , 230 , 160 , GTK_UNIT_MM , NULL },
1919 { 116 , 309 , 120 , GTK_UNIT_MM , NULL },
1920 { 117 , 324 , 229 , GTK_UNIT_MM , NULL },
1921 { 118 , 458 , 324 , GTK_UNIT_MM , NULL }};
1923 if (code < 1 || ((guint) code) >= G_N_ELEMENTS (paper) || paper[code].code == 0)
1924 return FALSE;
1925 g_return_val_if_fail (paper[code].code == code, FALSE);
1927 if (paper[code].name != NULL) {
1928 GtkPaperSize *ps = gtk_paper_size_new (paper[code].name);
1929 if (ps != NULL) {
1930 gtk_page_setup_set_paper_size (pi->page_setup, ps);
1931 return TRUE;
1934 if (paper[code].width > 0.0 && paper[code].height > 0.0) {
1935 GtkPaperSize *ps = xlsx_paper_size (paper[code].width, paper[code].height, paper[code].unit, code);
1936 if (ps != NULL) {
1937 gtk_page_setup_set_paper_size (pi->page_setup, ps);
1938 return TRUE;
1942 return FALSE;
1945 static void
1946 xlsx_CT_PageSetup (GsfXMLIn *xin, xmlChar const **attrs)
1948 XLSXReadState *state = (XLSXReadState *)xin->user_state;
1949 GnmPrintInformation *pi = state->sheet->print_info;
1950 int orient, paper_code = 0, scale, tmp_int;
1951 gboolean orient_set = FALSE, first_page_number = TRUE, tmp_bool;
1952 gnm_float width = 0., height = 0.;
1953 static EnumVal const orientation_types[] = {
1954 { "default", GTK_PAGE_ORIENTATION_PORTRAIT },
1955 { "portrait", GTK_PAGE_ORIENTATION_PORTRAIT },
1956 { "landscape", GTK_PAGE_ORIENTATION_LANDSCAPE },
1957 { NULL, 0 }
1959 static EnumVal const comment_types[] = {
1960 { "asDisplayed", GNM_PRINT_COMMENTS_IN_PLACE },
1961 { "atEnd", GNM_PRINT_COMMENTS_AT_END },
1962 { "none", GNM_PRINT_COMMENTS_NONE },
1963 { NULL, 0 }
1965 static EnumVal const error_types[] = {
1966 { "blank", GNM_PRINT_ERRORS_AS_BLANK },
1967 { "dash", GNM_PRINT_ERRORS_AS_DASHES },
1968 { "NA", GNM_PRINT_ERRORS_AS_NA },
1969 { "displayed", GNM_PRINT_ERRORS_AS_DISPLAYED },
1970 { NULL, 0 }
1972 static EnumVal const page_order_types[] = {
1973 { "overThenDown", 1 },
1974 { "downThenOver", 0 },
1975 { NULL, 0 }
1978 if (pi->page_setup == NULL)
1979 gnm_print_info_load_defaults (pi);
1980 /* In xlsx the default is 1 not 0 */
1981 pi->scaling.dim.rows = 1;
1982 pi->scaling.dim.cols = 1;
1984 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
1985 if (attr_enum (xin, attrs, "orientation", orientation_types, &orient))
1986 orient_set = TRUE;
1987 else if (attr_enum (xin, attrs, "cellComments", comment_types, &tmp_int))
1988 pi->comment_placement = tmp_int;
1989 else if (attr_enum (xin, attrs, "errors", error_types, &tmp_int))
1990 pi->error_display = tmp_int;
1991 else if (attr_enum (xin, attrs, "pageOrder", page_order_types, &tmp_int))
1992 pi->print_across_then_down = (tmp_int != 0);
1993 else if (attr_int (xin, attrs, "paperSize", &paper_code))
1995 else if (attr_distance (xin, attrs, "paperWidth", &width))
1997 else if (attr_distance (xin, attrs, "paperHeight", &height))
1999 else if (attr_bool (xin, attrs, "blackAndWhite", &tmp_bool))
2000 pi->print_black_and_white = tmp_bool;
2001 else if (attr_int (xin, attrs, "copies", &(pi->n_copies)))
2003 else if (attr_bool (xin, attrs, "draft", &tmp_bool))
2004 pi->print_as_draft = tmp_bool;
2005 else if (attr_int (xin, attrs, "firstPageNumber", &(pi->start_page)))
2007 else if (attr_int (xin, attrs, "fitToHeight", &(pi->scaling.dim.rows)))
2009 else if (attr_int (xin, attrs, "fitToWidth", &(pi->scaling.dim.cols)))
2011 else if (attr_int (xin, attrs, "scale", &scale)) {
2012 pi->scaling.percentage.x = scale;
2013 pi->scaling.percentage.y = scale;
2014 } else if (attr_bool (xin, attrs, "useFirstPageNumber", &first_page_number))
2018 if (!first_page_number)
2019 pi->start_page = -1;
2021 if (!xlsx_set_paper_from_code (pi, paper_code) && width > 0.0 && height > 0.0)
2022 gtk_page_setup_set_paper_size (pi->page_setup,
2023 xlsx_paper_size (width, height, GTK_UNIT_POINTS, 0));
2024 if (orient_set)
2025 print_info_set_paper_orientation (pi, orient);
2028 static void
2029 xlsx_CT_PageMargins (GsfXMLIn *xin, xmlChar const **attrs)
2031 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2032 gnm_float margin;
2033 GnmPrintInformation *pi = state->sheet->print_info;
2035 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2036 if (attr_float (xin, attrs, "left", &margin))
2037 print_info_set_margin_left (pi, GO_IN_TO_PT (margin));
2038 else if (attr_float (xin, attrs, "right", &margin))
2039 print_info_set_margin_right (pi, GO_IN_TO_PT (margin));
2040 else if (attr_float (xin, attrs, "top", &margin))
2041 print_info_set_edge_to_below_header (pi, GO_IN_TO_PT (margin));
2042 else if (attr_float (xin, attrs, "bottom", &margin))
2043 print_info_set_edge_to_above_footer (pi, GO_IN_TO_PT (margin));
2044 else if (attr_float (xin, attrs, "header", &margin))
2045 print_info_set_margin_header (pi, GO_IN_TO_PT (margin));
2046 else if (attr_float (xin, attrs, "footer", &margin))
2047 print_info_set_margin_footer (pi, GO_IN_TO_PT (margin));
2052 static void
2053 xlsx_CT_oddheader_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2055 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2056 GnmPrintInformation *pi = state->sheet->print_info;
2057 xls_header_footer_import (&pi->header, xin->content->str);
2060 static void
2061 xlsx_CT_oddfooter_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2063 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2064 GnmPrintInformation *pi = state->sheet->print_info;
2065 xls_header_footer_import (&pi->footer, xin->content->str);
2068 static void
2069 xlsx_CT_PageBreak (GsfXMLIn *xin, xmlChar const **attrs)
2071 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2072 GnmPageBreakType type = GNM_PAGE_BREAK_AUTO;
2073 gboolean tmp;
2074 int pos;
2075 int first, last;
2077 if (NULL == state->page_breaks)
2078 return;
2080 pos = 0;
2082 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2083 if (attr_int (xin, attrs, "id", &pos))
2085 else if (attr_bool (xin, attrs, "man", &tmp)) {
2086 if (tmp) type = GNM_PAGE_BREAK_MANUAL;
2087 } else if (attr_bool (xin, attrs, "pt", &tmp)) {
2088 if (tmp) type = GNM_PAGE_BREAK_DATA_SLICE;
2089 } else if (attr_int (xin, attrs, "min", &first))
2091 else if (attr_int (xin, attrs, "max", &last))
2095 gnm_page_breaks_append_break (state->page_breaks, pos, type);
2098 static void
2099 xlsx_CT_PageBreaks_begin (GsfXMLIn *xin, xmlChar const **attrs)
2101 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2102 int count = 0;
2103 int manual_count;
2105 g_return_if_fail (state->page_breaks == NULL);
2107 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2108 if (attr_int (xin, attrs, "count", &count))
2110 else if (attr_int (xin, attrs, "manualBreakCount", &manual_count))
2114 state->page_breaks = gnm_page_breaks_new (xin->node->user_data.v_int);
2117 static void
2118 xlsx_CT_PageBreaks_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2120 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2122 if (NULL != state->page_breaks) {
2123 print_info_set_breaks (state->sheet->print_info,
2124 state->page_breaks);
2125 state->page_breaks = NULL;
2129 static void
2130 xlsx_CT_DataValidation_begin (GsfXMLIn *xin, xmlChar const **attrs)
2132 static EnumVal const val_styles[] = {
2133 { "stop", GNM_VALIDATION_STYLE_STOP },
2134 { "warning", GNM_VALIDATION_STYLE_WARNING },
2135 { "information", GNM_VALIDATION_STYLE_INFO },
2136 { NULL, 0 }
2138 static EnumVal const val_types[] = {
2139 { "none", GNM_VALIDATION_TYPE_ANY },
2140 { "whole", GNM_VALIDATION_TYPE_AS_INT },
2141 { "decimal", GNM_VALIDATION_TYPE_AS_NUMBER },
2142 { "list", GNM_VALIDATION_TYPE_IN_LIST },
2143 { "date", GNM_VALIDATION_TYPE_AS_DATE },
2144 { "time", GNM_VALIDATION_TYPE_AS_TIME },
2145 { "textLength", GNM_VALIDATION_TYPE_TEXT_LENGTH },
2146 { "custom", GNM_VALIDATION_TYPE_CUSTOM },
2147 { NULL, 0 }
2149 static EnumVal const val_ops[] = {
2150 { "between", GNM_VALIDATION_OP_BETWEEN },
2151 { "notBetween", GNM_VALIDATION_OP_NOT_BETWEEN },
2152 { "equal", GNM_VALIDATION_OP_EQUAL },
2153 { "notEqual", GNM_VALIDATION_OP_NOT_EQUAL },
2154 { "lessThan", GNM_VALIDATION_OP_LT },
2155 { "lessThanOrEqual", GNM_VALIDATION_OP_LTE },
2156 { "greaterThan", GNM_VALIDATION_OP_GT },
2157 { "greaterThanOrEqual", GNM_VALIDATION_OP_GTE },
2158 { NULL, 0 }
2160 #if 0
2161 /* Get docs on this */
2162 "imeMode" default="noControl"
2163 "noControl"
2164 "off"
2165 "on"
2166 "disabled"
2167 "hiragana"
2168 "fullKatakana"
2169 "halfKatakana"
2170 "fullAlpha"
2171 "halfAlpha"
2172 "fullHangul"
2173 "halfHangul"
2174 #endif
2176 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2178 /* defaults */
2179 ValidationStyle val_style = GNM_VALIDATION_STYLE_STOP;
2180 ValidationType val_type = GNM_VALIDATION_TYPE_ANY;
2181 ValidationOp val_op = GNM_VALIDATION_OP_BETWEEN;
2182 gboolean allowBlank = FALSE;
2183 gboolean showDropDown = FALSE;
2184 gboolean showInputMessage = FALSE;
2185 gboolean showErrorMessage = FALSE;
2186 xmlChar const *errorTitle = NULL;
2187 xmlChar const *error = NULL;
2188 xmlChar const *promptTitle = NULL;
2189 xmlChar const *prompt = NULL;
2190 xmlChar const *refs = NULL;
2191 int tmp;
2193 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2194 if (0 == strcmp (attrs[0], "sqref"))
2195 refs = attrs[1];
2196 else if (attr_enum (xin, attrs, "errorStyle", val_styles, &tmp))
2197 val_style = tmp;
2198 else if (attr_enum (xin, attrs, "type", val_types, &tmp))
2199 val_type = tmp;
2200 else if (attr_enum (xin, attrs, "operator", val_ops, &tmp))
2201 val_op = tmp;
2203 else if (attr_bool (xin, attrs, "allowBlank", &allowBlank))
2205 else if (attr_bool (xin, attrs, "showDropDown", &showDropDown))
2207 else if (attr_bool (xin, attrs, "showInputMessage", &showInputMessage))
2209 else if (attr_bool (xin, attrs, "showErrorMessage", &showErrorMessage))
2211 else if (0 == strcmp (attrs[0], "errorTitle"))
2212 errorTitle = attrs[1];
2213 else if (0 == strcmp (attrs[0], "error"))
2214 error = attrs[1];
2215 else if (0 == strcmp (attrs[0], "promptTitle"))
2216 promptTitle = attrs[1];
2217 else if (0 == strcmp (attrs[0], "prompt"))
2218 prompt = attrs[1];
2221 /* order matters, we need the 1st item */
2222 state->validation_regions = g_slist_reverse (
2223 xlsx_parse_sqref (xin, refs));
2225 if (NULL == state->validation_regions)
2226 return;
2228 if (showErrorMessage) {
2229 GnmRange const *r = state->validation_regions->data;
2230 state->pos = r->start;
2231 state->validation = gnm_validation_new
2232 (val_style, val_type, val_op,
2233 state->sheet,
2234 errorTitle, error,
2235 NULL, NULL, allowBlank, showDropDown);
2238 if (showInputMessage && (NULL != promptTitle || NULL != prompt))
2239 state->input_msg = gnm_input_msg_new (prompt, promptTitle);
2242 static void
2243 xlsx_CT_DataValidation_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2245 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2246 GError *err;
2247 GnmStyle *style = NULL;
2248 GSList *ptr;
2250 if (NULL != state->validation &&
2251 NULL != (err = gnm_validation_is_ok (state->validation))) {
2252 xlsx_warning (xin, _("Ignoring invalid data validation because : %s"),
2253 _(err->message));
2254 gnm_validation_unref (state->validation);
2255 state->validation = NULL;
2258 if (NULL != state->validation) {
2259 style = gnm_style_new ();
2260 gnm_style_set_validation (style, state->validation);
2261 state->validation = NULL;
2264 if (NULL != state->input_msg) {
2265 if (NULL == style)
2266 style = gnm_style_new ();
2267 gnm_style_set_input_msg (style, state->input_msg);
2268 state->input_msg = NULL;
2271 for (ptr = state->validation_regions ; ptr != NULL ; ptr = ptr->next) {
2272 if (NULL != style) {
2273 gnm_style_ref (style);
2274 sheet_style_apply_range (state->sheet, ptr->data, style);
2276 g_free (ptr->data);
2278 if (NULL != style)
2279 gnm_style_unref (style);
2280 g_slist_free (state->validation_regions);
2281 state->validation_regions = NULL;
2282 state->pos.col = state->pos.row = -1;
2285 static void
2286 xlsx_validation_expr (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2288 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2289 GnmParsePos pp;
2290 GnmExprTop const *texpr;
2292 if (state->validation == NULL)
2293 return;
2295 /* Sneaky buggers, parse relative to the 1st sqRef */
2296 parse_pos_init (&pp, NULL, state->sheet,
2297 state->pos.col, state->pos.row);
2298 texpr = xlsx_parse_expr (xin, xin->content->str, &pp);
2299 if (NULL != texpr) {
2300 gnm_validation_set_expr (state->validation, texpr,
2301 xin->node->user_data.v_int);
2302 gnm_expr_top_unref (texpr);
2306 static void
2307 xlsx_CT_AutoFilter_begin (GsfXMLIn *xin, xmlChar const **attrs)
2309 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2310 GnmRange r;
2312 g_return_if_fail (state->filter == NULL);
2314 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2315 if (attr_range (xin, attrs, "ref", &r))
2316 state->filter = gnm_filter_new (state->sheet, &r);
2320 static void
2321 xlsx_CT_AutoFilter_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2323 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2324 g_return_if_fail (state->filter != NULL);
2325 state->filter = NULL;
2328 static void
2329 xlsx_CT_FilterColumn_begin (GsfXMLIn *xin, xmlChar const **attrs)
2331 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2332 int id = -1;
2333 gboolean hidden = FALSE;
2334 gboolean show = TRUE;
2336 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2337 if (attr_int (xin, attrs, "colId", &id))
2339 else if (attr_bool (xin, attrs, "hiddenButton", &hidden))
2341 else if (attr_bool (xin, attrs, "showButton", &show))
2345 state->filter_cur_field = id;
2348 static void
2349 xlsx_CT_Filters_begin (GsfXMLIn *xin, xmlChar const **attrs)
2351 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2353 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2354 if (0 == strcmp (attrs[0], "val")) {
2357 state->filter_items = NULL;
2359 static void
2360 xlsx_CT_Filters_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2362 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2363 state->filter_items = NULL;
2365 static void
2366 xlsx_CT_Filter (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2368 #if 0
2369 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2371 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2372 if (0 == strcmp (attrs[0], "val")) {
2374 #endif
2377 static void
2378 xlsx_CT_CustomFilters_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2380 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2382 #if 0
2383 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
2384 if (0 == strcmp (attrs[0], "val")) {
2386 #endif
2387 state->filter_items = NULL;
2389 static void
2390 xlsx_CT_CustomFilters_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2392 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2393 state->filter_items = NULL;
2396 static void
2397 xlsx_CT_CustomFilter (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2399 static EnumVal const ops[] = {
2400 { "lessThan", GNM_FILTER_OP_LT },
2401 { "lessThanOrEqual", GNM_FILTER_OP_LTE },
2402 { "equal", GNM_FILTER_OP_EQUAL },
2403 { "notEqual", GNM_FILTER_OP_NOT_EQUAL },
2404 { "greaterThanOrEqual", GNM_FILTER_OP_GTE },
2405 { "greaterThan", GNM_FILTER_OP_GT },
2406 { NULL, 0 }
2408 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2409 int tmp;
2410 GnmFilterOp op = GNM_FILTER_OP_EQUAL;
2411 GnmValue *v = NULL;
2412 GnmFilterCondition *cond;
2413 GODateConventions const *date_conv = workbook_date_conv (state->wb);
2415 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2416 if (0 == strcmp (attrs[0], "val")) {
2417 const char *txt = CXML2C (attrs[1]);
2418 value_release (v);
2419 v = format_match (txt, NULL, date_conv);
2420 if (!v)
2421 v = value_new_string (txt);
2422 } else if (attr_enum (xin, attrs, "operator", ops, &tmp)) {
2423 op = tmp;
2427 cond = gnm_filter_condition_new_single (op, v);
2428 if (cond)
2429 gnm_filter_set_condition (state->filter, state->filter_cur_field,
2430 cond, FALSE);
2433 static void
2434 xlsx_CT_Top10 (GsfXMLIn *xin, xmlChar const **attrs)
2436 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2437 gboolean top = TRUE;
2438 gboolean percent = FALSE;
2439 gnm_float val = -1.;
2440 GnmFilterCondition *cond;
2442 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2443 if (attr_float (xin, attrs, "val", &val))
2445 else if (attr_bool (xin, attrs, "top", &top))
2447 else if (attr_bool (xin, attrs, "percent", &percent))
2451 if (NULL != (cond = gnm_filter_condition_new_bucket (top, !percent, FALSE, val)))
2452 gnm_filter_set_condition (state->filter, state->filter_cur_field,
2453 cond, FALSE);
2456 static void
2457 xlsx_CT_DynamicFilter (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
2459 #if 0
2460 static EnumVal const types[] = {
2461 { "null", 0 },
2462 { "aboveAverage", 0 },
2463 { "belowAverage", 0 },
2464 { "tomorrow", 0 },
2465 { "today", 0 },
2466 { "yesterday", 0 },
2467 { "nextWeek", 0 },
2468 { "thisWeek", 0 },
2469 { "lastWeek", 0 },
2470 { "nextMonth", 0 },
2471 { "thisMonth", 0 },
2472 { "lastMonth", 0 },
2473 { "nextQuarter", 0 },
2474 { "thisQuarter", 0 },
2475 { "lastQuarter", 0 },
2476 { "nextYear", 0 },
2477 { "thisYear", 0 },
2478 { "lastYear", 0 },
2479 { "yearToDate", 0 },
2480 { "Q1", 0 },
2481 { "Q2", 0 },
2482 { "Q3", 0 },
2483 { "Q4", 0 },
2484 { "M1", 0 },
2485 { "M2", 0 },
2486 { "M3", 0 },
2487 { "M4", 0 },
2488 { "M5", 0 },
2489 { "M6", 0 },
2490 { "M7", 0 },
2491 { "M8", 0 },
2492 { "M9", 0 },
2493 { "M10", 0 },
2494 { "M11", 0 },
2495 { "M12", 0 },
2496 { NULL, 0 }
2498 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2499 int type = -1;
2501 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2502 if (attr_enum (xin, attrs, "type", types, &type))
2505 #endif
2508 static void
2509 xlsx_CT_MergeCell (GsfXMLIn *xin, xmlChar const **attrs)
2511 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2512 GnmRange r;
2514 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2515 if (attr_range (xin, attrs, "ref", &r))
2516 gnm_sheet_merge_add (state->sheet, &r, FALSE,
2517 GO_CMD_CONTEXT (state->context));
2521 static void
2522 xlsx_CT_SheetProtection (GsfXMLIn *xin, xmlChar const **attrs)
2524 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2525 gboolean sheet = FALSE;
2526 gboolean objects = FALSE;
2527 gboolean scenarios = FALSE;
2528 gboolean formatCells = TRUE;
2529 gboolean formatColumns = TRUE;
2530 gboolean formatRows = TRUE;
2531 gboolean insertColumns = TRUE;
2532 gboolean insertRows = TRUE;
2533 gboolean insertHyperlinks = TRUE;
2534 gboolean deleteColumns = TRUE;
2535 gboolean deleteRows = TRUE;
2536 gboolean selectLockedCells = FALSE;
2537 gboolean sort = TRUE;
2538 gboolean autoFilter = TRUE;
2539 gboolean pivotTables = TRUE;
2540 gboolean selectUnlockedCells = FALSE;
2542 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2543 if (attr_bool (xin, attrs, "sheet", &sheet))
2545 else if (attr_bool (xin, attrs, "objects", &objects))
2547 else if (attr_bool (xin, attrs, "scenarios", &scenarios))
2549 else if (attr_bool (xin, attrs, "formatCells", &formatCells))
2551 else if (attr_bool (xin, attrs, "formatColumns", &formatColumns))
2553 else if (attr_bool (xin, attrs, "formatRows", &formatRows))
2555 else if (attr_bool (xin, attrs, "insertColumns", &insertColumns))
2557 else if (attr_bool (xin, attrs, "insertRows", &insertRows))
2559 else if (attr_bool (xin, attrs, "insertHyperlinks", &insertHyperlinks))
2561 else if (attr_bool (xin, attrs, "deleteColumns", &deleteColumns))
2563 else if (attr_bool (xin, attrs, "deleteRows", &deleteRows))
2565 else if (attr_bool (xin, attrs, "selectLockedCells", &selectLockedCells))
2567 else if (attr_bool (xin, attrs, "sort", &sort))
2569 else if (attr_bool (xin, attrs, "autoFilter", &autoFilter))
2571 else if (attr_bool (xin, attrs, "pivotTables", &pivotTables))
2573 else if (attr_bool (xin, attrs, "selectUnlockedCells", &selectUnlockedCells))
2577 g_object_set (state->sheet,
2578 "protected", sheet,
2579 "protected-allow-edit-objects", objects,
2580 "protected-allow-edit-scenarios", scenarios,
2581 "protected-allow-cell-formatting", formatCells,
2582 "protected-allow-column-formatting", formatColumns,
2583 "protected-allow-row-formatting", formatRows,
2584 "protected-allow-insert-columns", insertColumns,
2585 "protected-allow-insert-rows", insertRows,
2586 "protected-allow-insert-hyperlinks", insertHyperlinks,
2587 "protected-allow-delete-columns", deleteColumns,
2588 "protected-allow-delete-rows", deleteRows,
2589 "protected-allow-select-locked-cells", selectLockedCells,
2590 "protected-allow-sort-ranges", sort,
2591 "protected-allow-edit-auto-filters", autoFilter,
2592 "protected-allow-edit-pivottable", pivotTables,
2593 "protected-allow-select-unlocked-cells", selectUnlockedCells,
2594 NULL);
2597 static void
2598 xlsx_cond_fmt_begin (GsfXMLIn *xin, xmlChar const **attrs)
2600 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2601 char const *refs = NULL;
2603 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2604 if (0 == strcmp (attrs[0], "sqref"))
2605 refs = attrs[1];
2608 state->cond_regions = xlsx_parse_sqref (xin, refs);
2610 /* create in first call xlsx_cond_rule to avoid creating condition with
2611 * no rules */
2612 state->conditions = NULL;
2615 static void
2616 xlsx_cond_fmt_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2618 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2619 GnmStyle *style = NULL;
2620 GSList *ptr;
2622 if (NULL != state->conditions) {
2623 style = gnm_style_new ();
2624 gnm_style_set_conditions (style, state->conditions);
2625 for (ptr = state->cond_regions ; ptr != NULL ; ptr = ptr->next) {
2626 gnm_style_ref (style);
2627 sheet_style_apply_range (state->sheet, ptr->data, style);
2628 g_free (ptr->data);
2630 gnm_style_unref (style);
2631 } else for (ptr = state->cond_regions ; ptr != NULL ; ptr = ptr->next)
2632 g_free (ptr->data);
2633 g_slist_free (state->cond_regions);
2634 state->cond_regions = NULL;
2637 typedef enum {
2638 XLSX_CF_TYPE_UNDEFINED,
2640 XLSX_CF_TYPE_EXPRESSION,
2641 XLSX_CF_TYPE_CELL_IS,
2642 XLSX_CF_TYPE_COLOR_SCALE,
2643 XLSX_CF_TYPE_DATA_BAR,
2644 XLSX_CF_TYPE_ICON_SET,
2645 XLSX_CF_TYPE_TOP10,
2646 XLSX_CF_TYPE_UNIQUE_VALUES,
2647 XLSX_CF_TYPE_DUPLICATE_VALUES,
2648 XLSX_CF_TYPE_CONTAINS_STR,
2649 XLSX_CF_TYPE_NOT_CONTAINS_STR,
2650 XLSX_CF_TYPE_BEGINS_WITH,
2651 XLSX_CF_TYPE_ENDS_WITH,
2652 XLSX_CF_TYPE_CONTAINS_BLANKS,
2653 XLSX_CF_TYPE_NOT_CONTAINS_BLANKS,
2654 XLSX_CF_TYPE_CONTAINS_ERRORS,
2655 XLSX_CF_TYPE_NOT_CONTAINS_ERRORS,
2656 XLSX_CF_TYPE_COMPARE_COLUMNS,
2657 XLSX_CF_TYPE_TIME_PERIOD,
2658 XLSX_CF_TYPE_ABOVE_AVERAGE
2659 } XlsxCFTypes;
2660 static void
2661 xlsx_cond_fmt_rule_begin (GsfXMLIn *xin, xmlChar const **attrs)
2663 static EnumVal const ops[] = {
2664 { "lessThan", GNM_STYLE_COND_LT },
2665 { "lessThanOrEqual", GNM_STYLE_COND_LTE },
2666 { "equal", GNM_STYLE_COND_EQUAL },
2667 { "notEqual", GNM_STYLE_COND_NOT_EQUAL },
2668 { "greaterThanOrEqual", GNM_STYLE_COND_GTE },
2669 { "greaterThan", GNM_STYLE_COND_GT },
2670 { "between", GNM_STYLE_COND_BETWEEN },
2671 { "notBetween", GNM_STYLE_COND_NOT_BETWEEN },
2672 { "containsText", GNM_STYLE_COND_CONTAINS_STR },
2673 { "notContainsText", GNM_STYLE_COND_NOT_CONTAINS_STR },
2674 { "beginsWith", GNM_STYLE_COND_BEGINS_WITH_STR },
2675 { "endsWith", GNM_STYLE_COND_ENDS_WITH_STR },
2676 { "notContain", GNM_STYLE_COND_NOT_CONTAINS_STR },
2677 { NULL, 0 }
2680 static EnumVal const types[] = {
2681 { "expression", XLSX_CF_TYPE_EXPRESSION },
2682 { "cellIs", XLSX_CF_TYPE_CELL_IS },
2683 { "colorScale", XLSX_CF_TYPE_COLOR_SCALE },
2684 { "dataBar", XLSX_CF_TYPE_DATA_BAR },
2685 { "iconSet", XLSX_CF_TYPE_ICON_SET },
2686 { "top10", XLSX_CF_TYPE_TOP10 },
2687 { "uniqueValues", XLSX_CF_TYPE_UNIQUE_VALUES },
2688 { "duplicateValues", XLSX_CF_TYPE_DUPLICATE_VALUES },
2689 { "containsText", XLSX_CF_TYPE_CONTAINS_STR },
2690 { "doesNotContainText", XLSX_CF_TYPE_NOT_CONTAINS_STR }, /* ??? */
2691 { "notContainsText", XLSX_CF_TYPE_NOT_CONTAINS_STR },
2692 { "beginsWith", XLSX_CF_TYPE_BEGINS_WITH },
2693 { "endsWith", XLSX_CF_TYPE_ENDS_WITH },
2694 { "containsBlanks", XLSX_CF_TYPE_CONTAINS_BLANKS },
2695 { "containsNoBlanks", XLSX_CF_TYPE_NOT_CONTAINS_BLANKS }, /* ??? */
2696 { "notContainsBlanks", XLSX_CF_TYPE_NOT_CONTAINS_BLANKS },
2697 { "containsErrors", XLSX_CF_TYPE_CONTAINS_ERRORS },
2698 { "containsNoErrors", XLSX_CF_TYPE_NOT_CONTAINS_ERRORS }, /* ??? */
2699 { "notContainsErrors", XLSX_CF_TYPE_NOT_CONTAINS_ERRORS },
2700 { "compareColumns", XLSX_CF_TYPE_COMPARE_COLUMNS },
2701 { "timePeriod", XLSX_CF_TYPE_TIME_PERIOD },
2702 { "aboveAverage", XLSX_CF_TYPE_ABOVE_AVERAGE },
2703 { NULL, 0 }
2706 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2707 gboolean formatRow = FALSE;
2708 gboolean stopIfTrue = FALSE;
2709 gboolean above = TRUE;
2710 gboolean percent = FALSE;
2711 gboolean bottom = FALSE;
2712 int tmp, dxf = -1;
2713 /* use custom invalid flag, it is not in MS enum */
2714 GnmStyleCondOp op = GNM_STYLE_COND_CUSTOM;
2715 XlsxCFTypes type = XLSX_CF_TYPE_UNDEFINED;
2716 char const *type_str = "-";
2717 GnmStyle *overlay = NULL;
2719 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2720 if (attr_bool (xin, attrs, "formatRow", &formatRow))
2722 else if (attr_bool (xin, attrs, "stopIfTrue", &stopIfTrue))
2724 else if (attr_bool (xin, attrs, "above", &above))
2726 else if (attr_bool (xin, attrs, "percent", &percent))
2728 else if (attr_bool (xin, attrs, "bottom", &bottom))
2730 else if (attr_int (xin, attrs, "dxfId", &dxf))
2732 else if (attr_enum (xin, attrs, "operator", ops, &tmp))
2733 op = tmp;
2734 else if (attr_enum (xin, attrs, "type", types, &tmp)) {
2735 type = tmp;
2736 type_str = attrs[1];
2739 #if 0
2741 "numFmtId" ="ST_NumFmtId" use="optional">
2742 "priority" ="xs:int" use="required">
2743 "text" ="xs:string" use="optional">
2744 "timePeriod" ="ST_TimePeriod" use="optional">
2745 "col1" ="xs:unsignedInt" use="optional">
2746 "col2" ="xs:unsignedInt" use="optional">
2748 #endif
2750 if (dxf >= 0)
2751 overlay = xlsx_get_dxf (xin, dxf);
2753 switch (type) {
2754 case XLSX_CF_TYPE_CELL_IS :
2755 /* Nothing */
2756 break;
2757 case XLSX_CF_TYPE_CONTAINS_STR:
2758 case XLSX_CF_TYPE_NOT_CONTAINS_STR:
2759 case XLSX_CF_TYPE_BEGINS_WITH:
2760 case XLSX_CF_TYPE_ENDS_WITH:
2761 case XLSX_CF_TYPE_CONTAINS_BLANKS:
2762 case XLSX_CF_TYPE_NOT_CONTAINS_BLANKS:
2763 case XLSX_CF_TYPE_CONTAINS_ERRORS:
2764 case XLSX_CF_TYPE_NOT_CONTAINS_ERRORS:
2765 /* The expressions stored for these are the full
2766 expressions, not just what we search for. */
2767 op = GNM_STYLE_COND_CUSTOM;
2768 break;
2770 case XLSX_CF_TYPE_EXPRESSION:
2771 op = GNM_STYLE_COND_CUSTOM;
2772 break;
2774 default :
2775 xlsx_warning (xin, _("Ignoring unhandled conditional format of type '%s'"), type_str);
2778 state->cond = gnm_style_cond_new (op, state->sheet);
2779 gnm_style_cond_set_overlay (state->cond, overlay);
2781 state->count = 0;
2784 static void
2785 xlsx_cond_fmt_rule_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2787 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2788 if (state->cond) {
2789 if (gnm_style_cond_is_valid (state->cond)) {
2790 if (NULL == state->conditions)
2791 state->conditions = gnm_style_conditions_new (state->sheet);
2792 /* Reverse the alternate-expression treatment. */
2793 gnm_style_cond_canonicalize (state->cond);
2795 gnm_style_conditions_insert (state->conditions,
2796 state->cond, -1);
2798 gnm_style_cond_free (state->cond);
2799 state->cond = NULL;
2803 static void
2804 xlsx_cond_fmt_formula_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2806 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2807 GnmParsePos pp;
2808 GnmExprTop const *texpr;
2809 GnmCellPos const *cp;
2811 if (!state->cond || state->count > 1 || state->cond_regions == NULL)
2812 return;
2814 cp = g_slist_last (state->cond_regions)->data;
2815 parse_pos_init (&pp, state->sheet->workbook, state->sheet, cp->col, cp->row);
2816 texpr = xlsx_parse_expr (xin, xin->content->str, &pp);
2817 if (texpr) {
2818 gnm_style_cond_set_expr (state->cond, texpr, state->count);
2819 gnm_expr_top_unref (texpr);
2822 state->count++;
2825 static void
2826 xlsx_CT_SheetView_begin (GsfXMLIn *xin, xmlChar const **attrs)
2828 /* static EnumVal const view_types[] = { */
2829 /* { "normal", GNM_SHEET_VIEW_NORMAL_MODE }, */
2830 /* { "pageBreakPreview", GNM_SHEET_VIEW_PAGE_BREAK_MODE }, */
2831 /* { "pageLayout", GNM_SHEET_VIEW_LAYOUT_MODE }, */
2832 /* { NULL, 0 } */
2833 /* }; */
2835 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2836 int showGridLines = TRUE;
2837 int showFormulas = FALSE;
2838 int showRowColHeaders = TRUE;
2839 int showZeros = TRUE;
2840 int frozen = FALSE;
2841 int frozenSplit = TRUE;
2842 int rightToLeft = FALSE;
2843 int tabSelected = FALSE;
2844 int active = FALSE;
2845 int showRuler = TRUE;
2846 int showOutlineSymbols = TRUE;
2847 int defaultGridColor = TRUE;
2848 int showWhiteSpace = TRUE;
2849 int scale = 100;
2850 int grid_color_index = -1;
2851 /* int tmp; */
2852 /* GnmSheetViewMode view_mode = GNM_SHEET_VIEW_NORMAL_MODE; */
2853 GnmCellPos topLeft = { -1, -1 };
2855 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2856 if (attr_pos (xin, attrs, "topLeftCell", &topLeft) ||
2857 attr_bool (xin, attrs, "showGridLines", &showGridLines) ||
2858 attr_bool (xin, attrs, "showFormulas", &showFormulas) ||
2859 attr_bool (xin, attrs, "showRowColHeaders", &showRowColHeaders) ||
2860 attr_bool (xin, attrs, "showZeros", &showZeros) ||
2861 attr_bool (xin, attrs, "frozen", &frozen) ||
2862 attr_bool (xin, attrs, "frozenSplit", &frozenSplit) ||
2863 attr_bool (xin, attrs, "rightToLeft", &rightToLeft) ||
2864 attr_bool (xin, attrs, "tabSelected", &tabSelected) ||
2865 attr_bool (xin, attrs, "active", &active) ||
2866 attr_bool (xin, attrs, "showRuler", &showRuler) ||
2867 attr_bool (xin, attrs, "showOutlineSymbols", &showOutlineSymbols) ||
2868 attr_bool (xin, attrs, "defaultGridColor", &defaultGridColor) ||
2869 attr_bool (xin, attrs, "showWhiteSpace", &showWhiteSpace) ||
2870 attr_int (xin, attrs, "zoomScale", &scale) ||
2871 attr_int (xin, attrs, "colorId", &grid_color_index))
2873 /* else if (attr_enum (xin, attrs, "view", view_types, &tmp)) */
2874 /* view_mode = tmp; */
2875 #if 0
2876 "zoomScaleNormal" type="xs:unsignedInt" use="optional" default="0"
2877 "zoomScaleSheetLayoutView" type="xs:unsignedInt" use="optional" default="0"
2878 "zoomScalePageLayoutView" type="xs:unsignedInt" use="optional" default="0"
2879 "workbookViewId" type="xs:unsignedInt" use="required"
2880 #endif
2883 /* get this from the workbookViewId */
2884 g_return_if_fail (state->sv == NULL);
2885 state->sv = sheet_get_view (state->sheet, state->wb_view);
2886 state->pane_pos = XLSX_PANE_TOP_LEFT;
2888 /* until we import multiple views unfreeze just in case a previous view
2889 * had frozen */
2890 gnm_sheet_view_freeze_panes (state->sv, NULL, NULL);
2892 if (topLeft.col >= 0)
2893 gnm_sheet_view_set_initial_top_left (state->sv, topLeft.col, topLeft.row);
2894 g_object_set (state->sheet,
2895 "text-is-rtl", rightToLeft,
2896 "display-formulas", showFormulas,
2897 "display-zeros", showZeros,
2898 "display-grid", showGridLines,
2899 "display-column-header", showRowColHeaders,
2900 "display-row-header", showRowColHeaders,
2901 "display-outlines", showOutlineSymbols,
2902 "zoom-factor", ((double)scale) / 100.,
2903 NULL);
2904 #if 0
2905 gboolean active = FALSE;
2906 gboolean showRuler = TRUE;
2907 gboolean showWhiteSpace = TRUE;
2908 #endif
2910 #if 0
2911 g_object_set (state->sv,
2912 "displayMode", view_mode,
2913 NULL);
2914 #endif
2916 if (!defaultGridColor && grid_color_index >= 0)
2917 sheet_style_set_auto_pattern_color (state->sheet,
2918 gnm_color_new_go (indexed_color (state, grid_color_index)));
2919 if (tabSelected)
2920 wb_view_sheet_focus (state->wb_view, state->sheet);
2922 static void
2923 xlsx_CT_SheetView_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
2925 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2926 g_return_if_fail (state->sv != NULL);
2927 state->sv = NULL;
2930 static EnumVal const pane_types[] = {
2931 { "topLeft", XLSX_PANE_TOP_LEFT },
2932 { "topRight", XLSX_PANE_TOP_RIGHT },
2933 { "bottomLeft", XLSX_PANE_BOTTOM_LEFT },
2934 { "bottomRight", XLSX_PANE_BOTTOM_RIGHT },
2935 { NULL, 0 }
2937 static void
2938 xlsx_CT_Selection (GsfXMLIn *xin, xmlChar const **attrs)
2940 XLSXReadState *state = (XLSXReadState *)xin->user_state;
2941 GnmCellPos edit_pos = { -1, -1 };
2942 int i, sel_with_edit_pos = 0;
2943 char const *refs = NULL;
2944 XLSXPanePos pane_pos = XLSX_PANE_TOP_LEFT;
2945 GnmRange r;
2946 GSList *ptr, *accum = NULL;
2948 g_return_if_fail (state->sv != NULL);
2950 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
2951 if (0 == strcmp (attrs[0], "sqref"))
2952 refs = attrs[1];
2953 else if (attr_enum (xin, attrs, "activePane", pane_types, &i))
2954 pane_pos = i;
2955 else if (attr_pos (xin, attrs, "activeCell", &edit_pos))
2957 else if (attr_int (xin, attrs, "activeCellId", &sel_with_edit_pos))
2961 if (pane_pos != state->pane_pos)
2962 return;
2964 for (i = 0 ; NULL != refs && *refs ; i++) {
2965 if (NULL == (refs = cellpos_parse (refs, gnm_sheet_get_size (state->sheet), &r.start, FALSE)))
2966 return;
2968 if (*refs == '\0' || *refs == ' ')
2969 r.end = r.start;
2970 else if (*refs != ':' ||
2971 NULL == (refs = cellpos_parse (refs + 1, gnm_sheet_get_size (state->sheet), &r.end, FALSE)))
2972 return;
2974 if (i == 0)
2975 sv_selection_reset (state->sv);
2977 /* gnumeric assumes the edit_pos is in the last selected range.
2978 * We need to re-order the selection list. */
2979 if (i <= sel_with_edit_pos && edit_pos.col >= 0)
2980 accum = g_slist_prepend (accum, gnm_range_dup (&r));
2981 else
2982 sv_selection_add_range (state->sv, &r);
2983 while (*refs == ' ')
2984 refs++;
2987 if (NULL != accum) {
2988 accum = g_slist_reverse (accum);
2989 for (ptr = accum ; ptr != NULL ; ptr = ptr->next) {
2990 sv_selection_add_range (state->sv, ptr->data);
2991 g_free (ptr->data);
2993 gnm_sheet_view_set_edit_pos (state->sv, &edit_pos);
2994 g_slist_free (accum);
2998 static void
2999 xlsx_CT_PivotSelection (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3001 #if 0
3002 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3003 <xsd:attribute name="pane" type="ST_Pane" use="optional" default="topLeft">
3004 <xsd:attribute name="showHeader" type="xsd:boolean" default="false">
3005 <xsd:attribute name="label" type="xsd:boolean" default="false">
3006 <xsd:attribute name="data" type="xsd:boolean" default="false">
3007 <xsd:attribute name="extendable" type="xsd:boolean" default="false">
3008 <xsd:attribute name="count" type="xsd:unsignedInt" default="0">
3009 <xsd:attribute name="axis" type="ST_Axis" use="optional">
3010 <xsd:attribute name="dimension" type="xsd:unsignedInt" default="0">
3011 <xsd:attribute name="start" type="xsd:unsignedInt" default="0">
3012 <xsd:attribute name="min" type="xsd:unsignedInt" default="0">
3013 <xsd:attribute name="max" type="xsd:unsignedInt" default="0">
3014 <xsd:attribute name="activeRow" type="xsd:unsignedInt" default="0">
3015 <xsd:attribute name="activeCol" type="xsd:unsignedInt" default="0">
3016 <xsd:attribute name="previousRow" type="xsd:unsignedInt" default="0">
3017 <xsd:attribute name="previousCol" type="xsd:unsignedInt" default="0">
3018 <xsd:attribute name="click" type="xsd:unsignedInt" default="0">
3019 <xsd:attribute ref="r:id" use="optional">
3020 #endif
3023 static void
3024 xlsx_CT_PivotArea (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3026 #if 0
3027 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3028 <xsd:attribute name="field" use="optional" type="xsd:int">
3029 <xsd:attribute name="type" type="ST_PivotAreaType" default="normal">
3030 <xsd:attribute name="dataOnly" type="xsd:boolean" default="true">
3031 <xsd:attribute name="labelOnly" type="xsd:boolean" default="false">
3032 <xsd:attribute name="grandRow" type="xsd:boolean" default="false">
3033 <xsd:attribute name="grandCol" type="xsd:boolean" default="false">
3034 <xsd:attribute name="cacheIndex" type="xsd:boolean" default="false">
3035 <xsd:attribute name="outline" type="xsd:boolean" default="true">
3036 <xsd:attribute name="offset" type="ST_Ref">
3037 <xsd:attribute name="collapsedLevelsAreSubtotals" type="xsd:boolean" default="false">
3038 <xsd:attribute name="axis" type="ST_Axis" use="optional">
3039 <xsd:attribute name="fieldPosition" type="xsd:unsignedInt" use="optional">
3040 #endif
3042 static void
3043 xlsx_CT_PivotAreaReferences (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3045 #if 0
3046 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3047 #endif
3049 static void
3050 xlsx_CT_PivotAreaReference (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3052 #if 0
3053 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3054 <xsd:attribute name="field" use="optional" type="xsd:unsignedInt">
3055 <xsd:attribute name="count" type="xsd:unsignedInt">
3056 <xsd:attribute name="selected" type="xsd:boolean" default="true">
3057 <xsd:attribute name="byPosition" type="xsd:boolean" default="false">
3058 <xsd:attribute name="relative" type="xsd:boolean" default="false">
3059 <xsd:attribute name="defaultSubtotal" type="xsd:boolean" default="false">
3060 <xsd:attribute name="sumSubtotal" type="xsd:boolean" default="false">
3061 <xsd:attribute name="countASubtotal" type="xsd:boolean" default="false">
3062 <xsd:attribute name="avgSubtotal" type="xsd:boolean" default="false">
3063 <xsd:attribute name="maxSubtotal" type="xsd:boolean" default="false">
3064 <xsd:attribute name="minSubtotal" type="xsd:boolean" default="false">
3065 <xsd:attribute name="productSubtotal" type="xsd:boolean" default="false">
3066 <xsd:attribute name="countSubtotal" type="xsd:boolean" default="false">
3067 <xsd:attribute name="stdDevSubtotal" type="xsd:boolean" default="false">
3068 <xsd:attribute name="stdDevPSubtotal" type="xsd:boolean" default="false">
3069 <xsd:attribute name="varSubtotal" type="xsd:boolean" default="false">
3070 <xsd:attribute name="varPSubtotal" type="xsd:boolean" default="false">
3071 #endif
3074 static void
3075 xlsx_CT_Pane (GsfXMLIn *xin, xmlChar const **attrs)
3077 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3078 GnmCellPos topLeft = { 0, 0 };
3079 int tmp;
3080 gnm_float xSplit = -1., ySplit = -1.;
3081 gboolean frozen = FALSE;
3083 g_return_if_fail (state->sv != NULL);
3085 /* <pane xSplit="2" ySplit="3" topLeftCell="J15" activePane="bottomRight" state="frozen"/> */
3086 state->pane_pos = XLSX_PANE_TOP_LEFT;
3087 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3088 if (0 == strcmp (attrs[0], "state"))
3089 frozen = (0 == strcmp (attrs[1], "frozen"));
3090 else if (attr_pos (xin, attrs, "topLeftCell", &topLeft))
3092 else if (attr_float (xin, attrs, "xSplit", &xSplit))
3094 else if (attr_float (xin, attrs, "ySplit", &ySplit))
3096 else if (attr_enum (xin, attrs, "pane", pane_types, &tmp))
3097 state->pane_pos = tmp;
3100 if (frozen) {
3101 GnmCellPos frozen, unfrozen;
3102 frozen = unfrozen = state->sv->initial_top_left;
3103 if (xSplit > 0)
3104 unfrozen.col += xSplit;
3105 else
3106 topLeft.col = state->sv->initial_top_left.col;
3107 if (ySplit > 0)
3108 unfrozen.row += ySplit;
3109 else
3110 topLeft.row = state->sv->initial_top_left.row;
3111 gnm_sheet_view_freeze_panes (state->sv, &frozen, &unfrozen);
3112 gnm_sheet_view_set_initial_top_left (state->sv, topLeft.col, topLeft.row);
3116 static void
3117 xlsx_ole_object (G_GNUC_UNUSED GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3119 #if 0
3120 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3122 /* <oleObject progId="Wordpad.Document.1" shapeId="1032" r:id="rId5"/> */
3123 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
3125 #endif
3128 static void
3129 xlsx_CT_HyperLinks (GsfXMLIn *xin, xmlChar const **attrs)
3131 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3132 gboolean has_ref = FALSE;
3133 GnmStyle *style;
3134 GnmRange r;
3135 GType link_type = 0;
3136 GnmHLink *lnk = NULL;
3137 char const *location = NULL;
3138 char const *tooltip = NULL;
3139 char const *extern_id = NULL;
3140 char *target = NULL;
3142 /* <hyperlink ref="A42" r:id="rId1"/> */
3143 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3144 if (attr_range (xin, attrs, "ref", &r))
3145 has_ref = TRUE;
3146 else if (0 == strcmp (attrs[0], "location"))
3147 location = CXML2C (attrs[1]);
3148 else if (0 == strcmp (attrs[0], "tooltip"))
3149 tooltip = CXML2C (attrs[1]);
3150 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3151 extern_id = CXML2C (attrs[1]);
3152 #if 0 /* ignore "display" on import, it always seems to be the cell content */
3153 else if (0 == strcmp (attrs[0], "display"))
3155 #endif
3158 if (!has_ref)
3159 return;
3161 if (NULL != extern_id) {
3162 GsfOpenPkgRel const *rel = gsf_open_pkg_lookup_rel_by_id (
3163 gsf_xml_in_get_input (xin), extern_id);
3164 if (NULL != rel &&
3165 gsf_open_pkg_rel_is_extern (rel) &&
3166 0 == strcmp (gsf_open_pkg_rel_get_type (rel),
3167 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")) {
3168 const char *url = gsf_open_pkg_rel_get_target (rel);
3169 if (url) {
3170 if (0 == strncmp (url, "mailto:", 7))
3171 link_type = gnm_hlink_email_get_type ();
3172 else
3173 link_type = gnm_hlink_url_get_type ();
3174 target = location
3175 ? g_strconcat (url, "#", location, NULL)
3176 : g_strdup (url);
3179 } else if (location) {
3180 target = g_strdup (location);
3181 link_type = gnm_hlink_cur_wb_get_type ();
3184 if (0 == link_type) {
3185 xlsx_warning (xin, _("Unknown type of hyperlink"));
3186 g_free (target);
3187 return;
3190 lnk = gnm_hlink_new (link_type, state->sheet);
3191 gnm_hlink_set_target (lnk, target);
3192 gnm_hlink_set_tip (lnk, tooltip);
3193 style = gnm_style_new ();
3194 gnm_style_set_hlink (style, lnk);
3195 sheet_style_apply_range (state->sheet, &r, style);
3196 g_free (target);
3199 static void
3200 cb_find_pivots (GsfInput *opkg, GsfOpenPkgRel const *rel, gpointer user_data)
3202 XLSXReadState *state = user_data;
3203 GsfInput *part_stream;
3204 char const *t = gsf_open_pkg_rel_get_type (rel);
3206 if (NULL != t &&
3207 0 == strcmp (t, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable") &&
3208 NULL != (part_stream = gsf_open_pkg_open_rel (opkg, rel, NULL)))
3209 xlsx_parse_stream (state, part_stream, xlsx_pivot_table_dtd);
3212 static void
3213 xlsx_CT_worksheet (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3215 gsf_open_pkg_foreach_rel (gsf_xml_in_get_input (xin),
3216 &cb_find_pivots, (XLSXReadState *)xin->user_state);
3220 static void
3221 xlsx_ext_begin (GsfXMLIn *xin, xmlChar const **attrs)
3223 gboolean warned = FALSE;
3224 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3225 if (0 == strcmp (attrs[0], "uri")) {
3226 #if 0
3227 xlsx_warning (xin,
3228 _("Encountered uninterpretable \"ext\" extension in namespace \"%s\""),
3229 attrs[1]);
3230 #endif
3231 warned = TRUE;
3235 if (!warned)
3236 xlsx_warning (xin,
3237 _("Encountered uninterpretable \"ext\" extension with missing namespace"));
3238 gsf_xml_in_set_silent_unknowns (xin, TRUE);
3241 static void
3242 xlsx_ext_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3244 gsf_xml_in_set_silent_unknowns (xin, FALSE);
3249 static void
3250 add_attr (XLSXReadState *state, PangoAttribute *attr)
3252 attr->start_index = 0;
3253 attr->end_index = -1;
3255 if (state->run_attrs == NULL)
3256 state->run_attrs = pango_attr_list_new ();
3258 pango_attr_list_insert (state->run_attrs, attr);
3261 static void
3262 xlsx_run_weight (GsfXMLIn *xin, xmlChar const **attrs)
3264 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3265 PangoWeight wt;
3266 int b = TRUE;
3267 (void)simple_bool (xin, attrs, &b);
3268 wt = b ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL;
3269 add_attr (state, pango_attr_weight_new (wt));
3272 static void
3273 xlsx_run_style (GsfXMLIn *xin, xmlChar const **attrs)
3275 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3276 PangoStyle st;
3277 int it = TRUE;
3278 (void)simple_bool (xin, attrs, &it);
3280 st = it ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
3281 add_attr (state, pango_attr_style_new (st));
3284 static void
3285 xlsx_run_family (GsfXMLIn *xin, xmlChar const **attrs)
3287 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3288 const char *fam = simple_string (xin, attrs);
3289 if (fam) {
3290 PangoAttribute *attr = pango_attr_family_new (fam);
3291 add_attr (state, attr);
3295 static void
3296 xlsx_run_size (GsfXMLIn *xin, xmlChar const **attrs)
3298 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3299 gnm_float sz;
3300 if (simple_float (xin, attrs, &sz)) {
3301 PangoAttribute *attr = pango_attr_size_new (CLAMP (sz, 0.0, 1000.0) * PANGO_SCALE);
3302 add_attr (state, attr);
3306 static void
3307 xlsx_run_strikethrough (GsfXMLIn *xin, xmlChar const **attrs)
3309 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3310 int st = TRUE; /* Default */
3311 (void)simple_bool (xin, attrs, &st);
3312 add_attr (state, pango_attr_strikethrough_new (st));
3315 static void
3316 xlsx_run_underline (GsfXMLIn *xin, xmlChar const **attrs)
3318 static EnumVal const types[] = {
3319 { "single", PANGO_UNDERLINE_SINGLE },
3320 { "double", PANGO_UNDERLINE_DOUBLE },
3321 { "singleAccounting", PANGO_UNDERLINE_LOW },
3322 { "doubleAccounting", PANGO_UNDERLINE_LOW }, /* fixme? */
3323 { "none", PANGO_UNDERLINE_NONE },
3324 { NULL, 0 }
3326 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3327 int u = PANGO_UNDERLINE_SINGLE;
3328 (void)simple_enum (xin, attrs, types, &u);
3329 add_attr (state, pango_attr_underline_new (u));
3332 static void
3333 xlsx_run_vertalign (GsfXMLIn *xin, xmlChar const **attrs)
3335 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3336 static EnumVal const types[] = {
3337 { "subscript", GO_FONT_SCRIPT_SUB },
3338 { "baseline", GO_FONT_SCRIPT_STANDARD },
3339 { "superscript", GO_FONT_SCRIPT_SUPER },
3340 { NULL, 0 }
3342 int v = GO_FONT_SCRIPT_STANDARD;
3343 (void)simple_enum (xin, attrs, types, &v);
3344 switch (v) {
3345 case GO_FONT_SCRIPT_SUB:
3346 add_attr (state, go_pango_attr_subscript_new (TRUE));
3347 break;
3348 case GO_FONT_SCRIPT_SUPER:
3349 add_attr (state, go_pango_attr_superscript_new (TRUE));
3350 break;
3351 default:
3352 break;
3357 static void
3358 xlsx_run_color (GsfXMLIn *xin, xmlChar const **attrs)
3360 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3361 GOColor c = GO_COLOR_BLACK;
3363 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3364 if (strcmp (attrs[0], "rgb") == 0) {
3365 unsigned r, g, b, a;
3366 if (4 != sscanf (attrs[1], "%02x%02x%02x%02x", &a, &r, &g, &b)) {
3367 xlsx_warning (xin,
3368 _("Invalid color '%s' for attribute rgb"),
3369 attrs[1]);
3370 continue;
3373 c = GO_COLOR_FROM_RGBA (r, g, b, a);
3374 } else if (strcmp (attrs[0], "indexed") == 0) {
3375 int idx = atoi (CXML2C (attrs[1]));
3376 c = indexed_color (state, idx);
3380 add_attr (state, go_color_to_pango (c, TRUE));
3383 static gboolean
3384 cb_trunc_attributes (PangoAttribute *a, gpointer plen)
3386 a->end_index = GPOINTER_TO_UINT (plen);
3387 return FALSE;
3390 static void
3391 xlsx_rich_text (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3393 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3394 const char *s = xin->content->str;
3396 if (state->run_attrs) {
3397 unsigned len = strlen (s);
3398 unsigned start = state->r_text->len, end = start + len;
3399 pango_attr_list_filter (state->run_attrs,
3400 (PangoAttrFilterFunc) cb_trunc_attributes,
3401 GUINT_TO_POINTER (len));
3402 if (state->rich_attrs == NULL)
3403 state->rich_attrs = pango_attr_list_new ();
3404 pango_attr_list_splice (state->rich_attrs, state->run_attrs, start, end);
3405 pango_attr_list_unref (state->run_attrs);
3406 state->run_attrs = NULL;
3408 g_string_append (state->r_text, s);
3412 * Rich text is used in multiple dtds. We don't hanadle that with
3413 * particular elegance, but we've got macros.
3415 #define RICH_TEXT_NODES \
3416 GSF_XML_IN_NODE (RICH, RICH_TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_rich_text), \
3417 GSF_XML_IN_NODE (RICH, RICH_PROPS, XL_NS_SS, "rPr", GSF_XML_NO_CONTENT, NULL, NULL), \
3418 /* GSF_XML_IN_NODE (RICH_PROPS, RICH_FONT, XL_NS_SS, "font", GSF_XML_NO_CONTENT, NULL, NULL), */ \
3419 /* docs say 'font' xl is generating rFont */ \
3420 GSF_XML_IN_NODE (RICH_PROPS, RICH_FONT, XL_NS_SS, "rFont", GSF_XML_NO_CONTENT, NULL, NULL), \
3422 GSF_XML_IN_NODE (RICH_PROPS, RICH_CHARSET, XL_NS_SS, "charset", GSF_XML_NO_CONTENT, NULL, NULL), \
3423 GSF_XML_IN_NODE (RICH_PROPS, RICH_FAMILY, XL_NS_SS, "family", GSF_XML_NO_CONTENT, xlsx_run_family, NULL), \
3424 GSF_XML_IN_NODE (RICH_PROPS, RICH_BOLD, XL_NS_SS, "b", GSF_XML_NO_CONTENT, xlsx_run_weight, NULL), \
3425 GSF_XML_IN_NODE (RICH_PROPS, RICH_ITALIC, XL_NS_SS, "i", GSF_XML_NO_CONTENT, xlsx_run_style, NULL), \
3426 GSF_XML_IN_NODE (RICH_PROPS, RICH_STRIKE, XL_NS_SS, "strike", GSF_XML_NO_CONTENT, xlsx_run_strikethrough, NULL), \
3427 GSF_XML_IN_NODE (RICH_PROPS, RICH_OUTLINE, XL_NS_SS, "outline", GSF_XML_NO_CONTENT, NULL, NULL), \
3428 GSF_XML_IN_NODE (RICH_PROPS, RICH_SHADOW, XL_NS_SS, "shadow", GSF_XML_NO_CONTENT, NULL, NULL), \
3429 GSF_XML_IN_NODE (RICH_PROPS, RICH_CONDENSE, XL_NS_SS, "condense", GSF_XML_NO_CONTENT, NULL, NULL), \
3430 GSF_XML_IN_NODE (RICH_PROPS, RICH_EXTEND, XL_NS_SS, "extend", GSF_XML_NO_CONTENT, NULL, NULL), \
3431 GSF_XML_IN_NODE (RICH_PROPS, RICH_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, xlsx_run_color, NULL), \
3432 GSF_XML_IN_NODE (RICH_PROPS, RICH_SZ, XL_NS_SS, "sz", GSF_XML_NO_CONTENT, xlsx_run_size, NULL), \
3433 GSF_XML_IN_NODE (RICH_PROPS, RICH_ULINE, XL_NS_SS, "u", GSF_XML_NO_CONTENT, xlsx_run_underline, NULL), \
3434 GSF_XML_IN_NODE (RICH_PROPS, RICH_VALIGN, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, xlsx_run_vertalign, NULL), \
3435 GSF_XML_IN_NODE (RICH_PROPS, RICH_SCHEME, XL_NS_SS, "scheme", GSF_XML_NO_CONTENT, NULL, NULL)
3440 static GsfXMLInNode const xlsx_sheet_dtd[] = {
3441 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3442 GSF_XML_IN_NODE_FULL (START, SHEET, XL_NS_SS, "worksheet", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, &xlsx_CT_worksheet, 0),
3443 GSF_XML_IN_NODE (SHEET, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
3444 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_SS, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
3445 GSF_XML_IN_NODE (EXTITEM, EXT_TABTEXTCOLOR, XL_NS_GNM_EXT, "tabTextColor", GSF_XML_NO_CONTENT, &xlsx_ext_tabtextcolor, NULL),
3446 GSF_XML_IN_NODE (SHEET, PROPS, XL_NS_SS, "sheetPr", GSF_XML_NO_CONTENT, &xlsx_CT_SheetPr, NULL),
3447 GSF_XML_IN_NODE (PROPS, OUTLINE_PROPS, XL_NS_SS, "outlinePr", GSF_XML_NO_CONTENT, NULL, NULL),
3448 GSF_XML_IN_NODE (PROPS, TAB_COLOR, XL_NS_SS, "tabColor", GSF_XML_NO_CONTENT, &xlsx_sheet_tabcolor, NULL),
3449 GSF_XML_IN_NODE (PROPS, PAGE_SETUP, XL_NS_SS, "pageSetUpPr", GSF_XML_NO_CONTENT, &xlsx_sheet_page_setup, NULL),
3450 GSF_XML_IN_NODE (SHEET, DIMENSION, XL_NS_SS, "dimension", GSF_XML_NO_CONTENT, NULL, NULL),
3451 GSF_XML_IN_NODE (SHEET, VIEWS, XL_NS_SS, "sheetViews", GSF_XML_NO_CONTENT, NULL, NULL),
3452 GSF_XML_IN_NODE (VIEWS, VIEW, XL_NS_SS, "sheetView", GSF_XML_NO_CONTENT, &xlsx_CT_SheetView_begin, &xlsx_CT_SheetView_end),
3453 GSF_XML_IN_NODE (VIEW, PANE, XL_NS_SS, "pane", GSF_XML_NO_CONTENT, &xlsx_CT_Pane, NULL),
3454 GSF_XML_IN_NODE (VIEW, SELECTION, XL_NS_SS, "selection", GSF_XML_NO_CONTENT, &xlsx_CT_Selection, NULL),
3455 GSF_XML_IN_NODE (VIEW, PIV_SELECTION, XL_NS_SS, "pivotSelection", GSF_XML_NO_CONTENT, &xlsx_CT_PivotSelection, NULL),
3456 GSF_XML_IN_NODE (PIV_SELECTION, PIV_AREA, XL_NS_SS, "pivotArea", GSF_XML_NO_CONTENT, &xlsx_CT_PivotArea, NULL),
3457 GSF_XML_IN_NODE (PIV_AREA, PIV_AREA_REFS, XL_NS_SS, "references", GSF_XML_NO_CONTENT, &xlsx_CT_PivotAreaReferences, NULL),
3458 GSF_XML_IN_NODE (PIV_AREA_REFS, PIV_AREA_REF, XL_NS_SS, "reference", GSF_XML_NO_CONTENT, &xlsx_CT_PivotAreaReference, NULL),
3460 GSF_XML_IN_NODE (SHEET, DEFAULT_FMT, XL_NS_SS, "sheetFormatPr", GSF_XML_NO_CONTENT, &xlsx_CT_SheetFormatPr, NULL),
3462 GSF_XML_IN_NODE (SHEET, COLS, XL_NS_SS, "cols", GSF_XML_NO_CONTENT, NULL, xlsx_CT_RowsCols_end),
3463 GSF_XML_IN_NODE (COLS, COL, XL_NS_SS, "col", GSF_XML_NO_CONTENT, &xlsx_CT_Col, NULL),
3465 GSF_XML_IN_NODE (SHEET, CONTENT, XL_NS_SS, "sheetData", GSF_XML_NO_CONTENT, NULL, NULL),
3466 GSF_XML_IN_NODE (CONTENT, ROW, XL_NS_SS, "row", GSF_XML_NO_CONTENT, &xlsx_CT_Row, NULL),
3467 GSF_XML_IN_NODE (ROW, CELL, XL_NS_SS, "c", GSF_XML_NO_CONTENT, &xlsx_cell_begin, &xlsx_cell_end),
3468 GSF_XML_IN_NODE (CELL, VALUE, XL_NS_SS, "v", GSF_XML_CONTENT, NULL, &xlsx_cell_val_end),
3469 GSF_XML_IN_NODE (CELL, FMLA, XL_NS_SS, "f", GSF_XML_CONTENT, &xlsx_cell_expr_begin, &xlsx_cell_expr_end),
3470 GSF_XML_IN_NODE (CELL, TEXTINLINE, XL_NS_SS, "is", GSF_XML_NO_CONTENT, &xlsx_cell_inline_begin, &xlsx_cell_inline_end),
3471 GSF_XML_IN_NODE (TEXTINLINE, TEXTRUN, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, &xlsx_cell_inline_text_end),
3472 GSF_XML_IN_NODE (TEXTINLINE, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
3473 RICH_TEXT_NODES,
3474 GSF_XML_IN_NODE (CELL, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
3476 GSF_XML_IN_NODE (SHEET, CALC_PR, XL_NS_SS, "sheetCalcPr", GSF_XML_NO_CONTENT, NULL, NULL),
3477 GSF_XML_IN_NODE (SHEET, CT_SortState, XL_NS_SS, "sortState", GSF_XML_NO_CONTENT, NULL, NULL),
3478 GSF_XML_IN_NODE (CT_SortState, CT_SortCondition, XL_NS_SS, "sortCondition", GSF_XML_NO_CONTENT, NULL, NULL),
3479 GSF_XML_IN_NODE (SHEET, SCENARIOS, XL_NS_SS, "scenarios", GSF_XML_NO_CONTENT, NULL, NULL),
3480 GSF_XML_IN_NODE (SCENARIOS, INPUT_CELLS, XL_NS_SS, "inputCells", GSF_XML_NO_CONTENT, NULL, NULL),
3481 GSF_XML_IN_NODE (SHEET, PROTECTED_RANGES, XL_NS_SS, "protectedRanges", GSF_XML_NO_CONTENT, NULL, NULL),
3482 GSF_XML_IN_NODE (PROTECTED_RANGES, PROTECTED_RANGE, XL_NS_SS, "protectedRange", GSF_XML_NO_CONTENT, NULL, NULL),
3484 GSF_XML_IN_NODE (SHEET, CT_AutoFilter, XL_NS_SS, "autoFilter", GSF_XML_NO_CONTENT,
3485 &xlsx_CT_AutoFilter_begin, &xlsx_CT_AutoFilter_end),
3486 GSF_XML_IN_NODE (CT_AutoFilter, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
3487 GSF_XML_IN_NODE (CT_AutoFilter, CT_SortState, XL_NS_SS, "sortState", GSF_XML_2ND, NULL, NULL),
3488 GSF_XML_IN_NODE (CT_AutoFilter, CT_FilterColumn, XL_NS_SS, "filterColumn", GSF_XML_NO_CONTENT,
3489 &xlsx_CT_FilterColumn_begin, NULL),
3490 GSF_XML_IN_NODE (CT_FilterColumn, CT_Filters, XL_NS_SS, "filters", GSF_XML_NO_CONTENT,
3491 &xlsx_CT_Filters_begin, &xlsx_CT_Filters_end),
3492 GSF_XML_IN_NODE (CT_Filters, CT_Filter, XL_NS_SS, "filter", GSF_XML_NO_CONTENT, &xlsx_CT_Filter, NULL),
3493 GSF_XML_IN_NODE (CT_FilterColumn, CT_CustomFilters, XL_NS_SS, "customFilters", GSF_XML_NO_CONTENT,
3494 &xlsx_CT_CustomFilters_begin, &xlsx_CT_CustomFilters_end),
3495 GSF_XML_IN_NODE (CT_CustomFilters, CT_CustomFilter, XL_NS_SS, "customFilter", GSF_XML_NO_CONTENT, &xlsx_CT_CustomFilter, NULL),
3496 GSF_XML_IN_NODE (CT_FilterColumn, CT_Top10, XL_NS_SS, "top10", GSF_XML_NO_CONTENT, &xlsx_CT_Top10, NULL),
3497 GSF_XML_IN_NODE (CT_FilterColumn, CT_DynamicFilter, XL_NS_SS, "dynamicFilter", GSF_XML_NO_CONTENT, &xlsx_CT_DynamicFilter, NULL),
3498 GSF_XML_IN_NODE (CT_FilterColumn, CT_ColorFilter, XL_NS_SS, "colorFilter", GSF_XML_NO_CONTENT, NULL, NULL),
3499 GSF_XML_IN_NODE (CT_FilterColumn, CT_IconFilter, XL_NS_SS, "iconFilter", GSF_XML_NO_CONTENT, NULL, NULL),
3501 GSF_XML_IN_NODE (SHEET, CT_DataValidations, XL_NS_SS, "dataValidations", GSF_XML_NO_CONTENT, NULL, NULL),
3502 GSF_XML_IN_NODE (CT_DataValidations, CT_DataValidation, XL_NS_SS, "dataValidation", GSF_XML_NO_CONTENT,
3503 &xlsx_CT_DataValidation_begin, &xlsx_CT_DataValidation_end),
3504 GSF_XML_IN_NODE_FULL (CT_DataValidation, VAL_FORMULA1, XL_NS_SS, "formula1", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xlsx_validation_expr, 0),
3505 GSF_XML_IN_NODE_FULL (CT_DataValidation, VAL_FORMULA2, XL_NS_SS, "formula2", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xlsx_validation_expr, 1),
3507 GSF_XML_IN_NODE (SHEET, MERGES, XL_NS_SS, "mergeCells", GSF_XML_NO_CONTENT, NULL, NULL),
3508 GSF_XML_IN_NODE (MERGES, MERGE, XL_NS_SS, "mergeCell", GSF_XML_NO_CONTENT, &xlsx_CT_MergeCell, NULL),
3510 GSF_XML_IN_NODE (SHEET, DRAWING, XL_NS_SS, "drawing", GSF_XML_NO_CONTENT, &xlsx_sheet_drawing, NULL),
3512 GSF_XML_IN_NODE (SHEET, PROTECTION, XL_NS_SS, "sheetProtection", GSF_XML_NO_CONTENT, &xlsx_CT_SheetProtection, NULL),
3513 GSF_XML_IN_NODE (SHEET, PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
3514 GSF_XML_IN_NODE (SHEET, COND_FMTS, XL_NS_SS, "conditionalFormatting", GSF_XML_NO_CONTENT,
3515 &xlsx_cond_fmt_begin, &xlsx_cond_fmt_end),
3516 GSF_XML_IN_NODE (COND_FMTS, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
3517 GSF_XML_IN_NODE (COND_FMTS, COND_RULE, XL_NS_SS, "cfRule", GSF_XML_NO_CONTENT,
3518 &xlsx_cond_fmt_rule_begin, &xlsx_cond_fmt_rule_end),
3519 GSF_XML_IN_NODE (COND_RULE, COND_FMLA, XL_NS_SS, "formula", GSF_XML_CONTENT, NULL, &xlsx_cond_fmt_formula_end),
3520 GSF_XML_IN_NODE (COND_RULE, COND_COLOR_SCALE, XL_NS_SS, "colorScale", GSF_XML_NO_CONTENT, NULL, NULL),
3521 GSF_XML_IN_NODE (COND_COLOR_SCALE, CFVO, XL_NS_SS, "cfvo", GSF_XML_NO_CONTENT, NULL, NULL),
3522 GSF_XML_IN_NODE (COND_COLOR_SCALE, COND_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
3523 GSF_XML_IN_NODE (COND_RULE, COND_DATA_BAR, XL_NS_SS, "dataBar", GSF_XML_NO_CONTENT, NULL, NULL),
3524 GSF_XML_IN_NODE (COND_RULE, COND_ICON_SET, XL_NS_SS, "iconSet", GSF_XML_NO_CONTENT, NULL, NULL),
3525 GSF_XML_IN_NODE (COND_ICON_SET, CFVO, XL_NS_SS, "cfvo", GSF_XML_2ND, NULL, NULL),
3527 GSF_XML_IN_NODE (SHEET, HYPERLINKS, XL_NS_SS, "hyperlinks", GSF_XML_NO_CONTENT, NULL, NULL),
3528 GSF_XML_IN_NODE (HYPERLINKS, HYPERLINK, XL_NS_SS, "hyperlink", GSF_XML_NO_CONTENT, &xlsx_CT_HyperLinks, NULL),
3530 GSF_XML_IN_NODE (SHEET, PRINT_OPTS, XL_NS_SS, "printOptions", GSF_XML_NO_CONTENT, NULL, NULL),
3531 GSF_XML_IN_NODE (SHEET, PRINT_MARGINS, XL_NS_SS, "pageMargins", GSF_XML_NO_CONTENT, &xlsx_CT_PageMargins, NULL),
3532 GSF_XML_IN_NODE (SHEET, PRINT_SETUP, XL_NS_SS, "pageSetup", GSF_XML_NO_CONTENT, &xlsx_CT_PageSetup, NULL),
3533 GSF_XML_IN_NODE (SHEET, PRINT_HEADER_FOOTER, XL_NS_SS, "headerFooter", GSF_XML_NO_CONTENT, NULL, NULL),
3534 GSF_XML_IN_NODE (PRINT_HEADER_FOOTER, ODD_HEADER, XL_NS_SS, "oddHeader", GSF_XML_CONTENT, NULL, &xlsx_CT_oddheader_end),
3535 GSF_XML_IN_NODE (PRINT_HEADER_FOOTER, ODD_FOOTER, XL_NS_SS, "oddFooter", GSF_XML_CONTENT, NULL, &xlsx_CT_oddfooter_end),
3537 GSF_XML_IN_NODE_FULL (SHEET, ROW_BREAKS, XL_NS_SS, "rowBreaks", GSF_XML_NO_CONTENT,
3538 FALSE, FALSE, &xlsx_CT_PageBreaks_begin, &xlsx_CT_PageBreaks_end, 1),
3539 GSF_XML_IN_NODE (ROW_BREAKS, CT_PageBreak, XL_NS_SS, "brk", GSF_XML_NO_CONTENT, &xlsx_CT_PageBreak, NULL),
3540 GSF_XML_IN_NODE_FULL (SHEET, COL_BREAKS, XL_NS_SS, "colBreaks", GSF_XML_NO_CONTENT,
3541 FALSE, FALSE, &xlsx_CT_PageBreaks_begin, &xlsx_CT_PageBreaks_end, 0),
3542 GSF_XML_IN_NODE (COL_BREAKS, CT_PageBreak, XL_NS_SS, "brk", GSF_XML_2ND, NULL, NULL),
3544 GSF_XML_IN_NODE (SHEET, LEGACY_DRAW, XL_NS_SS, "legacyDrawing", GSF_XML_NO_CONTENT, &xlsx_sheet_legacy_drawing, NULL),
3545 GSF_XML_IN_NODE (SHEET, OLE_OBJECTS, XL_NS_SS, "oleObjects", GSF_XML_NO_CONTENT, NULL, NULL),
3546 GSF_XML_IN_NODE (OLE_OBJECTS, OLE_OBJECT, XL_NS_SS, "oleObject", GSF_XML_NO_CONTENT, &xlsx_ole_object, NULL),
3548 GSF_XML_IN_NODE_END
3551 /****************************************************************************/
3553 static void
3554 xlsx_CT_PivotCache (GsfXMLIn *xin, xmlChar const **attrs)
3556 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3557 xmlChar const *id = NULL;
3558 xmlChar const *cacheId = NULL;
3560 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3561 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3562 id = attrs[1];
3563 else if (0 == strcmp (attrs[0], "cacheId"))
3564 cacheId = attrs[1];
3567 if (NULL != id && NULL != cacheId) {
3568 g_return_if_fail (NULL == state->pivot.cache);
3570 xlsx_parse_rel_by_id (xin, id,
3571 xlsx_pivot_cache_def_dtd, xlsx_ns);
3573 g_return_if_fail (NULL != state->pivot.cache);
3575 /* absorb the reference to the cache */
3576 g_hash_table_replace (state->pivot.cache_by_id,
3577 g_strdup (cacheId), state->pivot.cache);
3578 state->pivot.cache = NULL;
3582 static void
3583 xlsx_CT_WorkbookPr (GsfXMLIn *xin, xmlChar const **attrs)
3585 static EnumVal const switchModes[] = {
3586 { "on", TRUE },
3587 { "1", TRUE },
3588 { "true", TRUE },
3589 { "off", FALSE },
3590 { "0", FALSE },
3591 { "false", FALSE },
3592 { NULL, 0 }
3594 int tmp;
3595 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3597 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3598 if (attr_enum (xin, attrs, "date1904", switchModes, &tmp))
3599 workbook_set_1904 (state->wb, tmp);
3603 static void
3604 xlsx_CT_CalcPr (GsfXMLIn *xin, xmlChar const **attrs)
3606 static EnumVal const calcModes[] = {
3607 { "manual", FALSE },
3608 { "auto", TRUE },
3609 { "autoNoTable", TRUE },
3610 { NULL, 0 }
3612 static EnumVal const refModes[] = {
3613 { "A1", TRUE },
3614 { "R1C1", FALSE },
3615 { NULL, 0 }
3617 int tmp;
3618 gnm_float delta;
3619 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3621 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3622 if (attr_enum (xin, attrs, "calcMode", calcModes, &tmp))
3623 workbook_set_recalcmode (state->wb, tmp);
3624 else if (attr_bool (xin, attrs, "fullCalcOnLoad", &tmp))
3626 else if (attr_enum (xin, attrs, "refMode", refModes, &tmp))
3628 else if (attr_bool (xin, attrs, "iterate", &tmp))
3629 workbook_iteration_enabled (state->wb, tmp);
3630 else if (attr_int (xin, attrs, "iterateCount", &tmp))
3631 workbook_iteration_max_number (state->wb, tmp);
3632 else if (attr_float (xin, attrs, "iterateDelta", &delta))
3633 workbook_iteration_tolerance (state->wb, delta);
3634 else if (attr_bool (xin, attrs, "fullPrecision", &tmp))
3636 else if (attr_bool (xin, attrs, "calcCompleted", &tmp))
3638 else if (attr_bool (xin, attrs, "calcOnSave", &tmp))
3640 else if (attr_bool (xin, attrs, "conncurrentCalc", &tmp))
3642 else if (attr_bool (xin, attrs, "forceFullCalc", &tmp))
3644 else if (attr_int (xin, attrs, "concurrentManualCalc", &tmp))
3649 static void
3650 xlsx_CT_workbookView (GsfXMLIn *xin, xmlChar const **attrs)
3652 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3653 int active_tab = -1;
3654 int width = -1, height = -1;
3655 const int scale = 10; /* Guess */
3657 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3658 if (attr_int (xin, attrs, "activeTab", &active_tab))
3660 else if (attr_int (xin, attrs, "windowHeight", &height))
3662 else if (attr_int (xin, attrs, "windowWidth", &width))
3666 if (width > scale / 2 && height > scale / 2)
3667 wb_view_preferred_size (state->wb_view,
3668 (width + scale / 2) / scale,
3669 (height + scale / 2) / scale);
3672 static void
3673 xlsx_sheet_begin (GsfXMLIn *xin, xmlChar const **attrs)
3675 static EnumVal const visibilities[] = {
3676 { "visible", GNM_SHEET_VISIBILITY_VISIBLE },
3677 { "hidden", GNM_SHEET_VISIBILITY_HIDDEN },
3678 { "veryHidden", GNM_SHEET_VISIBILITY_VERY_HIDDEN },
3679 { NULL, 0 }
3681 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3682 char const *name = NULL;
3683 char const *part_id = NULL;
3684 Sheet *sheet;
3685 int viz = (int)GNM_SHEET_VISIBILITY_VISIBLE;
3687 maybe_update_progress (xin);
3689 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3690 if (0 == strcmp (attrs[0], "name"))
3691 name = attrs[1];
3692 else if (attr_enum (xin, attrs, "state", visibilities, &viz))
3693 ; /* Nothing */
3694 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3695 part_id = attrs[1];
3698 if (NULL == name) {
3699 xlsx_warning (xin, _("Ignoring a sheet without a name"));
3700 return;
3703 sheet = workbook_sheet_by_name (state->wb, name);
3704 if (NULL == sheet) {
3705 sheet = wrap_sheet_new (state->wb, name, XLSX_MaxCol, XLSX_MaxRow);
3706 workbook_sheet_attach (state->wb, sheet);
3708 g_object_set (sheet, "visibility", viz, NULL);
3710 g_object_set_data_full (G_OBJECT (sheet), "_XLSX_RelID", g_strdup (part_id),
3711 (GDestroyNotify) g_free);
3714 static void
3715 xlsx_wb_name_begin (GsfXMLIn *xin, xmlChar const **attrs)
3717 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3718 const char *name = NULL;
3719 int sheet_idx = -1;
3721 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3722 if (0 == strcmp (attrs[0], "name"))
3723 name = attrs[1];
3724 else if (attr_int (xin, attrs, "localSheetId", &sheet_idx))
3725 ; /* Nothing */
3728 state->defined_name = g_strdup (name);
3729 state->defined_name_sheet =
3730 sheet_idx >= 0
3731 ? workbook_sheet_by_index (state->wb, sheet_idx)
3732 : NULL;
3735 static void
3736 xlsx_wb_name_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3738 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3739 GnmParsePos pp;
3740 Sheet *sheet = state->defined_name_sheet;
3741 GnmNamedExpr *nexpr;
3742 char *error_msg = NULL;
3743 const char *thename = state->defined_name;
3744 const char *thevalue = xin->content->str;
3745 gboolean bogus = FALSE;
3747 g_return_if_fail (thename != NULL);
3749 parse_pos_init (&pp, state->wb, sheet, 0, 0);
3751 if (g_str_has_prefix (thename, "_xlnm.")) {
3752 gboolean editable;
3754 thename += 6;
3755 editable = g_str_equal (thename, "Sheet_Title");
3756 bogus = g_str_equal (thename, "Print_Area") &&
3757 g_str_equal (thevalue, "!#REF!");
3758 nexpr = bogus
3759 ? NULL
3760 : expr_name_add (&pp, thename,
3761 gnm_expr_top_new_constant (value_new_empty ()),
3762 &error_msg, TRUE, NULL);
3763 if (nexpr) {
3764 nexpr->is_permanent = TRUE;
3765 nexpr->is_editable = editable;
3767 } else
3768 nexpr = expr_name_add (&pp, thename,
3769 gnm_expr_top_new_constant (value_new_empty ()),
3770 &error_msg, TRUE, NULL);
3772 if (bogus) {
3773 /* Silently ignore */
3774 } else if (nexpr) {
3775 state->delayed_names =
3776 g_list_prepend (state->delayed_names, sheet);
3777 state->delayed_names =
3778 g_list_prepend (state->delayed_names,
3779 g_strdup (thevalue));
3780 state->delayed_names =
3781 g_list_prepend (state->delayed_names, nexpr);
3782 } else {
3783 xlsx_warning (xin, _("Failed to define name: %s"), error_msg);
3784 g_free (error_msg);
3787 g_free (state->defined_name);
3788 state->defined_name = NULL;
3791 static void
3792 handle_delayed_names (GsfXMLIn *xin)
3794 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3795 GList *l;
3797 for (l = state->delayed_names; l; l = l->next->next->next) {
3798 GnmNamedExpr *nexpr = l->data;
3799 char *expr_str = l->next->data;
3800 Sheet *sheet = l->next->next->data;
3801 GnmExprTop const *texpr;
3802 GnmParsePos pp;
3804 parse_pos_init (&pp, state->wb, sheet, 0, 0);
3805 if (*expr_str == 0)
3806 texpr = gnm_expr_top_new_constant (value_new_error_REF (NULL));
3807 else
3808 texpr = xlsx_parse_expr (xin, expr_str, &pp);
3809 if (texpr) {
3810 expr_name_set_expr (nexpr, texpr);
3812 g_free (expr_str);
3815 g_list_free (state->delayed_names);
3816 state->delayed_names = NULL;
3819 static void
3820 xlsx_wb_names_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3822 handle_delayed_names (xin);
3826 /**************************************************************************************************/
3828 static void
3829 xlsx_read_external_book (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3831 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3832 GsfOpenPkgRel const *rel = gsf_open_pkg_lookup_rel_by_type
3833 (gsf_xml_in_get_input (xin),
3834 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/"
3835 "externalLink");
3836 if (rel == NULL)
3837 rel = gsf_open_pkg_lookup_rel_by_type
3838 (gsf_xml_in_get_input (xin),
3839 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/"
3840 "externalLinkPath");
3841 if (NULL != rel && gsf_open_pkg_rel_is_extern (rel))
3842 state->external_ref = xlsx_conventions_add_extern_ref (
3843 state->convs, gsf_open_pkg_rel_get_target (rel));
3844 else
3845 xlsx_warning (xin, _("Unable to resolve external relationship"));
3847 static void
3848 xlsx_read_external_book_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3850 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3851 state->external_ref = NULL;
3853 static void
3854 xlsx_read_external_sheetname (GsfXMLIn *xin, xmlChar const **attrs)
3856 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3857 if (state->external_ref)
3858 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3859 if (0 == strcmp (attrs[0], "val"))
3860 workbook_sheet_attach
3861 (state->external_ref,
3862 state->external_ref_sheet =
3863 wrap_sheet_new (state->external_ref, attrs[1], 256, 65536));
3866 static void
3867 xlsx_read_external_sheetname_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3869 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3870 state->external_ref_sheet = NULL;
3873 static GsfXMLInNode const xlsx_extern_dtd[] = {
3874 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3875 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),
3876 GSF_XML_IN_NODE (LINK, BOOK, XL_NS_SS, "externalBook", GSF_XML_NO_CONTENT, NULL, NULL),
3877 GSF_XML_IN_NODE (BOOK, SHEET_NAMES, XL_NS_SS, "sheetNames", GSF_XML_NO_CONTENT, NULL, NULL),
3878 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),
3879 GSF_XML_IN_NODE (BOOK, SHEET_DATASET, XL_NS_SS, "sheetDataSet", GSF_XML_NO_CONTENT, NULL, NULL),
3880 GSF_XML_IN_NODE (SHEET_DATASET, SHEET_DATA, XL_NS_SS, "sheetData", GSF_XML_NO_CONTENT, NULL, NULL),
3881 GSF_XML_IN_NODE (SHEET_DATA, ROW, XL_NS_SS, "row", GSF_XML_NO_CONTENT, NULL, NULL),
3882 GSF_XML_IN_NODE (ROW, CELL, XL_NS_SS, "cell", GSF_XML_NO_CONTENT, NULL, NULL),
3883 GSF_XML_IN_NODE (CELL, VAL, XL_NS_SS, "v", GSF_XML_NO_CONTENT, NULL, NULL),
3885 GSF_XML_IN_NODE_END
3888 static void
3889 xlsx_wb_external_ref (GsfXMLIn *xin, xmlChar const **attrs)
3891 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3892 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
3893 xlsx_parse_rel_by_id (xin, attrs[1], xlsx_extern_dtd, xlsx_ns);
3897 /**************************************************************************************************/
3899 static void
3900 xlsx_comments_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
3902 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3903 state->authors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
3906 static void
3907 xlsx_comments_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3909 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3910 g_ptr_array_unref (state->authors);
3911 state->authors = NULL;
3914 static void
3915 xlsx_comment_author_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3917 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3918 int i = strlen (xin->content->str);
3919 char *name = xin->content->str;
3921 /* remove any trailing white space */
3922 /* not sure this is correct, we might be careful about encoding */
3923 while (i > 0 && g_ascii_isspace (name[i-1]))
3924 i--;
3925 name = g_new (char, i + 1);
3926 memcpy (name, xin->content->str, i);
3927 name[i] = 0;
3928 g_ptr_array_add (state->authors, name);
3931 static void
3932 xlsx_comment_start (GsfXMLIn *xin, xmlChar const **attrs)
3934 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3935 SheetObject *so;
3936 GnmRange anchor_r;
3938 state->comment = g_object_new (cell_comment_get_type (), NULL);
3939 so = GNM_SO (state->comment);
3940 anchor_r = sheet_object_get_anchor (so)->cell_bound;
3942 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
3943 if (strcmp (attrs[0], "ref") == 0)
3944 range_parse (&anchor_r, attrs[1], gnm_sheet_get_size (state->sheet));
3945 else if (strcmp (attrs[0], "authorId") == 0) {
3946 unsigned id = atoi (attrs[1]);
3947 char const *name;
3948 if (id < state->authors->len) {
3949 name = g_ptr_array_index (state->authors, id);
3950 if (*name) /* do not set an empty name */
3951 g_object_set (state->comment, "author", name, NULL);
3956 cell_comment_set_pos (GNM_CELL_COMMENT (so), &anchor_r.start);
3957 state->r_text = g_string_new ("");
3960 static void
3961 xlsx_comment_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3963 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3964 char *text = g_string_free (state->r_text, FALSE);
3965 state->r_text = NULL;
3966 g_object_set (state->comment, "text", text, NULL);
3967 g_free (text);
3968 if (state->rich_attrs) {
3969 g_object_set (state->comment, "markup", state->rich_attrs, NULL);
3970 pango_attr_list_unref (state->rich_attrs);
3971 state->rich_attrs = NULL;
3973 sheet_object_set_sheet (GNM_SO (state->comment), state->sheet);
3974 g_object_unref (state->comment);
3975 state->comment = NULL;
3977 maybe_update_progress (xin);
3980 static void
3981 xlsx_r_text (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
3983 XLSXReadState *state = (XLSXReadState *)xin->user_state;
3984 g_string_append (state->r_text, xin->content->str);
3987 static GsfXMLInNode const xlsx_comments_dtd[] = {
3988 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
3989 GSF_XML_IN_NODE_FULL (START, COMMENTS, XL_NS_SS, "comments", GSF_XML_NO_CONTENT, FALSE, TRUE, xlsx_comments_start, xlsx_comments_end, 0),
3990 GSF_XML_IN_NODE (COMMENTS, AUTHORS, XL_NS_SS, "authors", GSF_XML_NO_CONTENT, NULL, NULL),
3991 GSF_XML_IN_NODE (AUTHORS, AUTHOR, XL_NS_SS, "author", GSF_XML_CONTENT, NULL, xlsx_comment_author_end),
3992 GSF_XML_IN_NODE (COMMENTS, COMMENTLIST, XL_NS_SS, "commentList", GSF_XML_NO_CONTENT, NULL, NULL),
3993 GSF_XML_IN_NODE (COMMENTLIST, COMMENT, XL_NS_SS, "comment", GSF_XML_NO_CONTENT, xlsx_comment_start, xlsx_comment_end),
3994 GSF_XML_IN_NODE (COMMENT, TEXTITEM, XL_NS_SS, "text", GSF_XML_NO_CONTENT, NULL, NULL),
3995 GSF_XML_IN_NODE (TEXTITEM, TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_r_text),
3996 GSF_XML_IN_NODE (TEXTITEM, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
3997 RICH_TEXT_NODES,
3998 GSF_XML_IN_NODE (TEXTITEM, ITEM_PHONETIC_RUN, XL_NS_SS, "rPh", GSF_XML_NO_CONTENT, NULL, NULL),
3999 GSF_XML_IN_NODE (ITEM_PHONETIC_RUN, PHONETIC_TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, NULL),
4000 GSF_XML_IN_NODE (TEXTITEM, ITEM_PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
4002 GSF_XML_IN_NODE_END
4005 /**************************************************************************************************/
4007 static gint
4008 cb_by_zorder (gconstpointer a, gconstpointer b, gpointer data)
4010 GHashTable *zorder = data;
4011 int za = GPOINTER_TO_UINT (g_hash_table_lookup (zorder, a));
4012 int zb = GPOINTER_TO_UINT (g_hash_table_lookup (zorder, b));
4013 return zb - za; /* descending */
4017 static void
4018 xlsx_wb_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4020 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4021 int i, n = workbook_sheet_count (state->wb);
4022 char const *part_id;
4023 GnmStyle *style;
4024 GsfInput *sin, *cin;
4025 GError *err = NULL;
4027 end_update_progress (state);
4029 /* Load sheets after setting up the workbooks to give us time to create
4030 * all of them and parse names */
4031 for (i = 0 ; i < n ; i++, state->sheet = NULL) {
4032 char *message;
4033 int j, zoffset;
4034 GSList *l;
4036 if (NULL == (state->sheet = workbook_sheet_by_index (state->wb, i)))
4037 continue;
4038 if (NULL == (part_id = g_object_get_data (G_OBJECT (state->sheet), "_XLSX_RelID"))) {
4039 xlsx_warning (xin, _("Missing part-id for sheet '%s'"),
4040 state->sheet->name_unquoted);
4041 continue;
4044 /* Apply the 'Normal' style (aka builtin 0) to the entire sheet */
4045 if (NULL != (style = g_hash_table_lookup(state->cell_styles, "0"))) {
4046 GnmRange r;
4047 gnm_style_ref (style);
4048 range_init_full_sheet (&r, state->sheet);
4049 sheet_style_set_range (state->sheet, &r, style);
4052 sin = gsf_open_pkg_open_rel_by_id (gsf_xml_in_get_input (xin), part_id, &err);
4053 if (NULL != err) {
4054 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4055 go_io_warning (state->context, "%s", err->message);
4056 g_error_free (err);
4057 err = NULL;
4058 continue;
4060 /* load comments */
4062 cin = gsf_open_pkg_open_rel_by_type (sin,
4063 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", NULL);
4064 message = g_strdup_printf (_("Reading sheet '%s'..."), state->sheet->name_unquoted);
4065 start_update_progress (state, sin, message,
4066 0.3 + i*0.6/n, 0.3 + i*0.6/n + 0.5/n);
4067 g_free (message);
4068 xlsx_parse_stream (state, sin, xlsx_sheet_dtd);
4069 end_update_progress (state);
4071 if (cin != NULL) {
4072 start_update_progress (state, cin, _("Reading comments..."),
4073 0.3 + i*0.6/n + 0.5/n, 0.3 + i*0.6/n + 0.6/n);
4074 xlsx_parse_stream (state, cin, xlsx_comments_dtd);
4075 end_update_progress (state);
4078 zoffset = (g_slist_length (state->pending_objects) -
4079 g_hash_table_size (state->zorder));
4080 for (j = zoffset, l = state->pending_objects; l; l = l->next) {
4081 SheetObject *so = l->data;
4082 int z = GPOINTER_TO_UINT (g_hash_table_lookup (state->zorder, so));
4083 if (z >= 1)
4084 z += zoffset;
4085 else
4086 z = j--;
4087 g_hash_table_insert (state->zorder, so, GINT_TO_POINTER (z));
4089 state->pending_objects = g_slist_sort_with_data
4090 (state->pending_objects, cb_by_zorder, state->zorder);
4092 while (state->pending_objects) {
4093 SheetObject *obj = state->pending_objects->data;
4094 state->pending_objects = g_slist_delete_link (state->pending_objects,
4095 state->pending_objects);
4096 sheet_object_set_sheet (obj, state->sheet);
4097 g_object_unref (obj);
4100 /* Flag a respan here in case nothing else does */
4101 sheet_flag_recompute_spans (state->sheet);
4105 static void
4106 xlsx_webpub_begin (GsfXMLIn *xin, xmlChar const **attrs)
4108 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4109 if (strcmp (attrs[0], "characterSet") == 0) {
4110 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4111 state->version = ECMA_376_2008;
4116 static GsfXMLInNode const xlsx_workbook_dtd[] = {
4117 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4118 GSF_XML_IN_NODE_FULL (START, WORKBOOK, XL_NS_SS, "workbook", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, &xlsx_wb_end, 0),
4119 GSF_XML_IN_NODE (WORKBOOK, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
4120 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_SS, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
4121 GSF_XML_IN_NODE (WORKBOOK, VERSION, XL_NS_SS, "fileVersion", GSF_XML_NO_CONTENT, NULL, NULL),
4122 GSF_XML_IN_NODE (WORKBOOK, PROPERTIES, XL_NS_SS, "workbookPr", GSF_XML_NO_CONTENT, &xlsx_CT_WorkbookPr, NULL),
4123 GSF_XML_IN_NODE (WORKBOOK, CALC_PROPS, XL_NS_SS, "calcPr", GSF_XML_NO_CONTENT, &xlsx_CT_CalcPr, NULL),
4125 GSF_XML_IN_NODE (WORKBOOK, VIEWS, XL_NS_SS, "bookViews", GSF_XML_NO_CONTENT, NULL, NULL),
4126 GSF_XML_IN_NODE (VIEWS, VIEW, XL_NS_SS, "workbookView", GSF_XML_NO_CONTENT, &xlsx_CT_workbookView, NULL),
4127 GSF_XML_IN_NODE (WORKBOOK, CUSTOMWVIEWS, XL_NS_SS, "customWorkbookViews", GSF_XML_NO_CONTENT, NULL, NULL),
4128 GSF_XML_IN_NODE (CUSTOMWVIEWS, CUSTOMWVIEW , XL_NS_SS, "customWorkbookView", GSF_XML_NO_CONTENT, NULL, NULL),
4129 GSF_XML_IN_NODE (CUSTOMWVIEW, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
4130 GSF_XML_IN_NODE_FULL (WORKBOOK, SHEETS, XL_NS_SS, "sheets", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4131 GSF_XML_IN_NODE (SHEETS, SHEET, XL_NS_SS, "sheet", GSF_XML_NO_CONTENT, &xlsx_sheet_begin, NULL),
4132 GSF_XML_IN_NODE (WORKBOOK, FGROUPS, XL_NS_SS, "functionGroups", GSF_XML_NO_CONTENT, NULL, NULL),
4133 GSF_XML_IN_NODE (FGROUPS, FGROUP, XL_NS_SS, "functionGroup", GSF_XML_NO_CONTENT, NULL, NULL),
4134 GSF_XML_IN_NODE (WORKBOOK, WEB_PUB, XL_NS_SS, "webPublishing", GSF_XML_NO_CONTENT, xlsx_webpub_begin, NULL),
4135 GSF_XML_IN_NODE (WORKBOOK, EXTERNS, XL_NS_SS, "externalReferences", GSF_XML_NO_CONTENT, NULL, NULL),
4136 GSF_XML_IN_NODE (EXTERNS, EXTERN, XL_NS_SS, "externalReference", GSF_XML_NO_CONTENT, xlsx_wb_external_ref, NULL),
4137 GSF_XML_IN_NODE (WORKBOOK, NAMES, XL_NS_SS, "definedNames", GSF_XML_NO_CONTENT, NULL, xlsx_wb_names_end),
4138 GSF_XML_IN_NODE (NAMES, NAME, XL_NS_SS, "definedName", GSF_XML_CONTENT, xlsx_wb_name_begin, xlsx_wb_name_end),
4139 GSF_XML_IN_NODE (WORKBOOK, PIVOTCACHES, XL_NS_SS, "pivotCaches", GSF_XML_NO_CONTENT, NULL, NULL),
4140 GSF_XML_IN_NODE (PIVOTCACHES, PIVOTCACHE, XL_NS_SS, "pivotCache", GSF_XML_NO_CONTENT, &xlsx_CT_PivotCache, NULL),
4142 GSF_XML_IN_NODE (WORKBOOK, RECOVERY, XL_NS_SS, "fileRecoveryPr", GSF_XML_NO_CONTENT, NULL, NULL),
4143 GSF_XML_IN_NODE (WORKBOOK, OLESIZE, XL_NS_SS, "oleSize", GSF_XML_NO_CONTENT, NULL, NULL),
4144 GSF_XML_IN_NODE (WORKBOOK, SMARTTAGPR, XL_NS_SS, "smartTagPr", GSF_XML_NO_CONTENT, NULL, NULL),
4145 GSF_XML_IN_NODE (WORKBOOK, SMARTTTYPES, XL_NS_SS, "smartTagTypes", GSF_XML_NO_CONTENT, NULL, NULL),
4146 GSF_XML_IN_NODE (SMARTTTYPES, SMARTTTYPE, XL_NS_SS, "smartTagType", GSF_XML_NO_CONTENT, NULL, NULL),
4147 GSF_XML_IN_NODE (WORKBOOK, WEB_PUB_OBJS, XL_NS_SS, "webPublishObjects", GSF_XML_NO_CONTENT, NULL, NULL),
4148 GSF_XML_IN_NODE (WEB_PUB_OBJS, WEB_PUB_OBJ, XL_NS_SS, "webPublishObject", GSF_XML_NO_CONTENT, NULL, NULL),
4150 GSF_XML_IN_NODE_END
4153 /****************************************************************************/
4155 static void
4156 xlsx_sst_begin (GsfXMLIn *xin, xmlChar const **attrs)
4158 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4159 int count;
4161 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4162 if (attr_int (xin, attrs, "uniqueCount", &count))
4163 g_array_set_size (state->sst, count);
4165 state->count = 0;
4168 static void
4169 xlsx_sstitem_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4171 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4172 state->r_text = g_string_new ("");
4175 static void
4176 xlsx_sstitem_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4178 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4179 XLSXStr *entry;
4180 char *text = g_string_free (state->r_text, FALSE);
4181 state->r_text = NULL;
4183 if (state->count >= state->sst->len)
4184 g_array_set_size (state->sst, state->count+1);
4185 entry = &g_array_index (state->sst, XLSXStr, state->count);
4186 state->count++;
4187 entry->str = go_string_new_nocopy (text);
4189 if (state->rich_attrs) {
4190 entry->markup = go_format_new_markup (state->rich_attrs, FALSE);
4191 state->rich_attrs = NULL;
4195 static GsfXMLInNode const xlsx_shared_strings_dtd[] = {
4196 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4197 GSF_XML_IN_NODE_FULL (START, SST, XL_NS_SS, "sst", GSF_XML_NO_CONTENT, FALSE, TRUE, &xlsx_sst_begin, NULL, 0),
4198 GSF_XML_IN_NODE (SST, ITEM, XL_NS_SS, "si", GSF_XML_NO_CONTENT, &xlsx_sstitem_start, &xlsx_sstitem_end), /* beta2 */
4199 GSF_XML_IN_NODE (ITEM, TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_r_text),
4200 GSF_XML_IN_NODE (ITEM, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
4201 RICH_TEXT_NODES,
4202 GSF_XML_IN_NODE (ITEM, ITEM_PHONETIC_RUN, XL_NS_SS, "rPh", GSF_XML_NO_CONTENT, NULL, NULL),
4203 GSF_XML_IN_NODE (ITEM_PHONETIC_RUN, PHONETIC_TEXT, XL_NS_SS, "t", GSF_XML_SHARED_CONTENT, NULL, NULL),
4204 GSF_XML_IN_NODE (ITEM, ITEM_PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
4206 GSF_XML_IN_NODE_END
4209 /****************************************************************************/
4211 static void
4212 xlsx_numfmt_common (GsfXMLIn *xin, xmlChar const **attrs, gboolean apply)
4214 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4215 xmlChar const *fmt = NULL;
4216 xmlChar const *id = NULL;
4218 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4219 if (0 == strcmp (attrs[0], "numFmtId"))
4220 id = attrs[1];
4221 else if (0 == strcmp (attrs[0], "formatCode"))
4222 fmt = attrs[1];
4225 if (NULL != id && NULL != fmt) {
4226 GOFormat *gfmt = go_format_new_from_XL (fmt);
4227 if (apply)
4228 gnm_style_set_format (state->style_accum, gfmt);
4229 g_hash_table_replace (state->num_fmts, g_strdup (id), gfmt);
4233 static void
4234 xlsx_style_numfmt (GsfXMLIn *xin, xmlChar const **attrs)
4236 xlsx_numfmt_common (xin, attrs, FALSE);
4239 enum {
4240 XLSX_COLLECT_FONT,
4241 XLSX_COLLECT_FILLS,
4242 XLSX_COLLECT_BORDERS,
4243 XLSX_COLLECT_XFS,
4244 XLSX_COLLECT_STYLE_XFS,
4245 XLSX_COLLECT_DXFS,
4246 XLSX_COLLECT_TABLE_STYLES
4249 static void
4250 xlsx_collection_begin (GsfXMLIn *xin, xmlChar const **attrs)
4252 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4253 unsigned count = 0;
4254 GPtrArray **pcollection;
4256 g_return_if_fail (NULL == state->collection);
4258 switch (xin->node->user_data.v_int) {
4259 case XLSX_COLLECT_FONT: pcollection = &state->fonts; break;
4260 case XLSX_COLLECT_FILLS: pcollection = &state->fills; break;
4261 case XLSX_COLLECT_BORDERS: pcollection = &state->borders; break;
4262 case XLSX_COLLECT_XFS: pcollection = &state->xfs; break;
4263 case XLSX_COLLECT_STYLE_XFS: pcollection = &state->style_xfs; break;
4264 case XLSX_COLLECT_DXFS: pcollection = &state->dxfs; break;
4265 case XLSX_COLLECT_TABLE_STYLES: pcollection = &state->table_styles; break;
4266 default:
4267 g_assert_not_reached ();
4268 return;
4271 state->count = 0;
4272 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4273 if (attr_uint (xin, attrs, "count", &count))
4277 /* Don't trust huge counts. */
4278 count = MIN (count, 1000u);
4280 if (*pcollection == NULL) {
4281 *pcollection = g_ptr_array_new ();
4282 g_ptr_array_set_size (*pcollection, count);
4285 state->collection = *pcollection;
4288 static void
4289 xlsx_collection_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4291 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4293 /* resize just in case the count hint was wrong */
4294 g_ptr_array_set_size (state->collection, state->count);
4295 state->count = 0;
4296 state->collection = NULL;
4299 static void
4300 xlsx_col_elem_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4302 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4303 if (!state->style_accum_partial) {
4304 g_return_if_fail (NULL == state->style_accum);
4305 state->style_accum = gnm_style_new ();
4309 static void
4310 xlsx_col_elem_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4312 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4314 if (!state->style_accum_partial) {
4315 GnmStyle *res = state->style_accum;
4316 state->style_accum = NULL;
4317 if (state->count >= state->collection->len)
4318 g_ptr_array_add (state->collection, res);
4319 else if (NULL != g_ptr_array_index (state->collection, state->count)) {
4320 g_warning ("dup @ %d = %p", state->count, res);
4321 gnm_style_unref (res);
4322 } else
4323 g_ptr_array_index (state->collection, state->count) = res;
4324 state->count++;
4328 static void
4329 xlsx_col_border_begin (GsfXMLIn *xin, xmlChar const **attrs)
4331 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4332 gboolean diagonal_down = FALSE, diagonal_up = FALSE;
4334 xlsx_col_elem_begin (xin, attrs);
4335 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4336 if (attr_bool (xin, attrs, "diagonalDown", &diagonal_down))
4338 else (attr_bool (xin, attrs, "diagonalUp", &diagonal_up))
4342 if (diagonal_up) {
4343 GnmBorder *border = gnm_style_border_fetch
4344 (GNM_STYLE_BORDER_THIN, style_color_black (), GNM_STYLE_BORDER_DIAGONAL);
4345 gnm_style_set_border (state->style_accum,
4346 MSTYLE_BORDER_DIAGONAL,
4347 border);
4349 if (diagonal_down) {
4350 GnmBorder *border = gnm_style_border_fetch
4351 (GNM_STYLE_BORDER_HAIR, style_color_black (), GNM_STYLE_BORDER_DIAGONAL);
4352 gnm_style_set_border (state->style_accum,
4353 MSTYLE_BORDER_REV_DIAGONAL,
4354 border);
4358 static void
4359 xlsx_font_name (GsfXMLIn *xin, xmlChar const **attrs)
4361 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4362 const char *name = simple_string (xin, attrs);
4363 if (name)
4364 gnm_style_set_font_name (state->style_accum, name);
4367 static void
4368 xlsx_font_bold (GsfXMLIn *xin, xmlChar const **attrs)
4370 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4371 int val = TRUE;
4372 (void)simple_bool (xin, attrs, &val);
4373 gnm_style_set_font_bold (state->style_accum, val);
4376 static void
4377 xlsx_font_italic (GsfXMLIn *xin, xmlChar const **attrs)
4379 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4380 int val = TRUE;
4381 (void)simple_bool (xin, attrs, &val);
4382 gnm_style_set_font_italic (state->style_accum, val);
4385 static void
4386 xlsx_font_strike (GsfXMLIn *xin, xmlChar const **attrs)
4388 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4389 int val = TRUE;
4390 (void)simple_bool (xin, attrs, &val);
4391 gnm_style_set_font_strike (state->style_accum, val);
4394 static void
4395 xlsx_font_color (GsfXMLIn *xin, xmlChar const **attrs)
4397 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4398 /* LibreOffice 3.3.2 sets the alpha to 0, so text becomes invisible */
4399 /* (Excel drops the alpha too it seems.) */
4400 GnmColor *color = elem_color (xin, attrs, FALSE);
4401 if (NULL != color)
4402 gnm_style_set_font_color (state->style_accum, color);
4404 static void
4405 xlsx_CT_FontSize (GsfXMLIn *xin, xmlChar const **attrs)
4407 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4408 gnm_float val;
4409 if (simple_float (xin, attrs, &val))
4410 gnm_style_set_font_size (state->style_accum, val);
4412 static void
4413 xlsx_CT_vertAlign (GsfXMLIn *xin, xmlChar const **attrs)
4415 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4416 static EnumVal const types[] = {
4417 { "subscript", GO_FONT_SCRIPT_SUB },
4418 { "baseline", GO_FONT_SCRIPT_STANDARD },
4419 { "superscript", GO_FONT_SCRIPT_SUPER },
4420 { NULL, 0 }
4422 int val = GO_FONT_SCRIPT_STANDARD;
4423 (void)simple_enum (xin, attrs, types, &val);
4424 gnm_style_set_font_script (state->style_accum, val);
4426 static void
4427 xlsx_font_uline (GsfXMLIn *xin, xmlChar const **attrs)
4429 static EnumVal const types[] = {
4430 { "single", UNDERLINE_SINGLE },
4431 { "double", UNDERLINE_DOUBLE },
4432 { "singleAccounting", UNDERLINE_SINGLE_LOW },
4433 { "doubleAccounting", UNDERLINE_DOUBLE_LOW },
4434 { "none", UNDERLINE_NONE },
4435 { NULL, 0 }
4437 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4438 int val = UNDERLINE_SINGLE;
4439 (void)simple_enum (xin, attrs, types, &val);
4440 gnm_style_set_font_uline (state->style_accum, val);
4443 static void
4444 xlsx_font_valign (GsfXMLIn *xin, xmlChar const **attrs)
4446 static EnumVal const types[] = {
4447 { "baseline", GO_FONT_SCRIPT_STANDARD },
4448 { "superscript", GO_FONT_SCRIPT_SUPER },
4449 { "subscript", GO_FONT_SCRIPT_SUB },
4450 { NULL, 0 }
4452 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4453 int val = GO_FONT_SCRIPT_STANDARD;
4454 (void)simple_enum (xin, attrs, types, &val);
4455 gnm_style_set_font_script (state->style_accum, val);
4458 static void
4459 xlsx_pattern (GsfXMLIn *xin, xmlChar const **attrs)
4461 static EnumVal const patterns[] = {
4462 { "none", 0 },
4463 { "solid", 1 },
4464 { "mediumGray", 3 },
4465 { "darkGray", 2 },
4466 { "lightGray", 4 },
4467 { "darkHorizontal", 7 },
4468 { "darkVertical", 8 },
4469 { "darkDown", 10},
4470 { "darkUp", 9 },
4471 { "darkGrid", 11 },
4472 { "darkTrellis", 12 },
4473 { "lightHorizontal", 13 },
4474 { "lightVertical", 14 },
4475 { "lightDown", 15 },
4476 { "lightUp", 16 },
4477 { "lightGrid", 17 },
4478 { "lightTrellis", 18 },
4479 { "gray125", 5 },
4480 { "gray0625", 6 },
4481 { NULL, 0 }
4483 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4484 int val = 0; /* none */
4486 /* we are setting a default pattern of solid, see bug #702615 */
4487 /* Note that this conflicts with ECMA 376: "This element is used
4488 to specify cell fill information for pattern and solid color
4489 cell fills. For solid cell fills (no pattern), fgColor is used.
4490 For cell fills with patterns specified, then the cell fill color
4491 is specified by the bgColor element." */
4492 /* As the above bug report shows Excel 2010 creates: */
4493 /* <dxf><font><color rgb="FF9C0006"/></font><fill><patternFill>
4494 <bgColor rgb="FFFFC7CE"/></patternFill></fill></dxf> */
4496 gnm_style_set_pattern (state->style_accum, 1);
4498 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4499 if (attr_enum (xin, attrs, "patternType", patterns, &val))
4500 gnm_style_set_pattern (state->style_accum, val);
4503 static void
4504 xlsx_pattern_fg_bg (GsfXMLIn *xin, xmlChar const **attrs)
4506 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4507 gboolean solid_pattern = gnm_style_is_element_set (state->style_accum, MSTYLE_PATTERN)
4508 && (1 == gnm_style_get_pattern (state->style_accum));
4509 /* MAGIC :
4510 * Looks like pattern background and forground colours are inverted for
4511 * dxfs with solid fills for no apparent reason. */
4512 gboolean const invert = state->style_accum_partial
4513 && solid_pattern;
4514 /* LibreOffice 3.3.2 sets the alpha to 0, so solid fill becomes invisible */
4515 /* (Excel drops the alpha too it seems.) */
4516 GnmColor *color = elem_color (xin, attrs, !solid_pattern);
4517 if (NULL == color)
4518 return;
4520 if (xin->node->user_data.v_int ^ invert)
4521 gnm_style_set_back_color (state->style_accum, color);
4522 else
4523 gnm_style_set_pattern_color (state->style_accum, color);
4526 static void
4527 xlsx_CT_GradientFill (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4529 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4531 gnm_style_set_pattern (state->style_accum, 1);
4533 #if 0
4534 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4535 <xsd:attribute name="type" type="ST_GradientType" use="optional" default="linear">
4536 <xsd:attribute name="degree" type="xsd:double" use="optional" default="0">
4537 <xsd:attribute name="left" type="xsd:double" use="optional" default="0">
4538 <xsd:attribute name="right" type="xsd:double" use="optional" default="0">
4539 <xsd:attribute name="top" type="xsd:double" use="optional" default="0">
4540 <xsd:attribute name="bottom" type="xsd:double" use="optional" default="0">
4541 #endif
4544 static void
4545 xlsx_border_begin (GsfXMLIn *xin, xmlChar const **attrs)
4547 static EnumVal const borders[] = {
4548 { "none", GNM_STYLE_BORDER_NONE },
4549 { "thin", GNM_STYLE_BORDER_THIN },
4550 { "medium", GNM_STYLE_BORDER_MEDIUM },
4551 { "dashed", GNM_STYLE_BORDER_DASHED },
4552 { "dotted", GNM_STYLE_BORDER_DOTTED },
4553 { "thick", GNM_STYLE_BORDER_THICK },
4554 { "double", GNM_STYLE_BORDER_DOUBLE },
4555 { "hair", GNM_STYLE_BORDER_HAIR },
4556 { "mediumDashed", GNM_STYLE_BORDER_MEDIUM_DASH },
4557 { "dashDot", GNM_STYLE_BORDER_DASH_DOT },
4558 { "mediumDashDot", GNM_STYLE_BORDER_MEDIUM_DASH_DOT },
4559 { "dashDotDot", GNM_STYLE_BORDER_DASH_DOT_DOT },
4560 { "mediumDashDotDot", GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT },
4561 { "slantDashDot", GNM_STYLE_BORDER_SLANTED_DASH_DOT },
4562 { NULL, 0 }
4564 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4565 int border_style = GNM_STYLE_BORDER_NONE;
4567 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4568 if (attr_enum (xin, attrs, "style", borders, &border_style))
4571 state->border_style = border_style;
4572 state->border_color = NULL;
4575 static void
4576 xlsx_border_begin_v2 (GsfXMLIn *xin, xmlChar const **attrs)
4578 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4579 state->version = ECMA_376_2008;
4580 xlsx_border_begin (xin, attrs);
4583 static void
4584 xlsx_border_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4586 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4587 GnmBorder *border;
4588 GnmStyleBorderLocation const loc = xin->node->user_data.v_int;
4590 if (NULL == state->border_color)
4591 state->border_color = style_color_black ();
4592 border = gnm_style_border_fetch (state->border_style,
4593 state->border_color, gnm_style_border_get_orientation (loc));
4594 gnm_style_set_border (state->style_accum,
4595 GNM_STYLE_BORDER_LOCATION_TO_STYLE_ELEMENT (loc),
4596 border);
4597 state->border_color = NULL;
4600 static void
4601 xlsx_border_diagonal_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4603 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4604 GnmBorder *border, *new_border;
4606 if (NULL == state->border_color)
4607 state->border_color = style_color_black ();
4608 new_border = gnm_style_border_fetch
4609 (state->border_style, state->border_color, GNM_STYLE_BORDER_DIAGONAL);
4611 border = gnm_style_get_border (state->style_accum, MSTYLE_BORDER_REV_DIAGONAL);
4612 if (border != NULL && border->line_type != GNM_STYLE_BORDER_NONE) {
4613 gnm_style_border_ref (new_border);
4614 gnm_style_set_border (state->style_accum,
4615 MSTYLE_BORDER_REV_DIAGONAL,
4616 new_border);
4618 border = gnm_style_get_border (state->style_accum, MSTYLE_BORDER_DIAGONAL);
4619 if (border != NULL && border->line_type != GNM_STYLE_BORDER_NONE) {
4620 gnm_style_border_ref (new_border);
4621 gnm_style_set_border (state->style_accum,
4622 MSTYLE_BORDER_DIAGONAL,
4623 new_border);
4625 gnm_style_border_unref (new_border);
4626 state->border_color = NULL;
4629 static void
4630 xlsx_border_color (GsfXMLIn *xin, xmlChar const **attrs)
4632 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4633 GnmColor *color = elem_color (xin, attrs, TRUE);
4634 if (state->border_color)
4635 style_color_unref (state->border_color);
4636 state->border_color = color;
4639 static void
4640 xlsx_xf_begin (GsfXMLIn *xin, xmlChar const **attrs)
4642 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4643 GnmStyle *accum = gnm_style_new ();
4644 GnmStyle *parent = NULL;
4645 GnmStyle *result;
4646 GPtrArray *elem = NULL;
4647 int indx;
4649 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4650 if (0 == strcmp (attrs[0], "numFmtId")) {
4651 GOFormat *fmt = xlsx_get_num_fmt (xin, attrs[1]);
4652 if (NULL != fmt)
4653 gnm_style_set_format (accum, fmt);
4654 } else if (attr_int (xin, attrs, "fontId", &indx))
4655 elem = state->fonts;
4656 else if (attr_int (xin, attrs, "fillId", &indx))
4657 elem = state->fills;
4658 else if (attr_int (xin, attrs, "borderId", &indx))
4659 elem = state->borders;
4660 else if (attr_int (xin, attrs, "xfId", &indx))
4661 parent = xlsx_get_style_xf (xin, indx);
4663 if (NULL != elem) {
4664 GnmStyle const *component = NULL;
4665 if (0 <= indx && indx < (int)elem->len)
4666 component = g_ptr_array_index (elem, indx);
4667 if (NULL != component) {
4668 #if 0
4669 gnm_style_merge (accum, component);
4670 #else
4671 GnmStyle *merged = gnm_style_new_merged (accum, component);
4672 gnm_style_unref (accum);
4673 accum = merged;
4674 #endif
4675 } else
4676 xlsx_warning (xin, "Missing record '%d' for %s", indx, attrs[0]);
4677 elem = NULL;
4680 if (NULL == parent) {
4681 result = gnm_style_new_default ();
4682 gnm_style_merge (result, accum);
4683 } else
4684 result = gnm_style_new_merged (parent, accum);
4685 gnm_style_unref (accum);
4687 state->style_accum = result;
4688 #if 0
4689 "quotePrefix" ??
4691 "applyNumberFormat"
4692 "applyFont"
4693 "applyFill"
4694 "applyBorder"
4695 "applyAlignment"
4696 "applyProtection"
4697 #endif
4699 static void
4700 xlsx_xf_end (GsfXMLIn *xin, GsfXMLBlob *blob)
4702 xlsx_col_elem_end (xin, blob);
4705 static void
4706 xlsx_xf_align (GsfXMLIn *xin, xmlChar const **attrs)
4708 static EnumVal const haligns[] = {
4709 { "general" , GNM_HALIGN_GENERAL },
4710 { "left" , GNM_HALIGN_LEFT },
4711 { "center" , GNM_HALIGN_CENTER },
4712 { "right" , GNM_HALIGN_RIGHT },
4713 { "fill" , GNM_HALIGN_FILL },
4714 { "justify" , GNM_HALIGN_JUSTIFY },
4715 { "centerContinuous" , GNM_HALIGN_CENTER_ACROSS_SELECTION },
4716 { "distributed" , GNM_HALIGN_DISTRIBUTED },
4717 { NULL, 0 }
4720 static EnumVal const valigns[] = {
4721 { "top", GNM_VALIGN_TOP },
4722 { "center", GNM_VALIGN_CENTER },
4723 { "bottom", GNM_VALIGN_BOTTOM },
4724 { "justify", GNM_VALIGN_JUSTIFY },
4725 { "distributed", GNM_VALIGN_DISTRIBUTED },
4726 { NULL, 0 }
4729 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4730 int halign = GNM_HALIGN_GENERAL;
4731 int valign = GNM_VALIGN_BOTTOM;
4732 int rotation = 0, indent = 0;
4733 int wrapText = FALSE, justifyLastLine = FALSE, shrinkToFit = FALSE;
4735 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4736 if (attr_enum (xin, attrs, "horizontal", haligns, &halign) ||
4737 attr_enum (xin, attrs, "vertical", valigns, &valign) ||
4738 attr_int (xin, attrs, "textRotation", &rotation) ||
4739 attr_bool (xin, attrs, "wrapText", &wrapText) ||
4740 attr_int (xin, attrs, "indent", &indent) ||
4741 attr_bool (xin, attrs, "justifyLastLine", &justifyLastLine) ||
4742 attr_bool (xin, attrs, "shrinkToFit", &shrinkToFit)
4743 /* "mergeCell" type="xs:boolean" use="optional" default="false" */
4744 /* "readingOrder" type="xs:unsignedInt" use="optional" default="0" */
4748 gnm_style_set_align_h (state->style_accum, halign);
4749 gnm_style_set_align_v (state->style_accum, valign);
4750 gnm_style_set_rotation (state->style_accum,
4751 (rotation == 0xff) ? -1 : ((rotation > 90) ? (360 + 90 - rotation) : rotation));
4752 gnm_style_set_wrap_text (state->style_accum, wrapText);
4753 gnm_style_set_indent (state->style_accum, indent);
4754 gnm_style_set_shrink_to_fit (state->style_accum, shrinkToFit);
4757 static void
4758 xlsx_xf_protect (GsfXMLIn *xin, xmlChar const **attrs)
4760 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4761 int locked = TRUE;
4762 int hidden = TRUE;
4764 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4765 if (attr_bool (xin, attrs, "locked", &locked))
4767 else if (attr_bool (xin, attrs, "hidden", &hidden))
4771 gnm_style_set_contents_locked (state->style_accum, locked);
4772 gnm_style_set_contents_hidden (state->style_accum, hidden);
4775 static void
4776 xlsx_cell_style (GsfXMLIn *xin, xmlChar const **attrs)
4778 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4779 /* xmlChar const *name = NULL; */
4780 xmlChar const *id = NULL;
4781 GnmStyle *style = NULL;
4782 int tmp;
4784 /* cellStyle name="Normal" xfId="0" builtinId="0" */
4785 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4786 if (attr_int (xin, attrs, "xfId", &tmp))
4787 style = xlsx_get_style_xf (xin, tmp);
4788 else /* if (0 == strcmp (attrs[0], "name")) */
4789 /* name = attrs[1]; */
4790 /* else */ if (0 == strcmp (attrs[0], "builtinId"))
4791 id = attrs[1];
4794 if (NULL != style && NULL != id) {
4795 gnm_style_ref (style);
4796 g_hash_table_replace (state->cell_styles, g_strdup (id), style);
4800 static void
4801 xlsx_dxf_begin (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
4803 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4804 state->style_accum_partial = TRUE;
4805 state->style_accum = gnm_style_new ();
4807 static void
4808 xlsx_dxf_end (GsfXMLIn *xin, GsfXMLBlob *blob)
4810 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4811 state->style_accum_partial = FALSE;
4812 xlsx_col_elem_end (xin, blob);
4815 static void
4816 xlsx_dxf_numfmt (GsfXMLIn *xin, xmlChar const **attrs)
4818 xlsx_numfmt_common (xin, attrs, TRUE);
4822 static GsfXMLInNode const xlsx_styles_dtd[] = {
4823 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4824 GSF_XML_IN_NODE_FULL (START, STYLE_INFO, XL_NS_SS, "styleSheet", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4825 GSF_XML_IN_NODE (STYLE_INFO, EXTLST, XL_NS_SS, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
4826 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_SS, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
4827 GSF_XML_IN_NODE (STYLE_INFO, NUM_FMTS, XL_NS_SS, "numFmts", GSF_XML_NO_CONTENT, NULL, NULL),
4828 GSF_XML_IN_NODE (NUM_FMTS, NUM_FMT, XL_NS_SS, "numFmt", GSF_XML_NO_CONTENT, &xlsx_style_numfmt, NULL),
4830 GSF_XML_IN_NODE_FULL (STYLE_INFO, FONTS, XL_NS_SS, "fonts", GSF_XML_NO_CONTENT,
4831 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_FONT),
4832 GSF_XML_IN_NODE (FONTS, FONT, XL_NS_SS, "font", GSF_XML_NO_CONTENT, &xlsx_col_elem_begin, &xlsx_col_elem_end),
4833 GSF_XML_IN_NODE (FONT, FONT_NAME, XL_NS_SS, "name", GSF_XML_NO_CONTENT, &xlsx_font_name, NULL),
4834 GSF_XML_IN_NODE (FONT, FONT_CHARSET, XL_NS_SS, "charset", GSF_XML_NO_CONTENT, NULL, NULL),
4835 GSF_XML_IN_NODE (FONT, FONT_FAMILY, XL_NS_SS, "family", GSF_XML_NO_CONTENT, NULL, NULL),
4836 GSF_XML_IN_NODE (FONT, FONT_BOLD, XL_NS_SS, "b", GSF_XML_NO_CONTENT, &xlsx_font_bold, NULL),
4837 GSF_XML_IN_NODE (FONT, FONT_ITALIC, XL_NS_SS, "i", GSF_XML_NO_CONTENT, &xlsx_font_italic, NULL),
4838 GSF_XML_IN_NODE (FONT, FONT_STRIKE, XL_NS_SS, "strike", GSF_XML_NO_CONTENT, &xlsx_font_strike, NULL),
4839 GSF_XML_IN_NODE (FONT, FONT_OUTLINE, XL_NS_SS, "outline", GSF_XML_NO_CONTENT, NULL, NULL),
4840 GSF_XML_IN_NODE (FONT, FONT_SHADOW, XL_NS_SS, "shadow", GSF_XML_NO_CONTENT, NULL, NULL),
4841 GSF_XML_IN_NODE (FONT, FONT_CONDENSE, XL_NS_SS, "condense", GSF_XML_NO_CONTENT, NULL, NULL),
4842 GSF_XML_IN_NODE (FONT, FONT_EXTEND, XL_NS_SS, "extend", GSF_XML_NO_CONTENT, NULL, NULL),
4843 GSF_XML_IN_NODE (FONT, FONT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_font_color, NULL),
4844 GSF_XML_IN_NODE (FONT, FONT_SZ, XL_NS_SS, "sz", GSF_XML_NO_CONTENT, &xlsx_CT_FontSize, NULL),
4845 GSF_XML_IN_NODE (FONT, FONT_SCRIPT, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, &xlsx_CT_vertAlign, NULL),
4846 GSF_XML_IN_NODE (FONT, FONT_ULINE, XL_NS_SS, "u", GSF_XML_NO_CONTENT, &xlsx_font_uline, NULL),
4847 GSF_XML_IN_NODE (FONT, FONT_VERTALIGN, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, &xlsx_font_valign, NULL),
4848 GSF_XML_IN_NODE (FONT, FONT_SCHEME, XL_NS_SS, "scheme", GSF_XML_NO_CONTENT, NULL, NULL),
4850 GSF_XML_IN_NODE_FULL (STYLE_INFO, FILLS, XL_NS_SS, "fills", GSF_XML_NO_CONTENT,
4851 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_FILLS),
4852 GSF_XML_IN_NODE (FILLS, FILL, XL_NS_SS, "fill", GSF_XML_NO_CONTENT, &xlsx_col_elem_begin, &xlsx_col_elem_end),
4853 GSF_XML_IN_NODE (FILL, PATTERN_FILL, XL_NS_SS, "patternFill", GSF_XML_NO_CONTENT, &xlsx_pattern, NULL),
4854 GSF_XML_IN_NODE_FULL (PATTERN_FILL, PATTERN_FILL_FG, XL_NS_SS, "fgColor", GSF_XML_NO_CONTENT,
4855 FALSE, FALSE, &xlsx_pattern_fg_bg, NULL, TRUE),
4856 GSF_XML_IN_NODE_FULL (PATTERN_FILL, PATTERN_FILL_BG, XL_NS_SS, "bgColor", GSF_XML_NO_CONTENT,
4857 FALSE, FALSE, &xlsx_pattern_fg_bg, NULL, FALSE),
4858 GSF_XML_IN_NODE (FILL, IMAGE_FILL, XL_NS_SS, "image", GSF_XML_NO_CONTENT, NULL, NULL),
4859 GSF_XML_IN_NODE (FILL, GRADIENT_FILL, XL_NS_SS, "gradientFill", GSF_XML_NO_CONTENT, &xlsx_CT_GradientFill, NULL),
4860 GSF_XML_IN_NODE (GRADIENT_FILL, GRADIENT_STOPS, XL_NS_SS, "stop", GSF_XML_NO_CONTENT, NULL, NULL),
4861 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),
4863 GSF_XML_IN_NODE_FULL (STYLE_INFO, BORDERS, XL_NS_SS, "borders", GSF_XML_NO_CONTENT,
4864 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_BORDERS),
4865 GSF_XML_IN_NODE (BORDERS, BORDER, XL_NS_SS, "border", GSF_XML_NO_CONTENT, &xlsx_col_border_begin, &xlsx_col_elem_end),
4866 GSF_XML_IN_NODE_FULL (BORDER, LEFT_B, XL_NS_SS, "left", GSF_XML_NO_CONTENT, FALSE, FALSE,
4867 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_LEFT),
4868 GSF_XML_IN_NODE (LEFT_B, LEFT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4869 GSF_XML_IN_NODE_FULL (BORDER, START_B, XL_NS_SS, "start", GSF_XML_NO_CONTENT, FALSE, FALSE,
4870 &xlsx_border_begin_v2, &xlsx_border_end, GNM_STYLE_BORDER_LEFT),
4871 GSF_XML_IN_NODE (START_B, START_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4872 GSF_XML_IN_NODE_FULL (BORDER, RIGHT_B, XL_NS_SS, "right", GSF_XML_NO_CONTENT, FALSE, FALSE,
4873 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_RIGHT),
4874 GSF_XML_IN_NODE (RIGHT_B, RIGHT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4875 GSF_XML_IN_NODE_FULL (BORDER, END_B, XL_NS_SS, "end", GSF_XML_NO_CONTENT, FALSE, FALSE,
4876 &xlsx_border_begin_v2, &xlsx_border_end, GNM_STYLE_BORDER_RIGHT),
4877 GSF_XML_IN_NODE (END_B, END_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4878 GSF_XML_IN_NODE_FULL (BORDER, TOP_B, XL_NS_SS, "top", GSF_XML_NO_CONTENT, FALSE, FALSE,
4879 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_TOP),
4880 GSF_XML_IN_NODE (TOP_B, TOP_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4881 GSF_XML_IN_NODE_FULL (BORDER, BOTTOM_B, XL_NS_SS, "bottom", GSF_XML_NO_CONTENT, FALSE, FALSE,
4882 &xlsx_border_begin, &xlsx_border_end, GNM_STYLE_BORDER_BOTTOM),
4883 GSF_XML_IN_NODE (BOTTOM_B, BOTTOM_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4884 GSF_XML_IN_NODE (BORDER, DIAG_B, XL_NS_SS, "diagonal", GSF_XML_NO_CONTENT,
4885 &xlsx_border_begin, &xlsx_border_diagonal_end),
4886 GSF_XML_IN_NODE (DIAG_B, DIAG_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, &xlsx_border_color, NULL),
4888 GSF_XML_IN_NODE (BORDER, BORDER_VERT, XL_NS_SS, "vertical", GSF_XML_NO_CONTENT, NULL, NULL),
4889 GSF_XML_IN_NODE (BORDER_VERT, VERT_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
4890 GSF_XML_IN_NODE (BORDER, BORDER_HORIZ, XL_NS_SS, "horizontal", GSF_XML_NO_CONTENT, NULL, NULL),
4891 GSF_XML_IN_NODE (BORDER_HORIZ, HORIZ_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
4893 GSF_XML_IN_NODE_FULL (STYLE_INFO, XFS, XL_NS_SS, "cellXfs", GSF_XML_NO_CONTENT,
4894 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_XFS),
4895 GSF_XML_IN_NODE (XFS, XF, XL_NS_SS, "xf", GSF_XML_NO_CONTENT, &xlsx_xf_begin, &xlsx_xf_end),
4896 GSF_XML_IN_NODE (XF, ALIGNMENT, XL_NS_SS, "alignment", GSF_XML_NO_CONTENT, &xlsx_xf_align, NULL),
4897 GSF_XML_IN_NODE (XF, PROTECTION, XL_NS_SS, "protection", GSF_XML_NO_CONTENT, &xlsx_xf_protect, NULL),
4899 GSF_XML_IN_NODE_FULL (STYLE_INFO, STYLE_XFS, XL_NS_SS, "cellStyleXfs", GSF_XML_NO_CONTENT,
4900 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_STYLE_XFS),
4901 GSF_XML_IN_NODE (STYLE_XFS, STYLE_XF, XL_NS_SS, "xf", GSF_XML_NO_CONTENT, &xlsx_xf_begin, &xlsx_xf_end),
4902 GSF_XML_IN_NODE (STYLE_XF, STYLE_ALIGNMENT, XL_NS_SS, "alignment", GSF_XML_NO_CONTENT, &xlsx_xf_align, NULL),
4903 GSF_XML_IN_NODE (STYLE_XF, STYLE_PROTECTION, XL_NS_SS, "protection", GSF_XML_NO_CONTENT, &xlsx_xf_protect, NULL),
4905 GSF_XML_IN_NODE (STYLE_INFO, STYLE_NAMES, XL_NS_SS, "cellStyles", GSF_XML_NO_CONTENT, NULL, NULL),
4906 GSF_XML_IN_NODE (STYLE_NAMES, STYLE_NAME, XL_NS_SS, "cellStyle", GSF_XML_NO_CONTENT, &xlsx_cell_style, NULL),
4907 GSF_XML_IN_NODE (STYLE_NAME, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
4908 GSF_XML_IN_NODE_FULL (STYLE_INFO, PARTIAL_XFS, XL_NS_SS, "dxfs", GSF_XML_NO_CONTENT,
4909 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_DXFS),
4910 GSF_XML_IN_NODE (PARTIAL_XFS, PARTIAL_XF, XL_NS_SS, "dxf", GSF_XML_NO_CONTENT, &xlsx_dxf_begin, &xlsx_dxf_end),
4911 GSF_XML_IN_NODE (PARTIAL_XF, DXF_NUM_FMT, XL_NS_SS, "numFmt", GSF_XML_NO_CONTENT, &xlsx_dxf_numfmt, NULL),
4912 GSF_XML_IN_NODE (PARTIAL_XF, FONT, XL_NS_SS, "font", GSF_XML_2ND, NULL, NULL),
4913 GSF_XML_IN_NODE (PARTIAL_XF, FILL, XL_NS_SS, "fill", GSF_XML_2ND, NULL, NULL),
4914 GSF_XML_IN_NODE (PARTIAL_XF, BORDER, XL_NS_SS, "border", GSF_XML_2ND, NULL, NULL),
4915 GSF_XML_IN_NODE (PARTIAL_XF, DXF_ALIGNMENT, XL_NS_SS, "alignment", GSF_XML_NO_CONTENT, &xlsx_xf_align, NULL),
4916 GSF_XML_IN_NODE (PARTIAL_XF, DXF_PROTECTION, XL_NS_SS, "protection", GSF_XML_NO_CONTENT, &xlsx_xf_protect, NULL),
4917 GSF_XML_IN_NODE (PARTIAL_XF, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
4919 GSF_XML_IN_NODE_FULL (STYLE_INFO, TABLE_STYLES, XL_NS_SS, "tableStyles", GSF_XML_NO_CONTENT,
4920 FALSE, FALSE, &xlsx_collection_begin, &xlsx_collection_end, XLSX_COLLECT_TABLE_STYLES),
4921 GSF_XML_IN_NODE (TABLE_STYLES, TABLE_STYLE, XL_NS_SS, "tableStyle", GSF_XML_NO_CONTENT, NULL, NULL),
4923 GSF_XML_IN_NODE (STYLE_INFO, COLORS, XL_NS_SS, "colors", GSF_XML_NO_CONTENT, NULL, NULL),
4924 GSF_XML_IN_NODE (COLORS, INDEXED_COLORS, XL_NS_SS, "indexedColors", GSF_XML_NO_CONTENT, NULL, NULL),
4925 GSF_XML_IN_NODE (INDEXED_COLORS, INDEXED_RGB, XL_NS_SS, "rgbColor", GSF_XML_NO_CONTENT, NULL, NULL),
4926 GSF_XML_IN_NODE (COLORS, THEME_COLORS, XL_NS_SS, "themeColors", GSF_XML_NO_CONTENT, NULL, NULL),
4927 GSF_XML_IN_NODE (THEME_COLORS, THEMED_RGB, XL_NS_SS, "rgbColor", GSF_XML_NO_CONTENT, NULL, NULL),
4928 GSF_XML_IN_NODE (COLORS, MRU_COLORS, XL_NS_SS, "mruColors", GSF_XML_NO_CONTENT, NULL, NULL),
4929 GSF_XML_IN_NODE (MRU_COLORS, MRU_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, NULL, NULL),
4931 GSF_XML_IN_NODE_END
4934 /****************************************************************************/
4936 static void
4937 xlsx_theme_color_sys (GsfXMLIn *xin, xmlChar const **attrs)
4939 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4940 GOColor c = GO_COLOR_BLACK;
4942 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4943 if (attr_gocolor (xin, attrs, "lastClr", &c)) {
4947 state->color = c;
4949 static void
4950 xlsx_theme_color_rgb (GsfXMLIn *xin, xmlChar const **attrs)
4952 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4953 GOColor c = GO_COLOR_BLACK;
4955 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
4956 if (attr_gocolor (xin, attrs, "val", &c)) {
4960 state->color = c;
4963 static void
4964 xlsx_theme_color_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
4966 XLSXReadState *state = (XLSXReadState *)xin->user_state;
4967 const char *name = ((GsfXMLInNode *)xin->node_stack->data)->name;
4969 g_hash_table_replace (state->theme_colors_by_name,
4970 g_strdup (name),
4971 GUINT_TO_POINTER (state->color));
4974 static GsfXMLInNode const xlsx_theme_dtd[] = {
4975 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4976 GSF_XML_IN_NODE_FULL (START, THEME, XL_NS_DRAW, "theme", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
4977 GSF_XML_IN_NODE (THEME, ELEMENTS, XL_NS_DRAW, "themeElements", GSF_XML_NO_CONTENT, NULL, NULL),
4978 GSF_XML_IN_NODE (ELEMENTS, COLOR_SCHEME, XL_NS_DRAW, "clrScheme", GSF_XML_NO_CONTENT, NULL, NULL),
4979 GSF_XML_IN_NODE (COLOR_SCHEME, dk1, XL_NS_DRAW, "dk1", GSF_XML_NO_CONTENT, NULL, NULL),
4980 GSF_XML_IN_NODE (dk1, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, &xlsx_theme_color_sys, &xlsx_theme_color_end),
4981 COLOR_MODIFIER_NODES(SYS_COLOR,TRUE),
4982 GSF_XML_IN_NODE (dk1, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, &xlsx_theme_color_rgb, &xlsx_theme_color_end),
4983 COLOR_MODIFIER_NODES(RGB_COLOR,FALSE),
4984 GSF_XML_IN_NODE (COLOR_SCHEME, lt1, XL_NS_DRAW, "lt1", GSF_XML_NO_CONTENT, NULL, NULL),
4985 GSF_XML_IN_NODE (lt1, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
4986 GSF_XML_IN_NODE (lt1, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
4987 GSF_XML_IN_NODE (COLOR_SCHEME, lt2, XL_NS_DRAW, "lt2", GSF_XML_NO_CONTENT, NULL, NULL),
4988 GSF_XML_IN_NODE (lt2, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
4989 GSF_XML_IN_NODE (lt2, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
4990 GSF_XML_IN_NODE (COLOR_SCHEME, dk2, XL_NS_DRAW, "dk2", GSF_XML_NO_CONTENT, NULL, NULL),
4991 GSF_XML_IN_NODE (dk2, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
4992 GSF_XML_IN_NODE (dk2, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
4993 GSF_XML_IN_NODE (COLOR_SCHEME, accent1, XL_NS_DRAW, "accent1", GSF_XML_NO_CONTENT, NULL, NULL),
4994 GSF_XML_IN_NODE (accent1, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
4995 GSF_XML_IN_NODE (accent1, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
4996 GSF_XML_IN_NODE (COLOR_SCHEME, accent2, XL_NS_DRAW, "accent2", GSF_XML_NO_CONTENT, NULL, NULL),
4997 GSF_XML_IN_NODE (accent2, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
4998 GSF_XML_IN_NODE (accent2, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
4999 GSF_XML_IN_NODE (COLOR_SCHEME, accent3, XL_NS_DRAW, "accent3", GSF_XML_NO_CONTENT, NULL, NULL),
5000 GSF_XML_IN_NODE (accent3, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5001 GSF_XML_IN_NODE (accent3, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5002 GSF_XML_IN_NODE (COLOR_SCHEME, accent4, XL_NS_DRAW, "accent4", GSF_XML_NO_CONTENT, NULL, NULL),
5003 GSF_XML_IN_NODE (accent4, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5004 GSF_XML_IN_NODE (accent4, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5005 GSF_XML_IN_NODE (COLOR_SCHEME, accent5, XL_NS_DRAW, "accent5", GSF_XML_NO_CONTENT, NULL, NULL),
5006 GSF_XML_IN_NODE (accent5, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5007 GSF_XML_IN_NODE (accent5, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5008 GSF_XML_IN_NODE (COLOR_SCHEME, accent6, XL_NS_DRAW, "accent6", GSF_XML_NO_CONTENT, NULL, NULL),
5009 GSF_XML_IN_NODE (accent6, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5010 GSF_XML_IN_NODE (accent6, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5011 GSF_XML_IN_NODE (COLOR_SCHEME, hlink, XL_NS_DRAW, "hlink", GSF_XML_NO_CONTENT, NULL, NULL),
5012 GSF_XML_IN_NODE (hlink, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5013 GSF_XML_IN_NODE (hlink, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5014 GSF_XML_IN_NODE (COLOR_SCHEME, folHlink, XL_NS_DRAW, "folHlink", GSF_XML_NO_CONTENT, NULL, NULL),
5015 GSF_XML_IN_NODE (folHlink, SYS_COLOR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5016 GSF_XML_IN_NODE (folHlink, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5018 GSF_XML_IN_NODE (ELEMENTS, FONT_SCHEME, XL_NS_DRAW, "fontScheme", GSF_XML_NO_CONTENT, NULL, NULL),
5019 GSF_XML_IN_NODE (FONT_SCHEME, MAJOR_FONT, XL_NS_DRAW, "majorFont", GSF_XML_NO_CONTENT, NULL, NULL),
5020 GSF_XML_IN_NODE (MAJOR_FONT, FONT_CS, XL_NS_DRAW, "cs", GSF_XML_NO_CONTENT, NULL, NULL),
5021 GSF_XML_IN_NODE (MAJOR_FONT, FONT_EA, XL_NS_DRAW, "ea", GSF_XML_NO_CONTENT, NULL, NULL),
5022 GSF_XML_IN_NODE (MAJOR_FONT, FONT_FONT, XL_NS_DRAW, "font", GSF_XML_NO_CONTENT, NULL, NULL),
5023 GSF_XML_IN_NODE (MAJOR_FONT, FONT_LATIN, XL_NS_DRAW, "latin", GSF_XML_NO_CONTENT, NULL, NULL),
5024 GSF_XML_IN_NODE (FONT_SCHEME, MINOR_FONT, XL_NS_DRAW, "minorFont", GSF_XML_NO_CONTENT, NULL, NULL),
5025 GSF_XML_IN_NODE (MINOR_FONT, FONT_CS, XL_NS_DRAW, "cs", GSF_XML_NO_CONTENT, NULL, NULL),
5026 GSF_XML_IN_NODE (MINOR_FONT, FONT_EA, XL_NS_DRAW, "ea", GSF_XML_NO_CONTENT, NULL, NULL),
5027 GSF_XML_IN_NODE (MINOR_FONT, FONT_FONT, XL_NS_DRAW, "font", GSF_XML_NO_CONTENT, NULL, NULL),
5028 GSF_XML_IN_NODE (MINOR_FONT, FONT_LATIN, XL_NS_DRAW, "latin", GSF_XML_NO_CONTENT, NULL, NULL),
5030 GSF_XML_IN_NODE (ELEMENTS, FORMAT_SCHEME, XL_NS_DRAW, "fmtScheme", GSF_XML_NO_CONTENT, NULL, NULL),
5031 GSF_XML_IN_NODE (FORMAT_SCHEME, FILL_STYLE_LIST, XL_NS_DRAW, "fillStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
5032 GSF_XML_IN_NODE (FILL_STYLE_LIST, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_NO_CONTENT, NULL, NULL),
5033 GSF_XML_IN_NODE (SOLID_FILL, SCHEME_COLOR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),
5034 COLOR_MODIFIER_NODES(SCHEME_COLOR,FALSE),
5035 GSF_XML_IN_NODE (FILL_STYLE_LIST, GRAD_FILL, XL_NS_DRAW, "gradFill", GSF_XML_NO_CONTENT, NULL, NULL),
5036 GSF_XML_IN_NODE (GRAD_FILL, GRAD_PATH, XL_NS_DRAW, "path", GSF_XML_NO_CONTENT, NULL, NULL),
5037 GSF_XML_IN_NODE (GRAD_PATH, GRAD_PATH_RECT, XL_NS_DRAW, "fillToRect", GSF_XML_NO_CONTENT, NULL, NULL),
5038 GSF_XML_IN_NODE (GRAD_FILL, GRAD_LIST, XL_NS_DRAW, "gsLst", GSF_XML_NO_CONTENT, NULL, NULL),
5039 GSF_XML_IN_NODE (GRAD_LIST, GRAD_LIST_ITEM, XL_NS_DRAW, "gs", GSF_XML_NO_CONTENT, NULL, NULL),
5040 GSF_XML_IN_NODE (GRAD_LIST_ITEM, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5041 GSF_XML_IN_NODE (GRAD_LIST_ITEM, SCHEME_COLOR, XL_NS_DRAW, "schemeClr", GSF_XML_2ND, NULL, NULL),
5042 GSF_XML_IN_NODE (GRAD_FILL, GRAD_LINE, XL_NS_DRAW, "lin", GSF_XML_NO_CONTENT, NULL, NULL),
5044 GSF_XML_IN_NODE (FORMAT_SCHEME, BG_FILL_STYLE_LIST, XL_NS_DRAW, "bgFillStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
5045 GSF_XML_IN_NODE (BG_FILL_STYLE_LIST, GRAD_FILL, XL_NS_DRAW, "gradFill", GSF_XML_2ND, NULL, NULL),
5046 GSF_XML_IN_NODE (BG_FILL_STYLE_LIST, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_2ND, NULL, NULL),
5047 GSF_XML_IN_NODE (FORMAT_SCHEME, LINE_STYLE_LIST, XL_NS_DRAW, "lnStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
5048 GSF_XML_IN_NODE (LINE_STYLE_LIST, LINE_STYLE, XL_NS_DRAW, "ln", GSF_XML_NO_CONTENT, NULL, NULL),
5049 GSF_XML_IN_NODE (LINE_STYLE, LN_NOFILL, XL_NS_DRAW, "noFill", GSF_XML_NO_CONTENT, NULL, NULL),
5050 GSF_XML_IN_NODE (LINE_STYLE, LN_DASH, XL_NS_DRAW, "prstDash", GSF_XML_NO_CONTENT, NULL, NULL),
5051 GSF_XML_IN_NODE (LINE_STYLE, LN_MITER, XL_NS_DRAW, "miter", GSF_XML_NO_CONTENT, NULL, NULL),
5052 GSF_XML_IN_NODE (LINE_STYLE, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_2ND, NULL, NULL),
5053 GSF_XML_IN_NODE (LINE_STYLE, FILL_PATT, XL_NS_DRAW, "pattFill", GSF_XML_NO_CONTENT, NULL, NULL),
5054 GSF_XML_IN_NODE (FORMAT_SCHEME, EFFECT_STYLE_LIST, XL_NS_DRAW, "effectStyleLst", GSF_XML_NO_CONTENT, NULL, NULL),
5055 GSF_XML_IN_NODE (EFFECT_STYLE_LIST, EFFECT_STYLE, XL_NS_DRAW, "effectStyle", GSF_XML_NO_CONTENT, NULL, NULL),
5056 GSF_XML_IN_NODE (EFFECT_STYLE, EFFECT_PROP, XL_NS_DRAW, "sp3d", GSF_XML_NO_CONTENT, NULL, NULL),
5057 GSF_XML_IN_NODE (EFFECT_PROP, CONTOUR_CLR, XL_NS_DRAW, "contourClr", GSF_XML_NO_CONTENT, NULL, NULL),
5058 GSF_XML_IN_NODE (CONTOUR_CLR, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),
5059 GSF_XML_IN_NODE (EFFECT_PROP, PROP_BEVEL, XL_NS_DRAW, "bevelT", GSF_XML_NO_CONTENT, NULL, NULL),
5060 GSF_XML_IN_NODE (EFFECT_STYLE, EFFECT_LIST, XL_NS_DRAW, "effectLst", GSF_XML_NO_CONTENT, NULL, NULL),
5061 GSF_XML_IN_NODE (EFFECT_LIST, REFLECTION, XL_NS_DRAW, "reflection", GSF_XML_NO_CONTENT, NULL, NULL),
5062 GSF_XML_IN_NODE (EFFECT_LIST, OUTER_SHADOW, XL_NS_DRAW, "outerShdw", GSF_XML_NO_CONTENT, NULL, NULL),
5063 GSF_XML_IN_NODE (OUTER_SHADOW, RGB_COLOR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5064 GSF_XML_IN_NODE (EFFECT_STYLE, EFFECT_SCENE_3D, XL_NS_DRAW, "scene3d", GSF_XML_NO_CONTENT, NULL, NULL),
5065 GSF_XML_IN_NODE (EFFECT_SCENE_3D, 3D_CAMERA, XL_NS_DRAW, "camera", GSF_XML_NO_CONTENT, NULL, NULL),
5066 GSF_XML_IN_NODE (3D_CAMERA, 3D_ROT, XL_NS_DRAW, "rot", GSF_XML_NO_CONTENT, NULL, NULL),
5067 GSF_XML_IN_NODE (EFFECT_SCENE_3D, 3D_LIGHT, XL_NS_DRAW, "lightRig", GSF_XML_NO_CONTENT, NULL, NULL),
5068 GSF_XML_IN_NODE (3D_LIGHT, 3D_ROT, XL_NS_DRAW, "rot", GSF_XML_NO_CONTENT, NULL, NULL),
5070 GSF_XML_IN_NODE (THEME, OBJ_DEFAULTS, XL_NS_DRAW, "objectDefaults", GSF_XML_NO_CONTENT, NULL, NULL),
5071 GSF_XML_IN_NODE (OBJ_DEFAULTS, SP_DEF, XL_NS_DRAW, "spDef", GSF_XML_NO_CONTENT, NULL, NULL),
5072 GSF_XML_IN_NODE (SP_DEF, SHAPE_PR, XL_NS_DRAW, "spPr", GSF_XML_NO_CONTENT, NULL, NULL),
5073 GSF_XML_IN_NODE (SHAPE_PR, XFRM, XL_NS_DRAW, "xfrm", GSF_XML_NO_CONTENT, NULL, NULL),
5074 GSF_XML_IN_NODE (SHAPE_PR, CUST_GEOM, XL_NS_DRAW, "custGeom", GSF_XML_NO_CONTENT, NULL, NULL),
5075 GSF_XML_IN_NODE (SHAPE_PR, EXTLST, XL_NS_DRAW, "extLst", GSF_XML_NO_CONTENT, NULL, NULL),
5076 GSF_XML_IN_NODE (EXTLST, EXTITEM, XL_NS_DRAW, "ext", GSF_XML_NO_CONTENT, &xlsx_ext_begin, &xlsx_ext_end),
5077 GSF_XML_IN_NODE (SHAPE_PR, SOLID_FILL, XL_NS_DRAW, "solidFill", GSF_XML_NO_CONTENT, NULL, NULL),
5078 GSF_XML_IN_NODE (SP_DEF, BODY_PR, XL_NS_DRAW, "bodyPr", GSF_XML_NO_CONTENT, NULL, NULL),
5079 GSF_XML_IN_NODE (SP_DEF, LST_STYLE, XL_NS_DRAW, "lstStyle", GSF_XML_NO_CONTENT, NULL, NULL),
5080 GSF_XML_IN_NODE (SP_DEF, STYLE, XL_NS_DRAW, "style", GSF_XML_NO_CONTENT, NULL, NULL),
5081 GSF_XML_IN_NODE (STYLE, EFFECT_REF, XL_NS_DRAW, "effectRef", GSF_XML_NO_CONTENT, NULL, NULL),
5082 GSF_XML_IN_NODE (EFFECT_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_NO_CONTENT, NULL, NULL),
5083 GSF_XML_IN_NODE (EFFECT_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_NO_CONTENT, NULL, NULL),
5084 GSF_XML_IN_NODE (EFFECT_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_NO_CONTENT, NULL, NULL),
5085 GSF_XML_IN_NODE (EFFECT_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_NO_CONTENT, NULL, NULL),
5086 GSF_XML_IN_NODE (EFFECT_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_NO_CONTENT, NULL, NULL),
5087 GSF_XML_IN_NODE (EFFECT_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_NO_CONTENT, NULL, NULL),
5088 GSF_XML_IN_NODE (STYLE, FILL_REF, XL_NS_DRAW, "fillRef", GSF_XML_NO_CONTENT, NULL, NULL),
5089 GSF_XML_IN_NODE (FILL_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_2ND, NULL, NULL),
5090 GSF_XML_IN_NODE (FILL_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_2ND, NULL, NULL),
5091 GSF_XML_IN_NODE (FILL_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_2ND, NULL, NULL),
5092 GSF_XML_IN_NODE (FILL_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_2ND, NULL, NULL),
5093 GSF_XML_IN_NODE (FILL_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5094 GSF_XML_IN_NODE (FILL_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5095 GSF_XML_IN_NODE (STYLE, FONT_REF, XL_NS_DRAW, "fontRef", GSF_XML_NO_CONTENT, NULL, NULL),
5096 GSF_XML_IN_NODE (FONT_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_2ND, NULL, NULL),
5097 GSF_XML_IN_NODE (FONT_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_2ND, NULL, NULL),
5098 GSF_XML_IN_NODE (FONT_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_2ND, NULL, NULL),
5099 GSF_XML_IN_NODE (FONT_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_2ND, NULL, NULL),
5100 GSF_XML_IN_NODE (FONT_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5101 GSF_XML_IN_NODE (FONT_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5102 GSF_XML_IN_NODE (STYLE, LN_REF, XL_NS_DRAW, "lnRef", GSF_XML_NO_CONTENT, NULL, NULL),
5103 GSF_XML_IN_NODE (LN_REF, HSL_CLR, XL_NS_DRAW, "hslClr", GSF_XML_2ND, NULL, NULL),
5104 GSF_XML_IN_NODE (LN_REF, PRST_CLR, XL_NS_DRAW, "prstClr", GSF_XML_2ND, NULL, NULL),
5105 GSF_XML_IN_NODE (LN_REF, SCHEME_CLR, XL_NS_DRAW, "schemeClr", GSF_XML_2ND, NULL, NULL),
5106 GSF_XML_IN_NODE (LN_REF, SCRGB_CLR, XL_NS_DRAW, "scrgbClr", GSF_XML_2ND, NULL, NULL),
5107 GSF_XML_IN_NODE (LN_REF, SRGB_CLR, XL_NS_DRAW, "srgbClr", GSF_XML_2ND, NULL, NULL),
5108 GSF_XML_IN_NODE (LN_REF, SYS_CLR, XL_NS_DRAW, "sysClr", GSF_XML_2ND, NULL, NULL),
5109 GSF_XML_IN_NODE (SP_DEF, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
5110 GSF_XML_IN_NODE (OBJ_DEFAULTS, LN_DEF, XL_NS_DRAW, "lnDef", GSF_XML_NO_CONTENT, NULL, NULL),
5111 GSF_XML_IN_NODE (LN_DEF, BODY_PR, XL_NS_DRAW, "bodyPr", GSF_XML_NO_CONTENT, NULL, NULL),
5112 GSF_XML_IN_NODE (LN_DEF, LST_STYLE, XL_NS_DRAW, "lstStyle", GSF_XML_NO_CONTENT, NULL, NULL),
5113 GSF_XML_IN_NODE (LN_DEF, SP_PR, XL_NS_DRAW, "spPr", GSF_XML_NO_CONTENT, NULL, NULL),
5114 GSF_XML_IN_NODE (LN_DEF, STYLE, XL_NS_DRAW, "style", GSF_XML_2ND, NULL, NULL),
5115 GSF_XML_IN_NODE (LN_DEF, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
5116 GSF_XML_IN_NODE (OBJ_DEFAULTS, TX_DEF, XL_NS_DRAW, "txDef", GSF_XML_NO_CONTENT, NULL, NULL),
5117 GSF_XML_IN_NODE (OBJ_DEFAULTS, EXTLST, XL_NS_SS, "extLst", GSF_XML_2ND, NULL, NULL),
5118 GSF_XML_IN_NODE (THEME, EXTRA_COLOR_SCHEME, XL_NS_DRAW, "extraClrSchemeLst", GSF_XML_NO_CONTENT, NULL, NULL),
5120 GSF_XML_IN_NODE (THEME, EXTLST, XL_NS_DRAW, "extLst", GSF_XML_2ND, NULL, NULL),
5122 GSF_XML_IN_NODE_END
5125 /****************************************************************************/
5127 G_MODULE_EXPORT gboolean
5128 xlsx_file_probe (GOFileOpener const *fo, GsfInput *input, GOFileProbeLevel pl);
5130 gboolean
5131 xlsx_file_probe (G_GNUC_UNUSED GOFileOpener const *fo, GsfInput *input, G_GNUC_UNUSED GOFileProbeLevel pl)
5133 GsfInfile *zip;
5134 GsfInput *stream;
5135 gboolean res = FALSE;
5137 if (NULL != (zip = gsf_infile_zip_new (input, NULL))) {
5138 if (NULL != (stream = gsf_infile_child_by_vname (zip, "xl", "workbook.xml", NULL))) {
5139 g_object_unref (stream);
5140 res = TRUE;
5142 g_object_unref (zip);
5144 return res;
5147 static void
5148 xlsx_style_array_free (GPtrArray *styles)
5150 if (styles != NULL) {
5151 unsigned i = styles->len;
5152 GnmStyle *style;
5153 while (i-- > 0)
5154 if (NULL != (style = g_ptr_array_index (styles, i)))
5155 gnm_style_unref (style);
5157 g_ptr_array_free (styles, TRUE);
5161 #include "xlsx-read-docprops.c"
5163 G_MODULE_EXPORT void
5164 xlsx_file_open (GOFileOpener const *fo, GOIOContext *context,
5165 WorkbookView *wb_view, GsfInput *input);
5167 void
5168 xlsx_file_open (G_GNUC_UNUSED GOFileOpener const *fo, GOIOContext *context,
5169 WorkbookView *wb_view, GsfInput *input)
5171 XLSXReadState state;
5172 GnmLocale *locale;
5174 memset (&state, 0, sizeof (XLSXReadState));
5175 state.version = ECMA_376_2006;
5176 state.context = context;
5177 state.wb_view = wb_view;
5178 state.wb = wb_view_get_workbook (wb_view);
5179 state.sheet = NULL;
5180 state.run_attrs = NULL;
5181 state.rich_attrs = NULL;
5182 state.sst = g_array_new (FALSE, TRUE, sizeof (XLSXStr));
5183 state.shared_exprs = g_hash_table_new_full (g_str_hash, g_str_equal,
5184 (GDestroyNotify)g_free, (GDestroyNotify) gnm_expr_top_unref);
5185 state.cell_styles = g_hash_table_new_full (g_str_hash, g_str_equal,
5186 (GDestroyNotify)g_free, (GDestroyNotify) gnm_style_unref);
5187 state.num_fmts = g_hash_table_new_full (g_str_hash, g_str_equal,
5188 (GDestroyNotify)g_free, (GDestroyNotify) go_format_unref);
5189 state.date_fmt = xlsx_pivot_date_fmt ();
5190 state.convs = xlsx_conventions_new (FALSE);
5191 state.theme_colors_by_name = g_hash_table_new_full (g_str_hash, g_str_equal,
5192 (GDestroyNotify)g_free, NULL);
5193 /* fill in some default colors (when theme is absent */
5194 g_hash_table_replace (state.theme_colors_by_name, g_strdup ("lt1"), GUINT_TO_POINTER (GO_COLOR_WHITE));
5195 g_hash_table_replace (state.theme_colors_by_name, g_strdup ("dk1"), GUINT_TO_POINTER (GO_COLOR_BLACK));
5196 state.pivot.cache_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
5197 (GDestroyNotify)g_free, (GDestroyNotify) g_object_unref);
5198 state.zorder = g_hash_table_new (g_direct_hash, g_direct_equal);
5200 locale = gnm_push_C_locale ();
5202 if (NULL != (state.zip = gsf_infile_zip_new (input, NULL))) {
5203 /* optional */
5204 GsfInput *wb_part = gsf_open_pkg_open_rel_by_type (GSF_INPUT (state.zip),
5205 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", NULL);
5207 if (NULL != wb_part) {
5208 GsfInput *in;
5210 in = gsf_open_pkg_open_rel_by_type (wb_part,
5211 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", NULL);
5212 if (in != NULL) {
5213 start_update_progress (&state, in, _("Reading shared strings..."),
5214 0., 0.05);
5215 xlsx_parse_stream (&state, in, xlsx_shared_strings_dtd);
5216 end_update_progress (&state);
5219 in = gsf_open_pkg_open_rel_by_type (wb_part,
5220 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", NULL);
5221 if (in) {
5222 start_update_progress (&state, in, _("Reading theme..."),
5223 0.05, 0.1);
5224 xlsx_parse_stream (&state, in, xlsx_theme_dtd);
5225 end_update_progress (&state);
5228 in = gsf_open_pkg_open_rel_by_type (wb_part,
5229 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", NULL);
5230 if (in != NULL) {
5231 start_update_progress (&state, in, _("Reading styles..."), 0.1, 0.2);
5232 xlsx_parse_stream (&state, in, xlsx_styles_dtd);
5233 end_update_progress (&state);
5236 start_update_progress (&state, wb_part, _("Reading workbook..."),
5237 0.2, 0.3);
5238 xlsx_parse_stream (&state, wb_part, xlsx_workbook_dtd);
5239 /* end_update_progress (&state); moved into xlsx_wb_end */
5240 /* MW 20111121: why? If parsing fails, I don't think that will ever be called. */
5242 xlsx_read_docprops (&state);
5244 } else
5245 go_cmd_context_error_import (GO_CMD_CONTEXT (context),
5246 _("No workbook stream found."));
5248 g_object_unref (state.zip);
5251 gnm_pop_C_locale (locale);
5253 if (NULL != state.sst) {
5254 unsigned i = state.sst->len;
5255 XLSXStr *entry;
5256 while (i-- > 0) {
5257 entry = &g_array_index (state.sst, XLSXStr, i);
5258 go_string_unref (entry->str);
5259 go_format_unref (entry->markup);
5261 g_array_free (state.sst, TRUE);
5263 if (state.r_text) g_string_free (state.r_text, TRUE);
5264 if (state.rich_attrs) pango_attr_list_unref (state.rich_attrs);
5265 if (state.run_attrs) pango_attr_list_unref (state.run_attrs);
5266 g_hash_table_destroy (state.pivot.cache_by_id);
5267 xlsx_conventions_free (state.convs);
5268 go_format_unref (state.date_fmt);
5269 g_hash_table_destroy (state.num_fmts);
5270 g_hash_table_destroy (state.cell_styles);
5271 g_hash_table_destroy (state.shared_exprs);
5272 xlsx_style_array_free (state.fonts);
5273 xlsx_style_array_free (state.fills);
5274 xlsx_style_array_free (state.borders);
5275 xlsx_style_array_free (state.xfs);
5276 xlsx_style_array_free (state.style_xfs);
5277 xlsx_style_array_free (state.dxfs);
5278 xlsx_style_array_free (state.table_styles);
5279 g_hash_table_destroy (state.theme_colors_by_name);
5280 g_hash_table_destroy (state.zorder);
5281 value_release (state.val);
5282 if (state.texpr) gnm_expr_top_unref (state.texpr);
5283 if (state.comment) g_object_unref (state.comment);
5284 if (state.cur_style) g_object_unref (state.cur_style);
5285 if (state.style_accum) gnm_style_unref (state.style_accum);
5286 if (state.pending_rowcol_style) gnm_style_unref (state.pending_rowcol_style);
5287 if (state.border_color) style_color_unref (state.border_color);
5289 workbook_set_saveinfo (state.wb, GO_FILE_FL_AUTO,
5290 go_file_saver_for_id ((state.version == ECMA_376_2006) ?
5291 "Gnumeric_Excel:xlsx" :
5292 "Gnumeric_Excel:xlsx2"));
5295 /* TODO * TODO * TODO
5297 * IMPROVE
5298 * - column widths : Don't use hard coded font size
5299 * - share colours
5300 * - conditional formats
5301 * : other condition types
5302 * : check binary operators
5304 * ".xlam", "application/vnd.ms-excel.addin.macroEnabled.12" ,
5305 * ".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12" ,
5306 * ".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12" ,
5307 * ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ,
5308 * ".xltm", "application/vnd.ms-excel.template.macroEnabled.12" ,
5309 * ".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"