xml-io.c 91.7 KB
Newer Older
1
/* vim: set sw=8: */
2 3 4
/*
 * xml-io.c: save/read gnumeric Sheets using an XML encoding.
 *
5 6 7
 * Authors:
 *   Daniel Veillard <Daniel.Veillard@w3.org>
 *   Miguel de Icaza <miguel@gnu.org>
Jody Goldberg's avatar
Jody Goldberg committed
8
 *   Jody Goldberg <jody@gnome.org>
9
 */
10 11
#include <gnumeric-config.h>
#include "gnumeric.h"
12
#include "xml-io.h"
13

14
#include "style-color.h"
15
#include "style-border.h"
16
#include "style.h"
Jody Goldberg's avatar
Jody Goldberg committed
17 18
#include "sheet.h"
#include "sheet-style.h"
19
#include "sheet-object.h"
20
#include "sheet-object-cell-comment.h"
21
#include "str.h"
22
#include "print-info.h"
23
#include "file.h"
24
#include "expr.h"
25
#include "expr-name.h"
26
#include "cell.h"
27
#include "value.h"
28
#include "validation.h"
29
#include "sheet-merge.h"
30 31 32
#include "io-context.h"
#include "command-context.h"
#include "workbook-control.h"
33
#include "workbook-view.h"
34
#include "workbook.h"
35
#include "selection.h"
36
#include "clipboard.h"
Jody Goldberg's avatar
Jody Goldberg committed
37
#include "format.h"
Jody Goldberg's avatar
Jody Goldberg committed
38
#include "ranges.h"
Chyla Zbigniew's avatar
Chyla Zbigniew committed
39
#include "file.h"
Jody Goldberg's avatar
Jody Goldberg committed
40
#include "str.h"
41
#include "plugin-util.h"
Jody Goldberg's avatar
Jody Goldberg committed
42

Jody Goldberg's avatar
Jody Goldberg committed
43 44 45
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/xmlmemory.h>
46 47
#include <sys/types.h>
#include <sys/stat.h>
48
#include <unistd.h>
49
#include <fcntl.h>
50
#include <errno.h>
51
#include <zlib.h>
52
#include <string.h>
Jody Goldberg's avatar
Jody Goldberg committed
53
#include <gal/util/e-xml-utils.h>
54
#include <gal/widgets/e-colors.h>
55 56
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-util.h>
57
#include <libgnome/gnome-config.h>
Jody Goldberg's avatar
Jody Goldberg committed
58 59 60
#include <locale.h>
#include <math.h>
#include <limits.h>
61 62 63
#ifdef ENABLE_BONOBO
#include <bonobo/bonobo-exception.h>
#endif
64

65 66 67
/* Precision to use when saving point measures. */
#define POINT_SIZE_PRECISION 3

68
/* FIXME - tune the values below */
69 70
#define XML_INPUT_BUFFER_SIZE      4096
#define N_ELEMENTS_BETWEEN_UPDATES 20
71

72 73
/* ------------------------------------------------------------------------- */

74 75
static GnumFileOpener *xml_opener = NULL;
static GnumFileSaver  *xml_saver = NULL;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
76

