1 /* vm: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * excel-xml-read.c : Read MS Excel 2003 SpreadsheetML
5 *
6 * Copyright (C) 2003-2008 Jody Goldberg (jody@gnome.org)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23 #include <gnumeric-config.h>
24 #include <gnumeric.h>
25 #include <xml-io-version.h>
26 #include <sheet-view.h>
27 #include <sheet-style.h>
28 #include <sheet-merge.h>
29 #include <sheet-filter.h>
30 #include <sheet.h>
31 #include <ranges.h>
32 #include <style.h>
33 #include <style-border.h>
34 #include <style-color.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 <validation.h>
41 #include <value.h>
42 #include <selection.h>
43 #include <command-context.h>
44 #include <workbook-view.h>
45 #include <workbook.h>
46 #include <gutils.h>
47 #include <goffice/goffice.h>
48
49 #include <gsf/gsf-libxml.h>
50 #include <gsf/gsf-input.h>
51 #include <gsf/gsf-utils.h>
52 #include <gmodule.h>
53 #include <glib/gi18n-lib.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <errno.h>
57
58 /*****************************************************************************/
59
60 /* A fake value of the right type, different from all the real enum values. */
61 #define VALUE_FAKE_DATETIME ((GnmValueType)42)
62
63 typedef struct {
64 GnumericXMLVersion version;
65 GOIOContext *context; /* The IOcontext managing things */
66 WorkbookView *wb_view; /* View for the new workbook */
67 Workbook *wb; /* The new workbook */
68 Sheet *sheet; /* The current sheet */
69 GnmCellPos pos;
70 int merge_across;
71 GnmValueType val_type;
72 GnmExprTop const*texpr;
73 GnmRange array_range;
74 char *style_name;
75 GnmStyle *style;
76 GnmStyle *def_style;
77 GHashTable *style_hash;
78 GsfDocMetaData *metadata; /* Document Properties */
79 } ExcelXMLReadState;
80
81 enum {
82 XL_NS_SS,
83 XL_NS_O,
84 XL_NS_XL,
85 XL_NS_XSI,
86 XL_NS_C,
87 XL_NS_HTML
88 };
89
90 /****************************************************************************/
91
92 static gboolean xl_xml_warning (GsfXMLIn *xin, char const *fmt, ...)
93 G_GNUC_PRINTF (2, 3);
94
95 static gboolean
xl_xml_warning(GsfXMLIn * xin,char const * fmt,...)96 xl_xml_warning (GsfXMLIn *xin, char const *fmt, ...)
97 {
98 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
99 char *msg;
100 va_list args;
101
102 va_start (args, fmt);
103 msg = g_strdup_vprintf (fmt, args);
104 va_end (args);
105
106 if (IS_SHEET (state->sheet)) {
107 char *tmp;
108 if (state->pos.col >= 0 && state->pos.row >= 0)
109 tmp = g_strdup_printf ("%s!%s : %s",
110 state->sheet->name_quoted,
111 cellpos_as_string (&state->pos), msg);
112 else
113 tmp = g_strdup_printf ("%s : %s",
114 state->sheet->name_quoted, msg);
115 g_free (msg);
116 msg = tmp;
117 }
118
119 go_io_warning (state->context, "%s", msg);
120 g_warning ("%s", msg);
121 g_free (msg);
122
123 return FALSE; /* convenience */
124 }
125 static void
unknown_attr(GsfXMLIn * xin,xmlChar const * const * attrs,char const * name)126 unknown_attr (GsfXMLIn *xin,
127 xmlChar const * const *attrs, char const *name)
128 {
129 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
130
131 g_return_if_fail (attrs != NULL);
132
133 if (state->version == GNM_XML_LATEST)
134 go_io_warning (state->context,
135 _("Unexpected attribute %s::%s == '%s'."),
136 name, attrs[0], attrs[1]);
137 }
138
139 typedef struct {
140 char const * const name;
141 int val;
142 } EnumVal;
143
144 static gboolean
attr_enum(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,EnumVal const * enums,int * res)145 attr_enum (GsfXMLIn *xin, xmlChar const * const *attrs,
146 int ns_id, char const *name, EnumVal const *enums, int *res)
147 {
148 g_return_val_if_fail (attrs != NULL, FALSE);
149 g_return_val_if_fail (attrs[0] != NULL, FALSE);
150 g_return_val_if_fail (attrs[1] != NULL, FALSE);
151
152 if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
153 return FALSE;
154
155 for (; enums->name != NULL ; enums++)
156 if (!strcmp (enums->name, attrs[1])) {
157 *res = enums->val;
158 return TRUE;
159 }
160 return xl_xml_warning (xin, "Invalid attribute '%s', unknown enum value '%s'",
161 name, attrs[1]);
162 }
163
164 static gboolean
attr_bool(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,gboolean * res)165 attr_bool (GsfXMLIn *xin, xmlChar const * const *attrs,
166 int ns_id, char const *name, gboolean *res)
167 {
168 g_return_val_if_fail (attrs != NULL, FALSE);
169 g_return_val_if_fail (attrs[0] != NULL, FALSE);
170 g_return_val_if_fail (attrs[1] != NULL, FALSE);
171
172 if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
173 return FALSE;
174 *res = g_ascii_strcasecmp ((gchar *)attrs[1], "false") && strcmp (attrs[1], "0");
175
176 return TRUE;
177 }
178
179 static gboolean
attr_int(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,int * res)180 attr_int (GsfXMLIn *xin, xmlChar const * const *attrs,
181 int ns_id, char const *name, int *res)
182 {
183 char *end;
184 int tmp;
185
186 g_return_val_if_fail (attrs != NULL, FALSE);
187 g_return_val_if_fail (attrs[0] != NULL, FALSE);
188 g_return_val_if_fail (attrs[1] != NULL, FALSE);
189
190 if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
191 return FALSE;
192
193 errno = 0;
194 tmp = strtol ((gchar *)attrs[1], &end, 10);
195 if (errno == ERANGE)
196 return xl_xml_warning (xin, "Invalid attribute '%s', integer '%s' is out of range",
197 name, attrs[1]);
198 if (*end)
199 return xl_xml_warning (xin, "Invalid attribute '%s', expected integer, received '%s'",
200 name, attrs[1]);
201
202 *res = tmp;
203 return TRUE;
204 }
205
206 static gboolean
attr_float(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name,gnm_float * res)207 attr_float (GsfXMLIn *xin, xmlChar const * const *attrs,
208 int ns_id, char const *name, gnm_float *res)
209 {
210 char *end;
211 double tmp;
212
213 g_return_val_if_fail (attrs != NULL, FALSE);
214 g_return_val_if_fail (attrs[0] != NULL, FALSE);
215 g_return_val_if_fail (attrs[1] != NULL, FALSE);
216
217 if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
218 return FALSE;
219
220 tmp = gnm_strto ((gchar *)attrs[1], &end);
221 if (*end)
222 return xl_xml_warning (xin, "Invalid attribute '%s', expected number, received '%s'",
223 name, attrs[1]);
224 *res = tmp;
225 return TRUE;
226 }
227
228 static GnmColor *
parse_color(GsfXMLIn * xin,xmlChar const * str,char const * name)229 parse_color (GsfXMLIn *xin, xmlChar const *str, char const *name)
230 {
231 guint r, g, b;
232
233 g_return_val_if_fail (str != NULL, NULL);
234
235 if (3 == sscanf (str, "#%2x%2x%2x", &r, &g, &b))
236 return gnm_color_new_rgb8 (r, g, b);
237
238 xl_xml_warning (xin, "Invalid attribute '%s', expected color, received '%s'",
239 name, str);
240 return NULL;
241 }
242
243 static GnmColor *
attr_color(GsfXMLIn * xin,xmlChar const * const * attrs,int ns_id,char const * name)244 attr_color (GsfXMLIn *xin, xmlChar const * const *attrs,
245 int ns_id, char const *name)
246 {
247 g_return_val_if_fail (attrs != NULL, NULL);
248 g_return_val_if_fail (attrs[0] != NULL, NULL);
249
250 if (!gsf_xml_in_namecmp (xin, attrs[0], ns_id, name))
251 return NULL;
252 return parse_color (xin, attrs[1], name);
253 }
254
255 static GnmExprTop const *
xl_xml_parse_expr(GsfXMLIn * xin,xmlChar const * expr_str,GnmParsePos const * pp)256 xl_xml_parse_expr (GsfXMLIn *xin, xmlChar const *expr_str,
257 GnmParsePos const *pp)
258 {
259 GnmExprTop const *texpr;
260 GnmParseError err;
261 if (*expr_str != '=') {
262 xl_xml_warning (xin, "Invalid formula '%s' does not begin with '='", expr_str);
263 return NULL;
264 }
265 /* Odd, some time IF and CHOOSE show up with leading spaces ??
266 * = IF(....
267 * = CHOOSE(...
268 * I wonder if it is related to some of the funky old
269 * optimizations in * xls ? */
270 while (' ' == *(++expr_str))
271 ;
272 texpr = gnm_expr_parse_str (expr_str, pp,
273 GNM_EXPR_PARSE_DEFAULT, gnm_conventions_xls_r1c1,
274 parse_error_init (&err));
275 if (NULL == texpr)
276 xl_xml_warning (xin, "'%s' %s", expr_str, err.err->message);
277 parse_error_free (&err);
278
279 return texpr;
280 }
281
282 static void
xl_xml_doc_prop_start(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)283 xl_xml_doc_prop_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
284 {
285 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
286 state->metadata = gsf_doc_meta_data_new ();
287 }
288
289 static void
xl_xml_doc_prop_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)290 xl_xml_doc_prop_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
291 {
292 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
293 go_doc_set_meta_data (GO_DOC (state->wb), state->metadata);
294 g_object_unref (state->metadata);
295 state->metadata = NULL;
296 }
297
298 static void
xl_xml_read_prop_type(GsfXMLIn * xin,GType g_type)299 xl_xml_read_prop_type (GsfXMLIn *xin, GType g_type)
300 {
301 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
302 GValue *res = g_new0 (GValue, 1);
303 if (gsf_xml_gvalue_from_str (res, g_type, xin->content->str))
304 gsf_doc_meta_data_insert
305 (state->metadata,
306 g_strdup (xin->node->user_data.v_str), res);
307 else
308 g_free (res);
309 }
310
311 static void
xl_xml_read_prop(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)312 xl_xml_read_prop (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
313 {
314 xl_xml_read_prop_type (xin, G_TYPE_STRING);
315 }
316
317 static void
xl_xml_read_prop_dt(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)318 xl_xml_read_prop_dt (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
319 {
320 xl_xml_read_prop_type (xin, GSF_TIMESTAMP_TYPE);
321 }
322
323 static void
xl_xml_read_keywords(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)324 xl_xml_read_keywords (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
325 {
326 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
327 gchar **strs, **orig_strs;
328 GsfDocPropVector *keywords;
329 GValue v = G_VALUE_INIT;
330 int count = 0;
331
332 if (strlen (xin->content->str) == 0)
333 return;
334
335 orig_strs = strs = g_strsplit (xin->content->str, " ", 0);
336 keywords = gsf_docprop_vector_new ();
337
338 while (strs != NULL && *strs != NULL && strlen (*strs) > 0) {
339 g_value_init (&v, G_TYPE_STRING);
340 g_value_set_string (&v, *strs);
341 gsf_docprop_vector_append (keywords, &v);
342 g_value_unset (&v);
343 count ++;
344 strs++;
345 }
346 g_strfreev(orig_strs);
347
348 if (count > 0) {
349 GValue *val = g_new0 (GValue, 1);
350 g_value_init (val, GSF_DOCPROP_VECTOR_TYPE);
351 g_value_set_object (val, keywords);
352 gsf_doc_meta_data_insert (state->metadata,
353 g_strdup (xin->node->user_data.v_str), val);
354 }
355 g_object_unref (keywords);
356 }
357
358 static void
xl_xml_table_start(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)359 xl_xml_table_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
360 {
361 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
362 state->pos.col = 0;
363 }
364
365 static void
xl_xml_col_start(GsfXMLIn * xin,xmlChar const ** attrs)366 xl_xml_col_start (GsfXMLIn *xin, xmlChar const **attrs)
367 {
368 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
369 int tmp, span = 1;
370 gboolean auto_fit = TRUE, hidden = FALSE;
371 gnm_float width = -1;
372 GnmStyle *style = NULL;
373
374 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
375 if (attr_int (xin, attrs, XL_NS_SS, "Index", &tmp)) {
376 if (tmp > 0)
377 state->pos.col = tmp - 1;
378 } else if (attr_int (xin, attrs, XL_NS_SS, "Span", &tmp)) {
379 /* NOTE : span is odd. It seems to apply as col+span
380 * rather than col+span-1 that is used for rows which
381 * is the more logical (to me) arrangement) */
382 if (tmp > 0)
383 span = tmp + 1;
384 } else if (attr_bool (xin, attrs, XL_NS_SS, "AutoFitWidth", &auto_fit))
385 ;
386 else if (attr_bool (xin, attrs, XL_NS_SS, "Hidden", &hidden))
387 ;
388 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "StyleID"))
389 style = g_hash_table_lookup (state->style_hash, attrs[1]);
390 else if (attr_float (xin, attrs, XL_NS_SS, "Width", &width))
391 ;
392 else
393 unknown_attr (xin, attrs, "Column");
394
395 if (NULL != style) {
396 GnmRange r;
397 r.start.col = state->pos.col;
398 r.end.col = state->pos.col + span - 1;
399 r.start.row = 0;
400 r.end.row = gnm_sheet_get_max_rows (state->sheet) - 1;
401 gnm_style_ref (style);
402 sheet_style_set_range (state->sheet, &r, style);
403 }
404 if (width > 0.)
405 for (tmp = 0 ; tmp < span ; tmp++)
406 sheet_col_set_size_pts (state->sheet,
407 state->pos.col + tmp, width, !auto_fit);
408 if (hidden)
409 colrow_set_visibility (state->sheet, TRUE, FALSE,
410 state->pos.col, state->pos.col+span-1);
411
412 state->pos.col += span;
413 }
414
415 static void
xl_xml_row_start(GsfXMLIn * xin,xmlChar const ** attrs)416 xl_xml_row_start (GsfXMLIn *xin, xmlChar const **attrs)
417 {
418 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
419 int tmp, span = 1;
420 gboolean auto_fit = TRUE, hidden = FALSE;
421 gnm_float height = -1;
422 GnmStyle *style = NULL;
423
424 state->pos.col = 0;
425 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
426 if (attr_int (xin, attrs, XL_NS_SS, "Index", &tmp)) {
427 if (tmp > 0)
428 state->pos.row = tmp - 1;
429 } else if (attr_int (xin, attrs, XL_NS_SS, "Span", &tmp)) {
430 if (tmp > 0)
431 span = tmp;
432 } else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "StyleID"))
433 style = g_hash_table_lookup (state->style_hash, attrs[1]);
434 else if (attr_bool (xin, attrs, XL_NS_SS, "AutoFitHeight", &auto_fit))
435 ;
436 else if (attr_bool (xin, attrs, XL_NS_SS, "Hidden", &hidden))
437 ;
438 else if (attr_float (xin, attrs, XL_NS_SS, "Height", &height))
439 ;
440 else
441 unknown_attr (xin, attrs, "Row");
442
443 if (height >= 0.)
444 for (tmp = 0 ; tmp < span ; tmp++)
445 sheet_row_set_size_pts (state->sheet, state->pos.row+tmp, height, !auto_fit);
446 if (hidden)
447 colrow_set_visibility (state->sheet, FALSE, FALSE,
448 state->pos.row, state->pos.row+span-1);
449
450 if (NULL != style) {
451 GnmRange r;
452 r.start.row = state->pos.row;
453 r.end.row = state->pos.row + span - 1;
454 r.start.col = 0;
455 r.end.col = gnm_sheet_get_max_cols (state->sheet) - 1;
456 gnm_style_ref (style);
457 sheet_style_set_range (state->sheet, &r, style);
458 }
459 }
460 static void
xl_xml_row_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)461 xl_xml_row_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
462 {
463 ((ExcelXMLReadState *)xin->user_state)->pos.row++;
464 }
465 static void
xl_xml_cell_start(GsfXMLIn * xin,xmlChar const ** attrs)466 xl_xml_cell_start (GsfXMLIn *xin, xmlChar const **attrs)
467 {
468 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
469 GnmStyle *style = NULL;
470 int across = 0, down = 0, tmp;
471 GnmParsePos pp;
472
473 parse_pos_init (&pp, NULL, state->sheet,
474 state->pos.col, state->pos.row);
475 state->array_range.start.col = -1; /* poison it */
476 state->val_type = VALUE_STRING;
477 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
478 if (attr_int (xin, attrs, XL_NS_SS, "Index", &tmp)) {
479 if (tmp > 0)
480 state->pos.col = tmp -1;
481 } else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Formula")) {
482 GnmExprTop const *texpr = xl_xml_parse_expr (xin, attrs[1], &pp);
483 if (NULL != texpr) {
484 if (NULL != state->texpr)
485 gnm_expr_top_unref (state->texpr);
486 state->texpr = texpr;
487 }
488 } else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "ArrayRange")) {
489 GnmRangeRef rr;
490 xmlChar const *end = rangeref_parse (&rr, attrs[1], &pp, gnm_conventions_xls_r1c1);
491 if (end != attrs[1] && *end == '\0')
492 range_init_rangeref (&state->array_range, &rr);
493 } else if (attr_int (xin, attrs, XL_NS_SS, "MergeAcross", &across))
494 ;
495 else if (attr_int (xin, attrs, XL_NS_SS, "MergeDown", &down))
496 ;
497 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "StyleID"))
498 style = g_hash_table_lookup (state->style_hash, attrs[1]);
499 else
500 unknown_attr (xin, attrs, "Cell");
501
502 if (NULL != style) {
503 gnm_style_ref (style);
504 if (across > 0 || down > 0) {
505 GnmRange r;
506 r.start = r.end = state->pos;
507 r.end.col += across;
508 r.end.row += down;
509 gnm_sheet_merge_add (state->sheet, &r, FALSE,
510 GO_CMD_CONTEXT (state->context));
511 sheet_style_set_range (state->sheet, &r, style);
512 } else
513 sheet_style_set_pos (state->sheet,
514 state->pos.col, state->pos.row, style);
515 }
516 state->merge_across = across;
517 }
518 static void
xl_xml_cell_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)519 xl_xml_cell_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
520 {
521 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
522 state->pos.col += (1 + state->merge_across);
523 }
524 static void
xl_xml_data_start(GsfXMLIn * xin,xmlChar const ** attrs)525 xl_xml_data_start (GsfXMLIn *xin, xmlChar const **attrs)
526 {
527 static EnumVal const val_types[] = {
528 { "String", VALUE_STRING },
529 { "Number", VALUE_FLOAT },
530 { "Boolean", VALUE_BOOLEAN },
531 { "Error", VALUE_ERROR },
532 { "DateTime", VALUE_FAKE_DATETIME },
533 { NULL, 0 }
534 };
535 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
536 int type;
537
538 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
539 if (attr_enum (xin, attrs, XL_NS_SS, "Type", val_types, &type))
540 state->val_type = type;
541 else
542 unknown_attr (xin, attrs, "CellData");
543 }
544
545 static void
xl_xml_data_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)546 xl_xml_data_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
547 {
548 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
549 GnmCell *cell = sheet_cell_fetch (state->sheet, state->pos.col, state->pos.row);
550 GnmValue *v;
551
552 if (state->val_type == VALUE_FAKE_DATETIME) {
553 GDate date;
554 unsigned y, mo, d, h, mi;
555 double s;
556 if (6 == sscanf (xin->content->str, "%u-%u-%uT%u:%u:%lg", &y, &mo, &d, &h, &mi, &s)) {
557 g_date_clear (&date, 1);
558 g_date_set_dmy (&date, d, mo, y);
559 if (g_date_valid (&date)) {
560 unsigned d_serial = go_date_g_to_serial (&date,
561 workbook_date_conv (state->wb));
562 v = value_new_float (d_serial + h/24. + mi/(24.*60.) + s/(24.*60.*60.));
563 } else
564 v = value_new_string (xin->content->str);
565 } else
566 v = value_new_string (xin->content->str);
567 } else if (state->val_type == VALUE_FLOAT) {
568 char *end;
569 v = value_new_float (gnm_strto (xin->content->str, &end));
570 if (*end)
571 xl_xml_warning
572 (xin, _("Invalid content of ss:data "
573 "element, expected number, "
574 "received '%s'"),
575 xin->content->str);
576 } else
577 v = value_new_from_string (state->val_type, xin->content->str,
578 NULL, FALSE);
579 if (NULL != state->texpr) {
580 if (NULL != v)
581 gnm_cell_set_expr_and_value (cell, state->texpr, v, TRUE);
582 else
583 gnm_cell_set_expr (cell, state->texpr);
584 gnm_expr_top_unref (state->texpr);
585 state->texpr = NULL;
586 } else if (NULL != v)
587 gnm_cell_set_value (cell, v);
588 else {
589 gnm_cell_set_text (cell, xin->content->str);
590 xl_xml_warning
591 (xin, _("Invalid content of ss:data "
592 "element, received '%s'"),
593 xin->content->str);
594 }
595 }
596
597 static void
xl_xml_font(GsfXMLIn * xin,xmlChar const ** attrs)598 xl_xml_font (GsfXMLIn *xin, xmlChar const **attrs)
599 {
600 static EnumVal const underlines[] = {
601 { "None", UNDERLINE_NONE },
602 { "Single", UNDERLINE_SINGLE },
603 { "SingleAccounting", UNDERLINE_SINGLE_LOW },
604 { "Double", UNDERLINE_DOUBLE },
605 { "DoubleAccounting", UNDERLINE_DOUBLE_LOW },
606 { NULL, 0 }
607 };
608 static EnumVal const scripts[] = {
609 { "Superscript", GO_FONT_SCRIPT_SUPER },
610 { "Subscript", GO_FONT_SCRIPT_SUB },
611 { "None", GO_FONT_SCRIPT_STANDARD },
612 { NULL, 0 }
613 };
614 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
615 GnmColor *color;
616 gboolean b_tmp;
617 int i_tmp;
618 gnm_float tmp;
619
620 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
621 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Family"))
622 ;
623 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "FontName"))
624 ;
625 else if (attr_float (xin, attrs, XL_NS_SS, "Size", &tmp))
626 gnm_style_set_font_size (state->style, tmp);
627 else if (attr_bool (xin, attrs, XL_NS_SS, "Bold", &b_tmp))
628 gnm_style_set_font_bold (state->style, b_tmp);
629 else if (attr_bool (xin, attrs, XL_NS_SS, "Italic", &b_tmp))
630 gnm_style_set_font_italic (state->style, b_tmp);
631 else if (attr_bool (xin, attrs, XL_NS_SS, "StrikeThrough", &b_tmp))
632 gnm_style_set_font_strike (state->style, b_tmp);
633 else if (attr_enum (xin, attrs, XL_NS_SS, "Underline", underlines, &i_tmp))
634 gnm_style_set_font_uline (state->style, i_tmp);
635 else if (attr_enum (xin, attrs, XL_NS_SS, "VerticalAlign", scripts, &i_tmp))
636 gnm_style_set_font_script (state->style, i_tmp);
637 else if ((color = attr_color (xin, attrs, XL_NS_SS, "Color")))
638 gnm_style_set_font_color (state->style, color);
639 else
640 unknown_attr (xin, attrs, "Style::Font");
641 }
642
643 static void
xl_xml_alignment(GsfXMLIn * xin,xmlChar const ** attrs)644 xl_xml_alignment (GsfXMLIn *xin, xmlChar const **attrs)
645 {
646 static EnumVal const valignments [] = {
647 { "Bottom", GNM_VALIGN_BOTTOM },
648 { "Center", GNM_VALIGN_CENTER },
649 { "Distributed", GNM_VALIGN_DISTRIBUTED },
650 { "Justify", GNM_VALIGN_JUSTIFY },
651 { "Top", GNM_VALIGN_TOP },
652 { NULL, 0 }
653 };
654 static EnumVal const halignments [] = {
655 { "Center", GNM_HALIGN_CENTER },
656 { "CenterAcrossSelection", GNM_HALIGN_CENTER_ACROSS_SELECTION },
657 { "Distributed", GNM_HALIGN_DISTRIBUTED },
658 { "Fill", GNM_HALIGN_FILL },
659 { "Justify", GNM_HALIGN_JUSTIFY },
660 { "Left", GNM_HALIGN_LEFT },
661 { "Right", GNM_HALIGN_RIGHT },
662
663 { NULL, 0 }
664 };
665 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
666 gboolean b_tmp;
667 int i_tmp;
668
669 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
670 if (attr_int (xin, attrs, XL_NS_SS, "Rotate", &i_tmp))
671 gnm_style_set_rotation (state->style, i_tmp);
672 else if (attr_bool (xin, attrs, XL_NS_SS, "WrapText", &b_tmp))
673 gnm_style_set_wrap_text (state->style, b_tmp);
674 else if (attr_enum (xin, attrs, XL_NS_SS, "Vertical", valignments, &i_tmp))
675 gnm_style_set_align_v (state->style, i_tmp);
676 else if (attr_enum (xin, attrs, XL_NS_SS, "Horizontal", halignments, &i_tmp))
677 gnm_style_set_align_h (state->style, i_tmp);
678 else if (attr_int (xin, attrs, XL_NS_SS, "Indent", &i_tmp))
679 gnm_style_set_indent (state->style, i_tmp);
680 }
681
682 static void
xl_xml_border(GsfXMLIn * xin,xmlChar const ** attrs)683 xl_xml_border (GsfXMLIn *xin, xmlChar const **attrs)
684 {
685 static EnumVal const sides[] = {
686 { "Top", GNM_STYLE_BORDER_TOP },
687 { "Bottom", GNM_STYLE_BORDER_BOTTOM },
688 { "Right", GNM_STYLE_BORDER_RIGHT },
689 { "Left", GNM_STYLE_BORDER_LEFT },
690 { "DiagonalLeft", GNM_STYLE_BORDER_REV_DIAG },
691 { "DiagonalRight", GNM_STYLE_BORDER_DIAG },
692 { NULL, 0 }
693 };
694 static EnumVal const line_styles[] = {
695 { "Continuous", GNM_STYLE_BORDER_HAIR }, /* 1 2 3 */
696 { "Dash", GNM_STYLE_BORDER_DASHED }, /* 1 2 */
697 { "DashDot", GNM_STYLE_BORDER_DASH_DOT }, /* 1 2 */
698 { "DashDotDot", GNM_STYLE_BORDER_DASH_DOT_DOT }, /* 1 2 */
699 { "Dot", GNM_STYLE_BORDER_DOTTED }, /* 1 */
700 { "Double", GNM_STYLE_BORDER_DOUBLE }, /* 3 */
701 { "SlantDashDot", GNM_STYLE_BORDER_SLANTED_DASH_DOT },/* 2 */
702 { NULL, 0 }
703 };
704 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
705 GnmStyleBorderLocation location = GNM_STYLE_BORDER_EDGE_MAX;
706 GnmStyleBorderType line_type = GNM_STYLE_BORDER_MAX;
707 GnmBorder *border;
708 GnmColor *color = NULL, *new_color;
709 int weight = 1, tmp;
710
711 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
712 if (attr_enum (xin, attrs, XL_NS_SS, "Position", sides, &tmp))
713 location = tmp;
714 else if (attr_enum (xin, attrs, XL_NS_SS, "LineStyle", line_styles, &tmp))
715 line_type = tmp;
716 else if (attr_int (xin, attrs, XL_NS_SS, "Weight", &weight))
717 ;
718 else if ((new_color = attr_color (xin, attrs, XL_NS_SS, "Color"))) {
719 style_color_unref (color);
720 color = new_color;
721 } else
722 unknown_attr (xin, attrs, "Style::Border");
723
724 switch (line_type) {
725 default:
726 break;
727 case GNM_STYLE_BORDER_HAIR:
728 if (weight == 2)
729 line_type = GNM_STYLE_BORDER_THIN;
730 else if (weight >= 3)
731 line_type = GNM_STYLE_BORDER_THICK;
732 break;
733 case GNM_STYLE_BORDER_DASHED:
734 if (weight >= 2)
735 line_type = GNM_STYLE_BORDER_MEDIUM_DASH;
736 break;
737 case GNM_STYLE_BORDER_DASH_DOT:
738 if (weight >= 2)
739 line_type = GNM_STYLE_BORDER_MEDIUM_DASH_DOT;
740 break;
741 case GNM_STYLE_BORDER_DASH_DOT_DOT:
742 if (weight >= 2)
743 line_type = GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT;
744 break;
745 }
746
747 if (color != NULL &&
748 location != GNM_STYLE_BORDER_EDGE_MAX &&
749 line_type != GNM_STYLE_BORDER_MAX) {
750 border = gnm_style_border_fetch (line_type,
751 color, gnm_style_border_get_orientation (location));
752 gnm_style_set_border (state->style,
753 GNM_STYLE_BORDER_LOCATION_TO_STYLE_ELEMENT (location),
754 border);
755 } else if (color)
756 style_color_unref (color);
757 }
758
759 static void
xl_xml_num_interior(GsfXMLIn * xin,xmlChar const ** attrs)760 xl_xml_num_interior (GsfXMLIn *xin, xmlChar const **attrs)
761 {
762 static EnumVal const patterns[] = {
763 { "Solid", 1 },
764 { "Gray75", 2 },
765 { "Gray50", 3 },
766 { "Gray25", 4 },
767 { "Gray125", 5 },
768 { "Gray0625", 6 },
769 { "HorzStripe", 7 },
770 { "VertStripe", 8 },
771 { "ReverseDiagStripe", 9 },
772 { "DiagStripe", 10 },
773 { "DiagCross", 11 },
774 { "ThickDiagCross", 12 },
775 { "ThinHorzStripe", 13 },
776 { "ThinVertStripe", 14 },
777 { "ThinReverseDiagStripe", 15 },
778 { "ThinDiagStripe", 16 },
779 { "ThinHorzCross", 17 },
780 { "ThinDiagCross", 18 },
781 { NULL, 0 }
782 };
783 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
784 GnmColor *color;
785 int tmp;
786
787 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
788 if ((color = attr_color (xin, attrs, XL_NS_SS, "Color")))
789 gnm_style_set_back_color (state->style, color);
790 else if (attr_enum (xin, attrs, XL_NS_SS, "Pattern", patterns, &tmp))
791 gnm_style_set_pattern (state->style, tmp);
792 else if ((color = attr_color (xin, attrs, XL_NS_SS, "PatternColor")))
793 gnm_style_set_pattern_color (state->style, color);
794 else
795 unknown_attr (xin, attrs, "Style::Interior");
796 }
797
798 static void
xl_xml_num_fmt(GsfXMLIn * xin,xmlChar const ** attrs)799 xl_xml_num_fmt (GsfXMLIn *xin, xmlChar const **attrs)
800 {
801 static struct {
802 char const *name;
803 GOFormatMagic id;
804 } named_magic_formats [] = {
805 { "General Date", GO_FORMAT_MAGIC_SHORT_DATETIME },
806 { "Long Date", GO_FORMAT_MAGIC_LONG_DATE },
807 { "Medium Date", GO_FORMAT_MAGIC_MEDIUM_DATE },
808 { "Short Date", GO_FORMAT_MAGIC_SHORT_DATE },
809 { "Long Time", GO_FORMAT_MAGIC_LONG_TIME },
810 { "Medium Time", GO_FORMAT_MAGIC_MEDIUM_TIME },
811 { "Short Time", GO_FORMAT_MAGIC_SHORT_TIME },
812 { NULL, 0 }
813 };
814 static struct {
815 char const *name;
816 char const *format;
817 } named_formats [] = {
818 { "General Number", "General" },
819 { "Currency", "$#,##0.00_);[Red](#,##0.00)" },
820 { "Euro Currency", "[$EUR-2]#,##0.00_);[Red](#,##0.00)" },
821 { "Fixed", "0.00" },
822 { "Standard", "#,##0.00" }, /* number, 2dig, +sep */
823 { "Percent", "0.00%" }, /* std percent */
824 { "Scientific", "0.00E+00" }, /* std scientific */
825 { "Yes/No", "\"Yes\";\"Yes\";\"No\"" },
826 { "True/False", "\"True\";\"True\";\"False\"" },
827 { "On/Off", "\"On\";\"On\";\"Off\"" },
828 { NULL, NULL }
829 };
830 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
831 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
832 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Format")) {
833 GOFormat *fmt = NULL;
834 int i;
835
836 for (i = 0 ; named_formats[i].name ; i++)
837 if (0 == strcmp (attrs[1], named_formats[i].name))
838 fmt = go_format_new_from_XL (named_formats[i].format);
839
840 if (NULL == fmt)
841 for (i = 0 ; named_magic_formats[i].name ; i++)
842 if (0 == strcmp (attrs[1], named_magic_formats[i].name))
843 fmt = go_format_new_magic (named_magic_formats[i].id);
844
845 if (NULL == fmt)
846 fmt = go_format_new_from_XL (attrs[1]);
847 gnm_style_set_format (state->style, fmt);
848 go_format_unref (fmt);
849 } else
850 unknown_attr (xin, attrs, "Style::NumberFormat");
851 }
852
853 static void
xl_xml_style_start(GsfXMLIn * xin,xmlChar const ** attrs)854 xl_xml_style_start (GsfXMLIn *xin, xmlChar const **attrs)
855 {
856 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
857 char const *id = NULL;
858 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
859 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "ID"))
860 id = attrs[1];
861 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Name"))
862 ; /* does anything use this ? */
863 else
864 unknown_attr (xin, attrs, "Style");
865
866 if (id == NULL)
867 return;
868
869 g_return_if_fail (state->style == NULL);
870
871 state->style = (state->def_style != NULL)
872 ? gnm_style_dup (state->def_style)
873 : gnm_style_new_default ();
874 if (!strcmp (id, "Default"))
875 state->def_style = state->style;
876 g_hash_table_replace (state->style_hash, g_strdup (id), state->style);
877 }
878
879 static void
xl_xml_style_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)880 xl_xml_style_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
881 {
882 ((ExcelXMLReadState *)xin->user_state)->style = NULL;
883 }
884
885 static void
xl_xml_named_range(GsfXMLIn * xin,xmlChar const ** attrs)886 xl_xml_named_range (GsfXMLIn *xin, xmlChar const **attrs)
887 {
888 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
889 char const *name = NULL;
890 char const *expr_str = NULL;
891
892 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
893 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Name"))
894 name = attrs[1];
895 else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "RefersTo"))
896 expr_str = attrs[1];
897
898 if (NULL != name && NULL != expr_str) {
899 GnmParsePos pp;
900 GnmExprTop const *texpr = xl_xml_parse_expr (xin, expr_str,
901 parse_pos_init (&pp, state->wb, NULL, 0, 0));
902 g_warning ("%s = %s", name, expr_str);
903 if (NULL != texpr)
904 expr_name_add (&pp, name, texpr, NULL, TRUE, NULL);
905 }
906 }
907
908 static void
xl_xml_sheet_start(GsfXMLIn * xin,xmlChar const ** attrs)909 xl_xml_sheet_start (GsfXMLIn *xin, xmlChar const **attrs)
910 {
911 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
912 char const *name = NULL;
913
914 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
915 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "Name"))
916 name = attrs[1];
917 else
918 unknown_attr (xin, attrs, "Worksheet");
919
920 if (name != NULL){
921 g_return_if_fail (state->sheet == NULL);
922 state->sheet = workbook_sheet_by_name (state->wb, name);
923 if (state->sheet == NULL) {
924 state->sheet = sheet_new (state->wb, name,
925 16384, 1048576); /* FIXME */
926 workbook_sheet_attach (state->wb, state->sheet);
927 }
928
929 /* Flag a respan here in case nothing else does */
930 sheet_flag_recompute_spans (state->sheet);
931 state->pos.col = state->pos.row = 0;
932 }
933 }
934
935 static void
xl_xml_sheet_end(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)936 xl_xml_sheet_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
937 {
938 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
939
940 g_return_if_fail (state->sheet != NULL);
941
942 state->sheet = NULL;
943 }
944
945 static void
xl_xml_pane(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)946 xl_xml_pane (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
947 {
948 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
949 state->pos.col = 0;
950 state->pos.row = 0;
951 }
952 static void
xl_xml_editpos_row(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)953 xl_xml_editpos_row (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
954 {
955 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
956 char *end;
957 int tmp;
958 errno = 0;
959 tmp = strtol (xin->content->str, &end, 10);
960 if (errno != ERANGE && *end == '\0')
961 state->pos.row = tmp;
962 }
963 static void
xl_xml_editpos_col(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)964 xl_xml_editpos_col (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
965 {
966 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
967 char *end;
968 int tmp;
969 errno = 0;
970 tmp = strtol (xin->content->str, &end, 10);
971 if (errno != ERANGE && *end == '\0')
972 state->pos.col = tmp;
973 }
974 static void
xl_xml_selection(GsfXMLIn * xin,G_GNUC_UNUSED GsfXMLBlob * blob)975 xl_xml_selection (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
976 {
977 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
978 SheetView *sv = sheet_get_view (state->sheet, state->wb_view);
979 char const *ptr, *end;
980 GnmParsePos pp;
981 GnmRangeRef rr;
982 GnmRange r;
983
984 g_return_if_fail (sv != NULL);
985
986 parse_pos_init_sheet (&pp, state->sheet);
987 sv_selection_reset (sv);
988 for (ptr = xin->content->str; ptr && *ptr ; ) {
989 end = rangeref_parse (&rr, ptr, &pp, gnm_conventions_xls_r1c1);
990 if (end != ptr) {
991 range_init_rangeref (&r, &rr);
992 sv_selection_add_full
993 (sv,
994 state->pos.col, state->pos.row,
995 r.start.col, r.start.row,
996 r.end.col, r.end.row,
997 GNM_SELECTION_MODE_ADD);
998
999 if (*end != ',')
1000 break;
1001 ptr = end + 1;
1002 } else
1003 break;
1004 }
1005 }
1006
1007 static void
xl_xml_auto_filter_start(GsfXMLIn * xin,G_GNUC_UNUSED xmlChar const ** attrs)1008 xl_xml_auto_filter_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
1009 {
1010 ExcelXMLReadState *state = (ExcelXMLReadState *)xin->user_state;
1011 GnmFilter *filter;
1012 GnmParsePos pp;
1013 GnmRangeRef rr;
1014 GnmRange r;
1015 char const *end, *range = NULL;
1016
1017 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
1018 if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_XL, "Range"))
1019 range = attrs[1];
1020 else
1021 unknown_attr (xin, attrs, "AutoFilter");
1022
1023 if (range)
1024 {
1025 parse_pos_init_sheet (&pp, state->sheet);
1026 end = rangeref_parse (&rr, range, &pp, gnm_conventions_xls_r1c1);
1027 if (end != range)
1028 {
1029 range_init_rangeref (&r, &rr);
1030 filter = gnm_filter_new (state->sheet, &r, TRUE);
1031 gnm_filter_reapply (filter);
1032 }
1033 }
1034 }
1035
1036 /****************************************************************************/
1037
1038 static GsfXMLInNS content_ns[] = {
1039 GSF_XML_IN_NS (XL_NS_SS, "urn:schemas-microsoft-com:office:spreadsheet"),
1040 GSF_XML_IN_NS (XL_NS_SS, "http://schemas.microsoft.com/office/excel/2003/xml"),
1041 GSF_XML_IN_NS (XL_NS_O, "urn:schemas-microsoft-com:office:office"),
1042 GSF_XML_IN_NS (XL_NS_XL, "urn:schemas-microsoft-com:office:excel"),
1043 GSF_XML_IN_NS (XL_NS_C, "urn:schemas-microsoft-com:office:component:spreadsheet"),
1044 GSF_XML_IN_NS (XL_NS_HTML, "http://www.w3.org/TR/REC-html40"),
1045 GSF_XML_IN_NS (XL_NS_XSI, "http://www.w3.org/2001/XMLSchema-instance"),
1046
1047 { NULL, 0 }
1048 };
1049
1050 static GsfXMLInNode const excel_xml_dtd[] = {
1051 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
1052 GSF_XML_IN_NODE_FULL (START, WORKBOOK, XL_NS_SS, "Workbook", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
1053 GSF_XML_IN_NODE (WORKBOOK, DOC_PROP, XL_NS_O, "DocumentProperties", GSF_XML_NO_CONTENT, &xl_xml_doc_prop_start, &xl_xml_doc_prop_end),
1054 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_AUTHOR, XL_NS_O, "Author", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_INITIAL_CREATOR),
1055 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_CATEGORY, XL_NS_O, "Category", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_CATEGORY),
1056 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_CEATED, XL_NS_O, "Created", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop_dt, .v_str = GSF_META_NAME_DATE_CREATED),
1057 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_COMPANY, XL_NS_O, "Company", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_COMPANY),
1058 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_DESCRIPTION, XL_NS_O, "Description", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_DESCRIPTION),
1059 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_HYPERLINK_BASE, XL_NS_O, "HyperlinkBase", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = "xlsx:HyperlinkBase"),
1060 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_KEYWORDS, XL_NS_O, "Keywords", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_keywords, .v_str = GSF_META_NAME_KEYWORDS),
1061
1062 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_LAST_AUTHOR, XL_NS_O, "LastAuthor", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_CREATOR),
1063 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_LAST_PRINTED, XL_NS_O, "LastPrinted", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop_dt, .v_str = GSF_META_NAME_PRINT_DATE),
1064 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_LAST_SAVED, XL_NS_O, "LastSaved", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop_dt, .v_str = GSF_META_NAME_DATE_MODIFIED),
1065 GSF_XML_IN_NODE (DOC_PROP, PROP_LINES, XL_NS_O, "Lines", GSF_XML_CONTENT, NULL, NULL),
1066 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_MANAGER, XL_NS_O, "Manager", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_MANAGER),
1067 GSF_XML_IN_NODE (DOC_PROP, PROP_REVISION, XL_NS_O, "Revision", GSF_XML_CONTENT, NULL, NULL),
1068 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_SUBJECT, XL_NS_O, "Subject", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_SUBJECT),
1069 GSF_XML_IN_NODE_FULL (DOC_PROP, PROP_TITLE, XL_NS_O, "Title", GSF_XML_CONTENT, FALSE, FALSE, NULL, &xl_xml_read_prop, .v_str = GSF_META_NAME_TITLE),
1070 GSF_XML_IN_NODE (DOC_PROP, PROP_TOTAL_TIME, XL_NS_O, "TotalTime", GSF_XML_CONTENT, NULL, NULL),
1071 GSF_XML_IN_NODE (DOC_PROP, PROP_VERSION, XL_NS_O, "Version", GSF_XML_CONTENT, NULL, NULL),
1072
1073 GSF_XML_IN_NODE (WORKBOOK, DOC_SETTINGS, XL_NS_O, "OfficeDocumentSettings", GSF_XML_NO_CONTENT, NULL, NULL),
1074 GSF_XML_IN_NODE (DOC_SETTINGS, DOC_COLORS, XL_NS_O, "Colors", GSF_XML_NO_CONTENT, NULL, NULL),
1075 GSF_XML_IN_NODE (DOC_COLORS, DOC_COLOR, XL_NS_O, "Color", GSF_XML_NO_CONTENT, NULL, NULL),
1076 GSF_XML_IN_NODE (DOC_COLOR, COLOR_INDEX, XL_NS_O, "Index", GSF_XML_NO_CONTENT, NULL, NULL),
1077 GSF_XML_IN_NODE (DOC_COLOR, COLOR_RGB, XL_NS_O, "RGB", GSF_XML_NO_CONTENT, NULL, NULL),
1078 GSF_XML_IN_NODE (DOC_SETTINGS, DOC_COMPONENTS, XL_NS_O, "DownloadComponents", GSF_XML_NO_CONTENT, NULL, NULL),
1079 GSF_XML_IN_NODE (DOC_SETTINGS, DOC_COMPONENTS_LOCATION, XL_NS_O, "LocationOfComponents", GSF_XML_NO_CONTENT, NULL, NULL),
1080 GSF_XML_IN_NODE (WORKBOOK, WB_VIEW, XL_NS_XL, "ExcelWorkbook", GSF_XML_NO_CONTENT, NULL, NULL),
1081 GSF_XML_IN_NODE (WB_VIEW, TAB_RATIO, XL_NS_XL, "TabRatio", GSF_XML_NO_CONTENT, NULL, NULL),
1082 GSF_XML_IN_NODE (WB_VIEW, SUPBOOK, XL_NS_XL, "SupBook", GSF_XML_NO_CONTENT, NULL, NULL),
1083 GSF_XML_IN_NODE (SUPBOOK, SUP_DLL, XL_NS_XL, "Dll", GSF_XML_NO_CONTENT, NULL, NULL),
1084 GSF_XML_IN_NODE (SUPBOOK, SUP_EXTERNNAME, XL_NS_XL, "ExternName", GSF_XML_NO_CONTENT, NULL, NULL),
1085 GSF_XML_IN_NODE (SUP_EXTERNNAME, EXTERNNAME_NAME, XL_NS_XL, "Name", GSF_XML_NO_CONTENT, NULL, NULL),
1086 GSF_XML_IN_NODE (WB_VIEW, VIEW_HEIGHT, XL_NS_XL, "WindowHeight", GSF_XML_CONTENT, NULL, NULL),
1087 GSF_XML_IN_NODE (WB_VIEW, VIEW_WIDTH, XL_NS_XL, "WindowWidth", GSF_XML_CONTENT, NULL, NULL),
1088 GSF_XML_IN_NODE (WB_VIEW, VIEW_TOP_X, XL_NS_XL, "WindowTopX", GSF_XML_CONTENT, NULL, NULL),
1089 GSF_XML_IN_NODE (WB_VIEW, VIEW_TOP_Y, XL_NS_XL, "WindowTopY", GSF_XML_CONTENT, NULL, NULL),
1090 GSF_XML_IN_NODE (WB_VIEW, PROTECT_STRUCTURE, XL_NS_XL, "ProtectStructure", GSF_XML_CONTENT, NULL, NULL),
1091 GSF_XML_IN_NODE (WB_VIEW, PROTECT_WINDOWS, XL_NS_XL, "ProtectWindows", GSF_XML_CONTENT, NULL, NULL),
1092 GSF_XML_IN_NODE (WB_VIEW, NATURAL_LANGUAGE, XL_NS_XL, "AcceptLabelsInFormulas", GSF_XML_CONTENT, NULL, NULL),
1093 GSF_XML_IN_NODE (WORKBOOK, STYLES, XL_NS_SS, "Styles", GSF_XML_NO_CONTENT, NULL, NULL),
1094 GSF_XML_IN_NODE (STYLES, STYLE, XL_NS_SS, "Style", GSF_XML_NO_CONTENT, &xl_xml_style_start, &xl_xml_style_end),
1095 GSF_XML_IN_NODE (STYLE, ALIGNMENT, XL_NS_SS, "Alignment", GSF_XML_NO_CONTENT, &xl_xml_alignment, NULL),
1096 GSF_XML_IN_NODE (STYLE, BORDERS, XL_NS_SS, "Borders", GSF_XML_NO_CONTENT, NULL, NULL),
1097 GSF_XML_IN_NODE (BORDERS, BORDER, XL_NS_SS, "Border", GSF_XML_NO_CONTENT, &xl_xml_border, NULL),
1098 GSF_XML_IN_NODE (STYLE, FONT, XL_NS_SS, "Font", GSF_XML_NO_CONTENT, &xl_xml_font, NULL),
1099 GSF_XML_IN_NODE (STYLE, INTERIOR, XL_NS_SS, "Interior", GSF_XML_NO_CONTENT, &xl_xml_num_interior, NULL),
1100 GSF_XML_IN_NODE (STYLE, NUM_FMT, XL_NS_SS, "NumberFormat", GSF_XML_NO_CONTENT, &xl_xml_num_fmt, NULL),
1101 GSF_XML_IN_NODE (STYLE, PROTECTION, XL_NS_SS, "Protection", GSF_XML_NO_CONTENT, NULL, NULL),
1102 GSF_XML_IN_NODE (WORKBOOK, NAMES, XL_NS_SS, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
1103 GSF_XML_IN_NODE (NAMES, NAMED_RANGE, XL_NS_SS, "NamedRange", GSF_XML_NO_CONTENT, &xl_xml_named_range, NULL),
1104
1105 GSF_XML_IN_NODE_FULL (WORKBOOK, WORKSHEET, XL_NS_SS, "Worksheet", GSF_XML_NO_CONTENT, FALSE, TRUE, &xl_xml_sheet_start, &xl_xml_sheet_end, 0),
1106 GSF_XML_IN_NODE (WORKSHEET, TABLE, XL_NS_SS, "Table", GSF_XML_NO_CONTENT, &xl_xml_table_start, NULL),
1107 GSF_XML_IN_NODE (TABLE, COLUMN, XL_NS_SS, "Column", GSF_XML_NO_CONTENT, &xl_xml_col_start, NULL),
1108 GSF_XML_IN_NODE (TABLE, ROW, XL_NS_SS, "Row", GSF_XML_NO_CONTENT, &xl_xml_row_start, &xl_xml_row_end),
1109 GSF_XML_IN_NODE_FULL (ROW, CELL, XL_NS_SS, "Cell", GSF_XML_NO_CONTENT, FALSE, TRUE, &xl_xml_cell_start, &xl_xml_cell_end, 0),
1110 GSF_XML_IN_NODE (CELL, NAMED_CELL, XL_NS_SS, "NamedCell", GSF_XML_NO_CONTENT, NULL, NULL),
1111 GSF_XML_IN_NODE_FULL (CELL, CELL_DATA, XL_NS_SS, "Data", GSF_XML_CONTENT, GSF_XML_NO_CONTENT, TRUE, &xl_xml_data_start, &xl_xml_data_end, 0),
1112 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_B, XL_NS_HTML, "B", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 0),
1113 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_I, XL_NS_HTML, "I", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 1),
1114 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_U, XL_NS_HTML, "U", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 2),
1115 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_FONT, XL_NS_HTML, "Font", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 3),
1116 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_S, XL_NS_HTML, "S", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 4),
1117 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_SUP, XL_NS_HTML, "Sup", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 5),
1118 GSF_XML_IN_NODE_FULL (CELL_DATA, HTML_SUB, XL_NS_HTML, "Sub", GSF_XML_SHARED_CONTENT, TRUE, FALSE, NULL, NULL, 6),
1119 GSF_XML_IN_NODE (WORKSHEET, OPTIONS, XL_NS_XL, "WorksheetOptions", GSF_XML_NO_CONTENT, NULL, NULL),
1120 GSF_XML_IN_NODE (OPTIONS, TOP_ROW, XL_NS_XL, "TopRowVisible", GSF_XML_NO_CONTENT, NULL, NULL),
1121 GSF_XML_IN_NODE (OPTIONS, UNSYNCED, XL_NS_XL, "Unsynced", GSF_XML_NO_CONTENT, NULL, NULL), /* ?? */
1122 GSF_XML_IN_NODE (OPTIONS, SELECTED, XL_NS_XL, "Selected", GSF_XML_NO_CONTENT, NULL, NULL), /* ?? */
1123 GSF_XML_IN_NODE (OPTIONS, PANES, XL_NS_XL, "Panes", GSF_XML_NO_CONTENT, NULL, NULL),
1124 GSF_XML_IN_NODE (PANES, PANE, XL_NS_XL, "Pane", GSF_XML_NO_CONTENT, &xl_xml_pane, NULL),
1125 GSF_XML_IN_NODE (PANE, PANE_NUM, XL_NS_XL, "Number", GSF_XML_CONTENT, NULL, NULL),
1126 GSF_XML_IN_NODE (PANE, PANE_ACTIVEROW, XL_NS_XL, "ActiveRow", GSF_XML_CONTENT, NULL, &xl_xml_editpos_row),
1127 GSF_XML_IN_NODE (PANE, PANE_ACTIVECOL, XL_NS_XL, "ActiveCol", GSF_XML_CONTENT, NULL, &xl_xml_editpos_col),
1128 GSF_XML_IN_NODE (PANE, PANE_SELECTION, XL_NS_XL, "RangeSelection", GSF_XML_CONTENT, NULL, &xl_xml_selection),
1129 GSF_XML_IN_NODE (OPTIONS, PAGE_SETUP, XL_NS_XL, "PageSetup", GSF_XML_NO_CONTENT, NULL, NULL),
1130 GSF_XML_IN_NODE (PAGE_SETUP, PAGE_LAYOUT, XL_NS_XL, "Layout", GSF_XML_NO_CONTENT, NULL, NULL),
1131 GSF_XML_IN_NODE (PAGE_SETUP, PAGE_HEADER, XL_NS_XL, "Header", GSF_XML_NO_CONTENT, NULL, NULL),
1132 GSF_XML_IN_NODE (PAGE_SETUP, PAGE_FOOTER, XL_NS_XL, "Footer", GSF_XML_NO_CONTENT, NULL, NULL),
1133 GSF_XML_IN_NODE (PAGE_SETUP, PAGE_MARGINS, XL_NS_XL, "PageMargins", GSF_XML_NO_CONTENT, NULL, NULL),
1134 GSF_XML_IN_NODE (OPTIONS, PRINT, XL_NS_XL, "Print", GSF_XML_NO_CONTENT, NULL, NULL),
1135 GSF_XML_IN_NODE (PRINT, PRINT_NUMBER_COPIES, XL_NS_XL, "NumberofCopies", GSF_XML_NO_CONTENT, NULL, NULL),
1136 GSF_XML_IN_NODE (PRINT, PRINT_VALID_INFO, XL_NS_XL, "ValidPrinterInfo", GSF_XML_NO_CONTENT, NULL, NULL),
1137 GSF_XML_IN_NODE (PRINT, PRINT_PAPER_SIZE, XL_NS_XL, "PaperSizeIndex", GSF_XML_CONTENT, NULL, NULL),
1138 GSF_XML_IN_NODE (PRINT, PRINT_HRES, XL_NS_XL, "HorizontalResolution", GSF_XML_CONTENT, NULL, NULL),
1139 GSF_XML_IN_NODE (PRINT, PRINT_VRES, XL_NS_XL, "VerticalResolution", GSF_XML_CONTENT, NULL, NULL),
1140
1141 GSF_XML_IN_NODE (OPTIONS, PROT_OBJS, XL_NS_XL, "ProtectObjects", GSF_XML_CONTENT, NULL, NULL),
1142 GSF_XML_IN_NODE (OPTIONS, PROT_SCENARIOS, XL_NS_XL, "ProtectScenarios", GSF_XML_CONTENT, NULL, NULL),
1143 GSF_XML_IN_NODE (OPTIONS, PAGEBREAK_ZOOM, XL_NS_XL, "PageBreakZoom", GSF_XML_NO_CONTENT, NULL, NULL),
1144 GSF_XML_IN_NODE (WORKSHEET, COND_FMT, XL_NS_XL, "ConditionalFormatting", GSF_XML_NO_CONTENT, NULL, NULL),
1145 GSF_XML_IN_NODE (COND_FMT, COND_RANGE, XL_NS_XL, "Range", GSF_XML_NO_CONTENT, NULL, NULL),
1146 GSF_XML_IN_NODE (COND_FMT, COND, XL_NS_XL, "Condition", GSF_XML_NO_CONTENT, NULL, NULL),
1147 GSF_XML_IN_NODE (COND, COND_VALUE1, XL_NS_XL, "Value1", GSF_XML_NO_CONTENT, NULL, NULL),
1148 GSF_XML_IN_NODE (COND, COND_STYLE, XL_NS_XL, "Format", GSF_XML_NO_CONTENT, NULL, NULL),
1149 GSF_XML_IN_NODE (WORKSHEET, AUTO_FILTER, XL_NS_XL, "AutoFilter", GSF_XML_NO_CONTENT, &xl_xml_auto_filter_start, NULL),
1150 GSF_XML_IN_NODE (WORKSHEET, WS_NAMES, XL_NS_SS, "Names", GSF_XML_NO_CONTENT, NULL, NULL),
1151 GSF_XML_IN_NODE (WS_NAMES, WS_NAMED_RANGE, XL_NS_SS, "NamedRange", GSF_XML_NO_CONTENT, NULL, NULL),
1152
1153 GSF_XML_IN_NODE_END
1154 };
1155
1156 G_MODULE_EXPORT void
1157 excel_xml_file_open (GOFileOpener const *fo, GOIOContext *context,
1158 WorkbookView *wbv, GsfInput *input);
1159
1160 G_MODULE_EXPORT gboolean
1161 excel_xml_file_probe (GOFileOpener const *fo, GsfInput *input, GOFileProbeLevel pl);
1162
1163 static gboolean
xl_xml_probe_start_element(const xmlChar * name,G_GNUC_UNUSED const xmlChar * prefix,const xmlChar * URI,G_GNUC_UNUSED int nb_namespaces,G_GNUC_UNUSED const xmlChar ** namespaces,G_GNUC_UNUSED int nb_attributes,G_GNUC_UNUSED int nb_defaulted,G_GNUC_UNUSED const xmlChar ** attributes)1164 xl_xml_probe_start_element (const xmlChar *name,
1165 G_GNUC_UNUSED const xmlChar *prefix,
1166 const xmlChar *URI,
1167 G_GNUC_UNUSED int nb_namespaces,
1168 G_GNUC_UNUSED const xmlChar **namespaces,
1169 G_GNUC_UNUSED int nb_attributes,
1170 G_GNUC_UNUSED int nb_defaulted,
1171 G_GNUC_UNUSED const xmlChar **attributes)
1172 {
1173 /* starts with <Workbook> in namespace "schemas-microsoft-com:office:spreadsheet" */
1174 return 0 == strcmp (name, "Workbook") &&
1175 NULL != URI &&
1176 NULL != strstr (URI, "schemas-microsoft-com:office:spreadsheet");
1177 }
1178
1179 gboolean
excel_xml_file_probe(G_GNUC_UNUSED GOFileOpener const * fo,GsfInput * input,GOFileProbeLevel pl)1180 excel_xml_file_probe (G_GNUC_UNUSED GOFileOpener const *fo,
1181 GsfInput *input, GOFileProbeLevel pl)
1182 {
1183 if (pl == GO_FILE_PROBE_FILE_NAME) {
1184 char const *ext;
1185 char const *name = gsf_input_name (input);
1186 return NULL != name &&
1187 NULL != (ext = gsf_extension_pointer (name)) &&
1188 0 == g_ascii_strcasecmp (ext, "xml");
1189 }
1190
1191 return gsf_xml_probe (input, &xl_xml_probe_start_element);
1192 }
1193
1194 void
excel_xml_file_open(G_GNUC_UNUSED GOFileOpener const * fo,GOIOContext * io_context,WorkbookView * wb_view,GsfInput * input)1195 excel_xml_file_open (G_GNUC_UNUSED GOFileOpener const *fo,
1196 GOIOContext *io_context,
1197 WorkbookView *wb_view, GsfInput *input)
1198 {
1199 GsfXMLInDoc *doc;
1200 ExcelXMLReadState state;
1201 GnmLocale *locale;
1202
1203 locale = gnm_push_C_locale ();
1204
1205 state.context = io_context;
1206 state.wb_view = wb_view;
1207 state.wb = wb_view_get_workbook (wb_view);
1208 state.sheet = NULL;
1209 state.style = NULL;
1210 state.def_style = NULL;
1211 state.texpr = NULL;
1212 state.style_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
1213 (GDestroyNotify)g_free, (GDestroyNotify) gnm_style_unref);
1214
1215 doc = gsf_xml_in_doc_new (excel_xml_dtd, content_ns);
1216 if (!gsf_xml_in_doc_parse (doc, input, &state))
1217 go_io_error_string (io_context, _("XML document not well formed!"));
1218 gsf_xml_in_doc_free (doc);
1219
1220 g_hash_table_destroy (state.style_hash);
1221
1222 gnm_pop_C_locale (locale);
1223 }
1224