77
GnumFileOpener *
78
gnumeric_xml_get_opener (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
79
{
80
	return xml_opener;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
81 82
}

83
GnumFileSaver *
84
gnumeric_xml_get_saver (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
85
{
86
	return xml_saver;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
87 88
}

89 90
/* ------------------------------------------------------------------------- */

91 92 93
XmlParseContext *
xml_parse_ctx_new_full (xmlDocPtr             doc,
			xmlNsPtr              ns,
Michael Meeks's avatar
Michael Meeks committed
94
			GnumericXMLVersion    version,
95 96 97 98 99 100
			XmlSheetObjectReadFn  read_fn,
			XmlSheetObjectWriteFn write_fn,
			gpointer              user_data)
{
	XmlParseContext *ctxt = g_new0 (XmlParseContext, 1);

101 102 103 104 105
	ctxt->version      = version;
	ctxt->doc          = doc;
	ctxt->ns           = ns;
	ctxt->expr_map     = g_hash_table_new (g_direct_hash, g_direct_equal);
	ctxt->shared_exprs = g_ptr_array_new ();
106

107 108 109
	ctxt->write_fn     = write_fn;
	ctxt->read_fn      = read_fn;
	ctxt->user_data    = user_data;
110 111 112 113 114 115 116 117

	return ctxt;
}

XmlParseContext *
xml_parse_ctx_new (xmlDocPtr doc,
		   xmlNsPtr  ns)
{
Michael Meeks's avatar
Michael Meeks committed
118
	return xml_parse_ctx_new_full (
Jody Goldberg's avatar
Jody Goldberg committed
119
		doc, ns, GNUM_XML_LATEST, NULL, NULL, NULL);
120
}
121

122 123 124 125 126 127
void
xml_parse_ctx_destroy (XmlParseContext *ctxt)
{
	g_return_if_fail (ctxt != NULL);

	g_hash_table_destroy (ctxt->expr_map);
128 129
	g_ptr_array_free (ctxt->shared_exprs, TRUE);

130 131
	g_free (ctxt);
}
132

133 134
/* ------------------------------------------------------------------------- */

135 136
/* Get an xmlChar * value for a node carried as an attibute
 * result must be xmlFree
137
 */
138
xmlChar *
139
xml_node_get_cstr (xmlNodePtr node, char const *name)
140
{
Jody Goldberg's avatar
Jody Goldberg committed
141 142 143 144 145 146 147 148
	if (name != NULL)
		return xmlGetProp (node, (xmlChar *)name);
	/* in libxml1 <foo/> would return NULL
	 * in libxml2 <foo/> would return ""
	 */
	if (node->xmlChildrenNode != NULL)
		return xmlNodeGetContent (node);
	return NULL;
149 150
}
void
151
xml_node_set_cstr (xmlNodePtr node, char const *name, char const *val)
152
{
153
	if (name)
Jody Goldberg's avatar
Jody Goldberg committed
154
		xmlSetProp (node, (xmlChar *)name, (xmlChar *)val);
155
	else
Jody Goldberg's avatar
Jody Goldberg committed
156
		xmlNodeSetContent (node, (xmlChar *)val);
157 158
}

159
gboolean
160
xml_node_get_int (xmlNodePtr node, char const *name, int *val)
161
{
162
	xmlChar *buf;
163
	char *end;
164

165 166 167
	buf = xml_node_get_cstr (node, name);
	if (buf == NULL)
		return FALSE;
168 169

	errno = 0; /* strto(ld) sets errno, but does not clear it.  */
Jody Goldberg's avatar
Jody Goldberg committed
170
	*val = strtol ((char *)buf, &end, 10);
171
	xmlFree (buf);
172

173
	return ((char *)buf != end) && (errno != ERANGE);
174
}
175

176
void
177
xml_node_set_int (xmlNodePtr node, char const *name, int val)
178
{
179 180
	char str[4 * sizeof (int)];
	sprintf (str, "%d", val);
Jody Goldberg's avatar
Jody Goldberg committed
181
	xml_node_set_cstr (node, name, str);
182 183
}

184
gboolean
185
xml_node_get_double (xmlNodePtr node, char const *name, double *val)
186
{
187
	xmlChar *buf;
188
	char *end;
189

190 191
	buf = xml_node_get_cstr (node, name);
	if (buf == NULL)
192
		return FALSE;
193 194

	errno = 0; /* strto(ld) sets errno, but does not clear it.  */
Jody Goldberg's avatar
Jody Goldberg committed
195
	*val = strtod ((char *)buf, &end);
196
	xmlFree (buf);
197

198
	return ((char *)buf != end) && (errno != ERANGE);
199
}
200

201
void
202
xml_node_set_double (xmlNodePtr node, char const *name, double val,
203
		     int precision)
204
{
205
	char str[101 + DBL_DIG];
206

207 208
	if (precision < 0 || precision > DBL_DIG)
		precision = DBL_DIG;
209

210
	if (fabs (val) < 1e9 && fabs (val) > 1e-5)
211
		snprintf (str, 100 + DBL_DIG, "%.*g", precision, val);
212 213
	else
		snprintf (str, 100 + DBL_DIG, "%f", val);
214

Jody Goldberg's avatar
Jody Goldberg committed
215
	xml_node_set_cstr (node, name, str);
216 217
}

218 219 220 221 222 223 224
StyleColor *
xml_node_get_color (xmlNodePtr node, char const *name)
{
	StyleColor *res = NULL;
	xmlChar *color;
	int red, green, blue;

Jody Goldberg's avatar
Jody Goldberg committed
225
	color = xmlGetProp (node, (xmlChar *)name);
226 227
	if (color == NULL)
		return 0;
Jody Goldberg's avatar
Jody Goldberg committed
228
	if (sscanf ((char *)color, "%X:%X:%X", &red, &green, &blue) == 3)
229 230 231 232 233 234 235 236 237 238 239 240
		res = style_color_new (red, green, blue);
	xmlFree (color);
	return res;
}
void
xml_node_set_color (xmlNodePtr node, char const *name, StyleColor const *val)
{
	char str[4 * sizeof (val->color)];
	sprintf (str, "%X:%X:%X", val->color.red, val->color.green, val->color.blue);
	xml_node_set_cstr (node, name, str);
}

241 242 243 244 245 246 247 248 249 250
static gboolean
xml_node_get_cellpos (xmlNodePtr node, char const *name, CellPos *val)
{
	xmlChar *buf;
	int dummy;
	gboolean res;

	buf = xml_node_get_cstr (node, name);
	if (val == NULL)
		return FALSE;
Jody Goldberg's avatar
Jody Goldberg committed
251
	res = parse_cell_name ((char *)buf, &val->col, &val->row, TRUE, &dummy);
252 253 254 255 256 257 258 259 260 261
	xmlFree (buf);
	return res;
}

static void
xml_node_set_cellpos (xmlNodePtr node, char const *name, CellPos const *val)
{
	xml_node_set_cstr (node, name, cell_pos_name (val));
}

262 263 264 265
/*
 * Set a double value for a node with POINT_SIZE_PRECISION digits precision.
 */
static void
266
xml_node_set_points (xmlNodePtr node, char const *name, double val)
267
{
268
	xml_node_set_double (node, name, val, POINT_SIZE_PRECISION);
269 270
}

271
static void
272
xml_node_set_print_unit (xmlNodePtr node, char const *name,
273
			 PrintUnit const *pu)
274 275
{
	xmlNodePtr  child;
Jody Goldberg's avatar
Jody Goldberg committed
276
	char       *txt = "points";
Jody Goldberg's avatar
Jody Goldberg committed
277
	xmlChar       *tstr;
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

	if (pu == NULL || name == NULL)
		return;

	switch (pu->desired_display) {
	case UNIT_POINTS:
		txt = "points";
		break;
	case UNIT_MILLIMETER:
		txt = "mm";
		break;
	case UNIT_CENTIMETER:
		txt = "cm";
		break;
	case UNIT_INCH:
		txt = "in";
		break;
	}

Jody Goldberg's avatar
Jody Goldberg committed
297
	child = xmlNewChild (node, NULL, (xmlChar *)name, NULL);
298

299
	xml_node_set_points (child, "Points", pu->points);
300

Jody Goldberg's avatar
Jody Goldberg committed
301 302
	tstr = xmlEncodeEntitiesReentrant (node->doc, (xmlChar *)txt);
	xml_node_set_cstr (child, "PrefUnit", (char *)tstr);
303
	if (tstr) xmlFree (tstr);
304 305 306
}

static void
307
xml_node_get_print_unit (xmlNodePtr node, PrintUnit * const pu)
308
{
Jody Goldberg's avatar
Jody Goldberg committed
309
	gchar       *txt;
310

311 312 313
	g_return_if_fail (pu != NULL);
	g_return_if_fail (node != NULL);

314
	xml_node_get_double (node, "Points", &pu->points);
Jody Goldberg's avatar
Jody Goldberg committed
315
	txt = (gchar *)xmlGetProp  (node, (xmlChar *)"PrefUnit");
316 317 318
	if (txt) {
		if (!g_strcasecmp (txt, "points"))
			pu->desired_display = UNIT_POINTS;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
319
		else if (!strcmp (txt, "mm"))
320
			pu->desired_display = UNIT_MILLIMETER;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
321
		else if (!strcmp (txt, "cm"))
322
			pu->desired_display = UNIT_CENTIMETER;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
323
		else if (!strcmp (txt, "in"))
324
			pu->desired_display = UNIT_INCH;
325
		xmlFree (txt);
326 327 328
	}
}

329
static gboolean
330
xml_node_get_range (xmlNodePtr tree, Range *r)
331
{
332
	gboolean res =
333 334 335 336
	    xml_node_get_int (tree, "startCol", &r->start.col) &&
	    xml_node_get_int (tree, "startRow", &r->start.row) &&
	    xml_node_get_int (tree, "endCol",   &r->end.col) &&
	    xml_node_get_int (tree, "endRow",   &r->end.row);
337

338 339
	/* Older versions of gnumeric had some boundary problems */
	range_ensure_sanity (r);
340 341

	return res;
342 343 344
}

static void
345
xml_node_set_range (xmlNodePtr tree, Range const *r)
346
{
Jody Goldberg's avatar
Jody Goldberg committed
347 348
	g_return_if_fail (range_is_sane (r));

349 350 351 352
	xml_node_set_int (tree, "startCol", r->start.col);
	xml_node_set_int (tree, "startRow", r->start.row);
	xml_node_set_int (tree, "endCol",   r->end.col);
	xml_node_set_int (tree, "endRow",   r->end.row);
353 354 355
}

static void
356
xml_read_selection_info (XmlParseContext *ctxt, xmlNodePtr tree)
357 358 359
{
	Range r;
	int row, col;
360
	Sheet *sheet = ctxt->sheet;
Jody Goldberg's avatar
Jody Goldberg committed
361
	xmlNodePtr sel, selections = e_xml_get_child_by_name (tree, (xmlChar *)"Selections");
362

363 364 365
	if (selections == NULL)
		return;

366
	sheet_selection_reset (sheet);
367
	for (sel = selections->xmlChildrenNode; sel; sel = sel->next)
Jody Goldberg's avatar
Jody Goldberg committed
368
		if (!xmlIsBlankNode (sel) && xml_node_get_range (sel, &r))
369 370 371 372
			sheet_selection_add_range (sheet,
						   r.start.col, r.start.row,
						   r.start.col, r.start.row,
						   r.end.col, r.end.row);
373

374 375
	if (xml_node_get_int (selections, "CursorCol", &col) &&
	    xml_node_get_int (selections, "CursorRow", &row))
376
		sheet_set_edit_pos (sheet, col, row);
377 378 379
}

static void
380
xml_write_selection_info (XmlParseContext *ctxt, Sheet const *sheet, xmlNodePtr tree)
381 382
{
	GList *ptr, *copy;
Jody Goldberg's avatar
Jody Goldberg committed
383
	tree = xmlNewChild (tree, ctxt->ns, (xmlChar *)"Selections", NULL);
384 385 386 387 388

	/* Insert the selections in REVERSE order */
	copy = g_list_copy (sheet->selections);
	ptr = g_list_reverse (copy);
	for (; ptr != NULL ; ptr = ptr->next) {
389
		Range const *r = ptr->data;
Jody Goldberg's avatar
Jody Goldberg committed
390
		xmlNodePtr child = xmlNewChild (tree, ctxt->ns, (xmlChar *)"Selection", NULL);
391
		xml_node_set_range (child, r);
392 393 394
	}
	g_list_free (copy);

395 396
	xml_node_set_int (tree, "CursorCol", sheet->edit_pos_real.col);
	xml_node_set_int (tree, "CursorRow", sheet->edit_pos_real.row);
397 398
}

399 400 401
/*
 * Create an XML subtree of doc equivalent to the given StyleBorder.
 */
402
static char const *StyleSideNames[6] =
403 404 405 406
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
407 408 409
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
410
};
411

412
static xmlNodePtr
413
xml_write_style_border (XmlParseContext *ctxt,
414
			const MStyle *style)
415 416 417
{
	xmlNodePtr cur;
	xmlNodePtr side;
418
	int        i;
419

420
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
421
		StyleBorder const *border;
422
		if (mstyle_is_element_set (style, i) &&
423
		    NULL != (border = mstyle_get_border (style, i))) {
Arturo Espinosa's avatar
Arturo Espinosa committed
424
			break;
425
		}
426
	}
427
	if (i > MSTYLE_BORDER_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
428
		return NULL;
429

Jody Goldberg's avatar
Jody Goldberg committed
430
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, (xmlChar *)"StyleBorder", NULL);
431

432
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
433
		StyleBorder const *border;
Jody Goldberg's avatar
Jody Goldberg committed
434
		if (mstyle_is_element_set (style, i) &&
435
		    NULL != (border = mstyle_get_border (style, i))) {
Jody Goldberg's avatar
Jody Goldberg committed
436 437
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
438
 			side = xmlNewChild (cur, ctxt->ns,
Jody Goldberg's avatar
Jody Goldberg committed
439
					    (xmlChar *)(StyleSideNames [i - MSTYLE_BORDER_TOP]),
440
 					    NULL);
441
			xml_node_set_int (side, "Style", t);
442
			if (t != STYLE_BORDER_NONE)
443
				xml_node_set_color (side, "Color", col);
444
 		}
445 446
	}
	return cur;
447 448 449 450 451
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
452
static void
453
xml_read_style_border (XmlParseContext *ctxt, xmlNodePtr tree, MStyle *mstyle)
454 455
{
	xmlNodePtr side;
456
	int        i;
457 458 459

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
460
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
461 462
			 tree->name);
	}
463

464
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
465
 		if ((side = e_xml_get_child_by_name (tree,
Jody Goldberg's avatar
Jody Goldberg committed
466
					      (xmlChar *)(StyleSideNames [i - MSTYLE_BORDER_TOP]))) != NULL) {
467 468
			int		 t;
			StyleColor      *color = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
469
			StyleBorder    *border;
470
			xml_node_get_int (side, "Style", &t);
471
			if (t != STYLE_BORDER_NONE)
472
				color = xml_node_get_color (side, "Color");
473
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
474
						     style_border_get_orientation (i));
475
			mstyle_set_border (mstyle, i, border);
476
 		}
477
	}
478 479 480 481 482
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
483
xmlNodePtr
484
xml_write_style (XmlParseContext *ctxt,
485
		 MStyle *style)
486
{
487
	xmlNodePtr  cur, child;
Jody Goldberg's avatar
Jody Goldberg committed
488
	xmlChar       *tstr;
489

Jody Goldberg's avatar
Jody Goldberg committed
490
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, (xmlChar *)"Style", NULL);
491

492
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_H))
493
		xml_node_set_int (cur, "HAlign", mstyle_get_align_h (style));
494
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_V))
495
		xml_node_set_int (cur, "VAlign", mstyle_get_align_v (style));
496
	if (mstyle_is_element_set (style, MSTYLE_WRAP_TEXT))
497
		xml_node_set_int (cur, "WrapText", mstyle_get_wrap_text (style));
498
	if (mstyle_is_element_set (style, MSTYLE_ORIENTATION))
499
		xml_node_set_int (cur, "Orient", mstyle_get_orientation (style));
500
	if (mstyle_is_element_set (style, MSTYLE_PATTERN))
501
		xml_node_set_int (cur, "Shade", mstyle_get_pattern (style));
Jody Goldberg's avatar
Jody Goldberg committed
502
	if (mstyle_is_element_set (style, MSTYLE_INDENT))
503
		xml_node_set_int (cur, "Indent", mstyle_get_indent (style));
504 505 506 507
	if (mstyle_is_element_set (style, MSTYLE_CONTENT_LOCKED))
		xml_node_set_int (cur, "Locked", mstyle_get_content_locked (style));
	if (mstyle_is_element_set (style, MSTYLE_CONTENT_HIDDEN))
		xml_node_set_int (cur, "Hidden", mstyle_get_content_hidden (style));
508 509

	if (mstyle_is_element_set (style, MSTYLE_COLOR_FORE))
510
		xml_node_set_color (cur, "Fore", mstyle_get_color (style, MSTYLE_COLOR_FORE));
511
	if (mstyle_is_element_set (style, MSTYLE_COLOR_BACK))
512
		xml_node_set_color (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
513
	if (mstyle_is_element_set (style, MSTYLE_COLOR_PATTERN))
514
		xml_node_set_color (cur, "PatternColor", mstyle_get_color (style, MSTYLE_COLOR_PATTERN));
Jody Goldberg's avatar
Jody Goldberg committed
515 516
	if (mstyle_is_element_set (style, MSTYLE_FORMAT)) {
		char *fmt = style_format_as_XL (mstyle_get_format (style), FALSE);
517
		xml_node_set_cstr (cur, "Format", fmt);
Jody Goldberg's avatar
Jody Goldberg committed
518 519
		g_free (fmt);
	}
520 521

	if (mstyle_is_element_set (style, MSTYLE_FONT_NAME) ||
522
	    mstyle_is_element_set (style, MSTYLE_FONT_SIZE) ||
523 524
	    mstyle_is_element_set (style, MSTYLE_FONT_BOLD) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_ITALIC) ||
525 526
	    mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH)) {
527
		char const *fontname;
528 529 530 531 532

		if (mstyle_is_element_set (style, MSTYLE_FONT_NAME))
			fontname = mstyle_get_font_name (style);
		else /* backwards compatibility */
			fontname = "Helvetica";
533

Jody Goldberg's avatar
Jody Goldberg committed
534 535
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, (xmlChar *)fontname);
		child = xmlNewChild (cur, ctxt->ns, (xmlChar *)"Font", tstr);
536 537
		if (tstr) xmlFree (tstr);

538
		if (mstyle_is_element_set (style, MSTYLE_FONT_SIZE))
539
			xml_node_set_points (child, "Unit",
540 541
					      mstyle_get_font_size (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_BOLD))
542
			xml_node_set_int (child, "Bold",
543 544
					   mstyle_get_font_bold (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_ITALIC))
545
			xml_node_set_int (child, "Italic",
546
					   mstyle_get_font_italic (style));
Jody Goldberg's avatar
Jody Goldberg committed
547
		if (mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE))
548
			xml_node_set_int (child, "Underline",
Jody Goldberg's avatar
Jody Goldberg committed
549
					   (int)mstyle_get_font_uline (style));
550
		if (mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH))
551
			xml_node_set_int (child, "StrikeThrough",
552
					   mstyle_get_font_strike (style));
553 554
	}

555
	if (mstyle_is_element_set (style, MSTYLE_VALIDATION)) {
Jody Goldberg's avatar
Jody Goldberg committed
556 557 558 559
		Validation const *v = mstyle_get_validation (style);
		ParsePos    pp;
		char	   *tmp;

Jody Goldberg's avatar
Jody Goldberg committed
560
		child = xmlNewChild (cur, ctxt->ns, (xmlChar *)"Validation", NULL);
Jody Goldberg's avatar
Jody Goldberg committed
561 562 563 564 565 566 567 568 569 570 571 572 573
		xml_node_set_int (child, "Style", v->style);
		xml_node_set_int (child, "Type", v->type);
		switch (v->type) {
		case VALIDATION_TYPE_AS_INT :
		case VALIDATION_TYPE_AS_NUMBER :
		case VALIDATION_TYPE_AS_DATE :
		case VALIDATION_TYPE_AS_TIME :
		case VALIDATION_TYPE_TEXT_LENGTH :
			xml_node_set_int (child, "Operator", v->op);
			break;
		default :
			break;
		}
574

Jody Goldberg's avatar
Jody Goldberg committed
575 576 577 578 579 580
		e_xml_set_bool_prop_by_name (child, (xmlChar *)"AllowBlank",
			v->allow_blank);
		e_xml_set_bool_prop_by_name (child, (xmlChar *)"UseDropdown",
			v->use_dropdown);

		if (v->title != NULL && v->title->str[0] != '\0') {
Jody Goldberg's avatar
Jody Goldberg committed
581 582
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, (xmlChar *)(v->title->str));
			xml_node_set_cstr (child, "Title", (char *)tstr);
583 584 585
			if (tstr) xmlFree (tstr);
		}

Jody Goldberg's avatar
Jody Goldberg committed
586
		if (v->msg != NULL && v->msg->str[0] != '\0') {
Jody Goldberg's avatar
Jody Goldberg committed
587 588
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, (xmlChar *)(v->msg->str));
			xml_node_set_cstr (child, "Message", (char *)tstr);
589 590
			if (tstr) xmlFree (tstr);
		}
Jody Goldberg's avatar
Jody Goldberg committed
591 592 593 594 595 596 597 598 599 600 601 602

		parse_pos_init (&pp, ctxt->wb, ctxt->sheet, 0, 0);
		if (v->expr[0] != NULL &&
		    (tmp = expr_tree_as_string (v->expr[0], &pp)) != NULL) {
			xmlNewChild (child, child->ns, (xmlChar *)"Expression0", tmp);
			g_free (tmp);
		}
		if (v->expr[1] != NULL &&
		    (tmp = expr_tree_as_string (v->expr[1], &pp)) != NULL) {
			xmlNewChild (child, child->ns, (xmlChar *)"Expression1", tmp);
			g_free (tmp);
		}
603 604
	}

605 606 607
	child = xml_write_style_border (ctxt, style);
	if (child)
		xmlAddChild (cur, child);
608 609

	return cur;
610 611
}

612
static xmlNodePtr
613
xml_write_names (XmlParseContext *ctxt, GList *names)
614
{
Jody Goldberg's avatar
Jody Goldberg committed
615 616
	xmlChar *txt;
	char *expr_str;
617 618
	xmlNodePtr  namesContainer, nameNode;
	NamedExpression const *nexpr;
619

Jody Goldberg's avatar
Jody Goldberg committed
620
	namesContainer = xmlNewDocNode (ctxt->doc, ctxt->ns, (xmlChar *)"Names", NULL);
621

622 623
	for (; names != NULL ; names = names->next) {
		nexpr = names->data;
624

625
		g_return_val_if_fail (nexpr != NULL, NULL);
626

Jody Goldberg's avatar
Jody Goldberg committed
627
		nameNode = xmlNewChild (namesContainer, ctxt->ns, (xmlChar *)"Name", NULL);
628

Jody Goldberg's avatar
Jody Goldberg committed
629 630
		txt = xmlEncodeEntitiesReentrant (ctxt->doc, (xmlChar *)nexpr->name->str);
		xmlNewChild (nameNode, ctxt->ns, (xmlChar *)"name", txt);
631
		if (txt) xmlFree (txt);
632

633
		expr_str = expr_name_as_string (nexpr, NULL);
Jody Goldberg's avatar
Jody Goldberg committed
634 635
		txt = xmlEncodeEntitiesReentrant (ctxt->doc, (xmlChar *)expr_str);
		xmlNewChild (nameNode, ctxt->ns, (xmlChar *)"value", txt);
636 637
		if (txt) xmlFree (txt);
		g_free (expr_str);
638

Jody Goldberg's avatar
Jody Goldberg committed
639 640
		xmlNewChild (nameNode, ctxt->ns, (xmlChar *)"position",
			(xmlChar *)cell_pos_name (&nexpr->pos.eval));
641
	}
642

643
	return namesContainer;
644 645 646
}

static void
647 648
xml_read_names (XmlParseContext *ctxt, xmlNodePtr tree,
		Workbook *wb, Sheet *sheet)
649
{
650 651 652
	xmlNode *id;
	xmlNode *expr;
	xmlNode *position;
Jody Goldberg's avatar
Jody Goldberg committed
653 654 655
	xmlNode *name = e_xml_get_child_by_name (tree, (xmlChar *)"Names");
	xmlChar *name_str;
	char	*expr_str;
656

657 658
	if (name == NULL)
		return;
659

660 661 662
	for (name = name->xmlChildrenNode; name ; name = name->next) {
		ParseError  perr;
		ParsePos    pp;
663

Jody Goldberg's avatar
Jody Goldberg committed
664 665
		if (xmlIsBlankNode (name) ||
		    name->name == NULL || strcmp (name->name, "Name"))
666
			continue;
667

Jody Goldberg's avatar
Jody Goldberg committed
668 669 670
		id = e_xml_get_child_by_name (name, (xmlChar *)"name");
		expr = e_xml_get_child_by_name (name, (xmlChar *)"value");
		position = e_xml_get_child_by_name (name, (xmlChar *)"position");
671

672
		g_return_if_fail (id != NULL && expr != NULL);
673

Jody Goldberg's avatar
Jody Goldberg committed
674 675
		name_str = xml_node_get_cstr (id, NULL);
		expr_str = (char *)xml_node_get_cstr (expr, NULL);
676
		g_return_if_fail (name_str != NULL && expr_str != NULL);
677

678 679
		parse_pos_init (&pp, wb, sheet, 0, 0);
		if (position != NULL) {
Jody Goldberg's avatar
Jody Goldberg committed
680
			xmlChar *pos_txt = xml_node_get_cstr (position, NULL);
681 682
			if (pos_txt != NULL) {
				CellRef tmp;
Jody Goldberg's avatar
Jody Goldberg committed
683
				char const *res = cellref_a1_get (&tmp, (char *)pos_txt, &pp.eval);
684
				if (res != NULL && *res == '\0') {
685 686
					pp.eval.col = tmp.col;
					pp.eval.row = tmp.row;
687
				}
688
				xmlFree (pos_txt);
689 690
			}
		}
691

692
		parse_error_init (&perr);
Jody Goldberg's avatar
Jody Goldberg committed
693
		if (!expr_name_create (&pp, (char *)name_str, expr_str, &perr))
694 695 696 697 698
			g_warning (perr.message);
		parse_error_free (&perr);

		xmlFree (name_str);
		xmlFree (expr_str);
699 700 701
	}
}

702
static xmlNodePtr
703
xml_write_summary (XmlParseContext *ctxt, SummaryInfo *summary_info)
704 705
{
	GList *items, *m;
Jody Goldberg's avatar
Jody Goldberg committed
706
	xmlChar *tstr;
707 708
	xmlNodePtr cur;

709
	if (!summary_info)
710 711
		return NULL;

712
	m = items = summary_info_as_list (summary_info);
713 714 715 716

	if (!items)
		return NULL;

Jody Goldberg's avatar
Jody Goldberg committed
717
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, (xmlChar *)"Summary", NULL);
718 719 720 721 722

	while (items) {
		xmlNodePtr   tmp;
		SummaryItem *sit = items->data;
		if (sit) {
Jody Goldberg's avatar
Jody Goldberg committed
723
			xmlChar *text;
724

Jody Goldberg's avatar
Jody Goldberg committed
725 726 727
			tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, (xmlChar *)"Item", NULL);
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, (xmlChar *)sit->name);
			xmlNewChild (tmp, ctxt->ns, (xmlChar *)"name", tstr);
728
			if (tstr) xmlFree (tstr);
729 730

			if (sit->type == SUMMARY_INT) {
Jody Goldberg's avatar
Jody Goldberg committed
731
				text = (xmlChar *)g_strdup_printf ("%d", sit->v.i);
732
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
Jody Goldberg's avatar
Jody Goldberg committed
733
				xmlNewChild (tmp, ctxt->ns, (xmlChar *)"val-int", tstr);
734
				if (tstr) xmlFree (tstr);
735
			} else {
Jody Goldberg's avatar
Jody Goldberg committed
736
				text = (xmlChar *)summary_item_as_text (sit);
737
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
Jody Goldberg's avatar
Jody Goldberg committed
738
				xmlNewChild (tmp, ctxt->ns, (xmlChar *)"val-string", tstr);
739
				if (tstr) xmlFree (tstr);
740 741
			}
			g_free (text);
742
			xmlAddChild (cur, tmp);
743 744 745 746 747 748 749 750
		}
		items = g_list_next (items);
	}
	g_list_free (m);
	return cur;
}

static void
751
xml_read_summary (XmlParseContext *ctxt, xmlNodePtr tree, SummaryInfo *summary_info)
752
{
753
	xmlNodePtr child;
754

755 756 757
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
758

Jody Goldberg's avatar
Jody Goldberg committed
759 760
	for (child = tree->xmlChildrenNode; child != NULL ; child = child->next)
		if (!xmlIsBlankNode (child) && child->name && !strcmp (child->name, "Item")) {
761
			xmlNodePtr bits;
Jody Goldberg's avatar
Jody Goldberg committed
762
			char *name = NULL;
763

Jody Goldberg's avatar
Jody Goldberg committed
764
			for (bits = child->xmlChildrenNode; bits != NULL ; bits = bits->next) {
765
				SummaryItem *sit = NULL;
766

Jody Goldberg's avatar
Jody Goldberg committed
767 768 769
				if (xmlIsBlankNode (bits))
					continue;

770
				if (!strcmp (bits->name, "name")) {
Jody Goldberg's avatar
Jody Goldberg committed
771
					name = (char *)xml_node_get_cstr (bits, NULL);
772 773 774 775
				} else {
					char *txt;
					g_return_if_fail (name);

Jody Goldberg's avatar
Jody Goldberg committed
776
					txt = (char *)xml_node_get_cstr (bits, NULL);
777 778
					if (txt != NULL){
						if (!strcmp (bits->name, "val-string"))
Jody Goldberg's avatar
Jody Goldberg committed
779
							sit = summary_item_new_string (name, txt, TRUE);
780
						else if (!strcmp (bits->name, "val-int"))
Miguel de Icaza's avatar
Miguel de Icaza committed
781
							sit = summary_item_new_int (name, atoi (txt));
782

783
						if (sit)
784
							summary_info_add (summary_info, sit);
Daniel Veillard's avatar
Daniel Veillard committed
785
						xmlFree (txt);
786
					}
787
				}
Jody Goldberg's avatar
Jody Goldberg committed
788 789 790 791
			}
			if (name) {
				xmlFree (name);
				name = NULL;
792 793 794 795
			}
		}
}

796
static void
797
xml_node_set_print_hf (xmlNodePtr node, char const *name,
798
		       PrintHF const *hf)
799 800 801 802 803 804
{
	xmlNodePtr  child;

	if (hf == NULL || name == NULL)
		return;

Jody Goldberg's avatar
Jody Goldberg committed
805
	child = xmlNewChild (node, NULL, (xmlChar *)name, NULL);
806 807 808
	xml_node_set_cstr (child, "Left", hf->left_format);
	xml_node_set_cstr (child, "Middle", hf->middle_format);
	xml_node_set_cstr (child, "Right", hf->right_format);
809 810 811
}

static void
812
xml_node_get_print_hf (xmlNodePtr node, PrintHF *hf)
813
{
Jody Goldberg's avatar
Jody Goldberg committed
814
	xmlChar *txt;
815

816 817 818
	g_return_if_fail (hf != NULL);
	g_return_if_fail (node != NULL);

Jody Goldberg's avatar
Jody Goldberg committed
819
	txt = xmlGetProp (node, (xmlChar *)"Left");
820
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
821 822
		if (hf->left_format)
			g_free (hf->left_format);
Jody Goldberg's avatar
Jody Goldberg committed
823
		hf->left_format = g_strdup ((gchar *)txt);
824
		xmlFree (txt);
Arturo Espinosa's avatar
Arturo Espinosa committed
825
	}
826

Jody Goldberg's avatar
Jody Goldberg committed
827
	txt = xmlGetProp (node, (xmlChar *)"Middle");
828
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
829 830
		if (hf->middle_format)
			g_free (hf->middle_format);
Jody Goldberg's avatar
Jody Goldberg committed
831
		hf->middle_format = g_strdup ((gchar *)txt);
832
		xmlFree (txt);
Arturo Espinosa's avatar
Arturo Espinosa committed
833
	}
834

Jody Goldberg's avatar
Jody Goldberg committed
835
	txt = xmlGetProp (node, (xmlChar *)"Right");
836
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
837 838
		if (hf->right_format)
			g_free (hf->right_format);
Jody Goldberg's avatar
Jody Goldberg committed
839
		hf->right_format = g_strdup ((gchar *)txt);
840
		xmlFree (txt);
Arturo Espinosa's avatar
Arturo Espinosa committed
841
	}