xml-io.c 69.2 KB
Newer Older
1 2 3
/*
 * xml-io.c: save/read gnumeric Sheets using an XML encoding.
 *
4 5 6
 * Authors:
 *   Daniel Veillard <Daniel.Veillard@w3.org>
 *   Miguel de Icaza <miguel@gnu.org>
7
 *
8
 * $Id$
9 10 11 12 13
 */

#include <config.h>
#include <stdio.h>
#include <gnome.h>
14
#include <locale.h>
15
#include <math.h>
16
#include "gnumeric.h"
17
#include "gnome-xml/parser.h"
Daniel Veillard's avatar
Daniel Veillard committed
18
#include "gnome-xml/parserInternals.h"
19
#include "gnome-xml/xmlmemory.h"
20
#include "color.h"
21
#include "border.h"
22
#include "sheet-object.h"
23
#include "sheet-object-graphic.h"
24
#include "print-info.h"
25
#include "xml-io.h"
26
#include "file.h"
27
#include "expr.h"
28
#include "cell.h"
29
#include "workbook.h"
30 31
#include "workbook-view.h"
#include "selection.h"
32
#include "command-context.h"
33 34 35 36

/*
 * A parsing context.
 */
37 38 39 40 41 42
typedef struct {
	xmlDocPtr doc;		/* Xml document */
	xmlNsPtr ns;		/* Main name space */
	xmlNodePtr parent;	/* used only for g_hash_table_foreach callbacks */
	Sheet *sheet;		/* the associated sheet */
	Workbook *wb;		/* the associated sheet */
43
	GHashTable *style_table;/* old style styles compatibility */
44 45
} parse_xml_context_t;

46 47 48
/*
 * Internal stuff: xml helper functions.
 */
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
static void
xml_arg_set (GtkArg *arg, gchar *string)
{
	switch (arg->type) {

		case GTK_TYPE_BOOL:
			if (!strcmp (string, "TRUE")) 
				GTK_VALUE_BOOL (*arg) = TRUE;
			else
				GTK_VALUE_BOOL (*arg) = FALSE;
	}
}

static char *
xml_arg_get (GtkArg *arg)
{
	switch (arg->type) {

		case GTK_TYPE_BOOL:
			if (GTK_VALUE_BOOL (*arg))
				return g_strdup ("TRUE");
			else
				return g_strdup ("FALSE");
	}

	return NULL;
}
 
78 79 80
/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
81 82
 *
 * Returns a g_malloc'ed string.  Caller must free.
83
 */
84
static char *
85
xml_value_get (xmlNodePtr node, const char *name)
86
{
87
	char *ret, *val;
88 89
	xmlNodePtr child;

90 91 92 93
	val = (char *) xmlGetProp (node, name);
	if (val != NULL) {
		ret = g_strdup (val);
		xmlFree (val);
Morten Welinder's avatar
Morten Welinder committed
94
		return ret;
95
	}
96 97 98
	child = node->childs;

	while (child != NULL) {
99 100 101 102
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
103 104 105 106 107 108
			val = xmlNodeGetContent(child);
			if (val != NULL) {
				ret = g_strdup (val);
				xmlFree (val);
				return ret;
			}
109
		}
110 111 112 113
		child = child->next;
	}

	return NULL;
114 115
}

116 117 118 119
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
120
static String *
121
xml_get_value_string (xmlNodePtr node, const char *name)
122
{
123
	char *val;
124 125
	String *ret;

126 127 128 129 130
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
131 132
}

133 134 135 136
/*
 * Get an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
137
static int
138
xml_get_value_int (xmlNodePtr node, const char *name, int *val)
139
{
140
	char *ret;
141
	int i;
142
	int res;
143

144
	ret = xml_value_get (node, name);
145
	if (ret == NULL) return 0;
146
	res = sscanf (ret, "%d", &i);
147 148
	g_free (ret);

149 150
	if (res == 1) {
	        *val = i;
151 152 153
		return 1;
	}
	return 0;
154 155
}

156
#if 0
157 158 159 160
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
161
static int
162
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
163
{
164 165
	int res;
	char *ret;
166 167
	float f;

168
	ret = xml_value_get (node, name);
169
	if (ret == NULL) return 0;
170
	res = sscanf (ret, "%f", &f);
171 172
	g_free (ret);

173 174
	if (res == 1) {
	        *val = f;
175 176 177
		return 1;
	}
	return 0;
178
}
179
#endif
180 181 182 183 184

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
185
static int
186
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
187
{
188 189
	int res;
	char *ret;
190

191
	ret = xml_value_get (node, name);
192
	if (ret == NULL) return 0;
193
	res = sscanf (ret, "%lf", val);
194
	g_free (ret);
195

196
	return (res == 1);
197 198
}

199
#if 0
200 201 202
/*
 * Get a set of coodinates for a node, carried as the content of a child.
 */
203
static int
204
xml_get_coordinate (xmlNodePtr node, const char *name, double *x, double *y)
205
{
206 207
	int res;
	char *ret;
208
	float X, Y;
209

210
	ret = xml_value_get (node, name);
211
	if (ret == NULL) return 0;
212
	res = sscanf (ret, "(%lf %lf)", x, y)
213
	g_free (ret);
214 215

	return (res == 2)
216
}
217
#endif
218 219 220 221 222

/*
 * Get a pair of coodinates for a node, carried as the content of a child.
 */

223
static int
224
xml_get_coordinates (xmlNodePtr node, const char *name,
225 226
		   double *x1, double *y1, double *x2, double *y2)
{
227 228
	int res;
	char *ret;
229

230
	ret = xml_value_get (node, name);
231
	if (ret == NULL) return 0;
232
	res = sscanf (ret, "(%lf %lf)(%lf %lf)", x1, y1, x2, y2);
233 234 235
	g_free (ret);

	if (res == 4)
236
		return 1;
237

238
	return 0;
239 240
}

241
#if 0
242 243 244
/*
 * Get a GnomeCanvasPoints for a node, carried as the content of a child.
 */
245
static GnomeCanvasPoints *
246
xml_get_gnome_canvas_points (xmlNodePtr node, const char *name)
247
{
248
	char *val;
249 250 251 252
	GnomeCanvasPoints *ret = NULL;
	int res;
	const char *ptr;
	int index = 0, i;
253
	float coord[20];	/* TODO: must be dynamic !!!! */
254

255
	val = xml_value_get (node, name);
256
	if (val == NULL) return NULL;
257 258 259 260 261
	ptr = val;
	do {
		while ((*ptr) && (*ptr != '('))
			ptr++;
		if (*ptr == 0)
262
			break;
263
		res = sscanf (ptr, "(%lf %lf)", &coord[index], &coord[index + 1]);
264 265 266 267 268
		if (res != 2)
			break;
		index += 2;
		ptr++;
	} while (res > 0);
269
	g_free (val);
270 271 272 273 274 275 276

	if (index >= 2)
		ret = gnome_canvas_points_new (index / 2);
	if (ret == NULL)
		return NULL;
	for (i = 0; i < index; i++)
		ret->coords[i] = coord[i];
277
	return ret;
278
}
279
#endif
280 281 282 283 284

/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
285
static void
286
xml_set_gnome_canvas_points (xmlNodePtr node, const char *name,
287
			     GnomeCanvasPoints *val)
288 289 290
{
	xmlNodePtr child;
	char *str, *base;
291
	char *tstr;
292 293 294 295 296 297
	int i;

	if (val == NULL)
		return;
	if ((val->num_points < 0) || (val->num_points > 5000))
		return;
298
	base = str = g_malloc (val->num_points * 30 * sizeof (char) + 1);
299 300 301
	if (str == NULL)
		return;
	for (i = 0; i < val->num_points; i++){
302 303 304
		sprintf (str, "(%f %f)", val->coords[2 * i],
			 val->coords[2 * i + 1]);
		str += strlen (str);
305
	}
306
	*str = 0;
307 308 309 310 311

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, base);
312
			g_free (base);
313 314 315 316
			return;
		}
		child = child->next;
	}
317 318 319 320

	tstr = xmlEncodeEntitiesReentrant (node->doc, base);
	xmlNewChild (node, NULL, name, tstr);
	if (tstr) xmlFree (tstr);
321
	g_free (base);
322 323
}

324 325 326 327
/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
328 329
static void
xml_set_value (xmlNodePtr node, const char *name, const char *val)
330
{
331
	char *ret;
332 333 334 335
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
336
		xmlFree (ret);
337 338 339 340 341 342 343 344 345 346 347 348
		xmlSetProp (node, name, val);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val);
349 350
}

351 352 353 354
/*
 * Set a String value for a node either carried as an attibute or as
 * the content of a child.
 */
355 356
static void
xml_set_value_string (xmlNodePtr node, const char *name, String *val)
357
{
358
	char *ret;
359 360 361 362
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
363
		xmlFree (ret);
364 365 366 367 368 369 370 371 372 373 374 375
		xmlSetProp (node, name, val->str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val->str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val->str);
376 377
}

378 379 380 381
/*
 * Set an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
382
static void
383
xml_set_value_int (xmlNodePtr node, const char *name, int val)
384
{
385
	char *ret;
386 387 388 389 390 391
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%d", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
392
		xmlFree (ret);
393 394 395 396 397 398 399 400 401 402 403 404
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
405 406
}

407
#if 0
408 409 410 411
/*
 * Set a float value for a node either carried as an attibute or as
 * the content of a child.
 */
412
static void
413
xml_set_value_float (xmlNodePtr node, const char *name, float val)
414
{
415
	char *ret;
416 417 418 419 420 421
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%f", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
422
		xmlFree (ret);
423 424 425 426 427 428 429 430 431 432 433 434
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
435
}
436
#endif
437 438 439 440 441

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
442
static void
443
xml_set_value_double (xmlNodePtr node, const char *name, double val)
444
{
445
	char *ret;
446
	xmlNodePtr child;
447
	char str[101 + DBL_DIG];
448

449 450 451 452
	if (fabs (val) < 1e9 && fabs (val) > 1e-5)
		snprintf (str, 100 + DBL_DIG, "%.*g", DBL_DIG, val);
	else
		snprintf (str, 100 + DBL_DIG, "%f", val);
453

454 455
	ret = xmlGetProp (node, name);
	if (ret != NULL){
456
		xmlFree (ret);
457 458 459 460 461 462 463 464 465 466 467 468
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
469 470
}

471 472 473 474 475
static void
xml_set_print_unit (xmlNodePtr node, const char *name,
		    const PrintUnit * const pu)
{
	xmlNodePtr  child;
Jody Goldberg's avatar
Jody Goldberg committed
476
	char       *txt = "points";
477
	char       *tstr;
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

	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;
	}

497 498 499 500
	tstr = xmlEncodeEntitiesReentrant (node->doc, name);
	child = xmlNewChild (node, NULL, "PrintUnit", tstr);
	if (tstr) xmlFree (tstr);

501
	xml_set_value_double (child, "Points", pu->points);
502 503 504 505

	tstr = xmlEncodeEntitiesReentrant (node->doc, txt);
	xml_set_value (child, "PrefUnit", tstr);
	if (tstr) xmlFree (tstr);
506 507 508 509 510 511
}

static void
xml_get_print_unit (xmlNodePtr node, PrintUnit * const pu)
{
	char       *txt;
512

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	g_return_if_fail (pu != NULL);
	g_return_if_fail (node != NULL);
	g_return_if_fail (node->childs != NULL);

	xml_get_value_double (node, "Points", &pu->points);
	txt = xml_value_get  (node, "PrefUnit");
	if (txt) {
		if (!g_strcasecmp (txt, "points"))
			pu->desired_display = UNIT_POINTS;
		else if (!g_strcasecmp (txt, "mm"))
			pu->desired_display = UNIT_MILLIMETER;
		else if (!g_strcasecmp (txt, "cm"))
			pu->desired_display = UNIT_CENTIMETER;
		else if (!g_strcasecmp (txt, "in"))
			pu->desired_display = UNIT_INCH;
528
		g_free (txt);
529 530 531
	}
}

532
/*
533
 * Search a child by name, if needed go down the tree to find it.
534
 */
535 536
static xmlNodePtr
xml_search_child (xmlNodePtr node, const char *name)
537 538 539 540 541 542 543 544 545 546 547 548
{
	xmlNodePtr ret;
	xmlNodePtr child;

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name))
			return child;
		child = child->next;
	}
	child = node->childs;
	while (child != NULL){
549
		ret = xml_search_child (child, name);
550 551 552 553 554
		if (ret != NULL)
			return ret;
		child = child->next;
	}
	return NULL;
555 556
}

557 558 559
static gboolean
xml_read_range (xmlNodePtr tree, Range *res)
{
Jody Goldberg's avatar
Jody Goldberg committed
560
	return
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	    xml_get_value_int (tree, "startCol", &res->start.col) &&
	    xml_get_value_int (tree, "startRow", &res->start.row) &&
	    xml_get_value_int (tree, "endCol",   &res->end.col) &&
	    xml_get_value_int (tree, "endRow",   &res->end.row);
}

static void
xml_write_range (xmlNodePtr tree, Range *value)
{
	xml_set_value_int (tree, "startCol", value->start.col);
	xml_set_value_int (tree, "startRow", value->start.row);
	xml_set_value_int (tree, "endCol",   value->end.col);
	xml_set_value_int (tree, "endRow",   value->end.row);
}

static void
xml_read_selection_info (parse_xml_context_t *ctxt, Sheet *sheet, xmlNodePtr tree)
{
	Range r;
	int row, col;
	xmlNodePtr sel, selections = xml_search_child (tree, "Selections");
	if (selections == NULL)
		return;

	sheet_selection_reset_only (sheet);
	for (sel = selections->childs; sel; sel = sel->next) {
		if (xml_read_range (sel, &r))
588 589 590 591
			sheet_selection_add_range (sheet,
						   r.start.col, r.start.row,
						   r.start.col, r.start.row,
						   r.end.col, r.end.row);
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
	}

	if (xml_get_value_int (tree, "CursorCol", &col) &&
	    xml_get_value_int (tree, "CursorRow", &row))
		sheet_cursor_set (sheet, col, row, col, row, col, row);
}

static void
xml_write_selection_info (parse_xml_context_t *ctxt, Sheet *sheet, xmlNodePtr tree)
{
	GList *ptr, *copy;
	tree = xmlNewChild (tree, ctxt->ns, "Selections", NULL);

	/* Insert the selections in REVERSE order */
	copy = g_list_copy (sheet->selections);
	ptr = g_list_reverse (copy);
	for (; ptr != NULL ; ptr = ptr->next) {
		SheetSelection *sel = ptr->data;
		xmlNodePtr child = xmlNewChild (tree, ctxt->ns, "Selection", NULL);
		xml_write_range (child, &sel->user);
	}
	g_list_free (copy);

615 616
	xml_set_value_int (tree, "CursorCol", sheet->cursor.edit_pos.col);
	xml_set_value_int (tree, "CursorRow", sheet->cursor.edit_pos.row);
617 618
}

619 620 621 622 623 624 625 626
/*
 * Get a color value for a node either carried as an attibute or as
 * the content of a child.
 *
 * TODO PBM: at parse time one doesn't have yet a widget, so we have
 *           to retrieve the default colormap, but this may be a bad
 *           option ...
 */
627
static int
628
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
629
{
630
	char *ret;
631 632
	int red, green, blue;

633
	ret = xml_value_get (node, name);
634
	if (ret == NULL) return 0;
635
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
636
		*color = style_color_new (red, green, blue);
637
		g_free (ret);
638 639
		return 1;
	}
640
	g_free (ret);
641
	return 0;
642 643 644 645 646 647
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
648 649
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
650
{
651
	char *ret;
652 653 654 655 656 657
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%X:%X:%X", val->color.red, val->color.green, val->color.blue);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
658
		xmlFree (ret);
659 660 661 662 663 664 665 666 667 668 669 670
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
671
}
672 673 674 675 676

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
677
 **/
678

679 680
static int
style_is_default_fore (StyleColor *color)
681
{
682 683
	if (!color)
		return TRUE;
684

685 686 687 688
	if (color->color.red == 0 && color->color.green == 0 && color->color.blue == 0)
		return TRUE;
	else
		return FALSE;
689 690
}

691 692
static int
style_is_default_back (StyleColor *color)
693
{
694 695
	if (!color)
		return TRUE;
696

697 698 699 700
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
701 702 703 704 705
}

/*
 * Create an XML subtree of doc equivalent to the given StyleBorder.
 */
706

Michael Meeks's avatar
Michael Meeks committed
707
static char *StyleSideNames[6] =
708 709 710 711
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
712 713 714
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
715
};
716

717
static xmlNodePtr
718 719
xml_write_style_border (parse_xml_context_t *ctxt,
			const MStyle *style)
720 721 722
{
	xmlNodePtr cur;
	xmlNodePtr side;
723
	int        i;
724

725 726 727
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
728
		    NULL != (border = mstyle_get_border (style, i))) {
Arturo Espinosa's avatar
Arturo Espinosa committed
729
			break;
730
		}
731
	}
732
	if (i > MSTYLE_BORDER_REV_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
733
		return NULL;
734

735
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
736

Michael Meeks's avatar
Michael Meeks committed
737
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
738 739
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
740
		    NULL != (border = mstyle_get_border (style, i))) {
Jody Goldberg's avatar
Jody Goldberg committed
741 742
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
743 744
 			side = xmlNewChild (cur, ctxt->ns,
					    StyleSideNames [i - MSTYLE_BORDER_TOP],
745
 					    NULL);
746
 			xml_set_color_value (side, "Color", col);
747
			xml_set_value_int (side, "Style", t);
748
 		}
749 750
	}
	return cur;
751 752 753 754 755
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
756
static void
757
xml_read_style_border (parse_xml_context_t *ctxt, xmlNodePtr tree, MStyle *mstyle)
758 759
{
	xmlNodePtr side;
760
	int        i;
761 762 763

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
764
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
765 766
			 tree->name);
	}
767

Michael Meeks's avatar
Michael Meeks committed
768
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
769 770
 		if ((side = xml_search_child (tree,
					      StyleSideNames [i - MSTYLE_BORDER_TOP])) != NULL) {
771 772 773 774 775
			int		 t;
			StyleColor      *color = NULL;
			MStyleBorder    *border;
			xml_get_value_int (side, "Style", &t);
			xml_get_color_value (side, "Color", &color);
776
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
777
						     style_border_get_orientation (i));
778 779
			if (border)
				mstyle_set_border (mstyle, i, border);
780
 		}
781
	}
782 783 784 785 786
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
787
static xmlNodePtr
788 789
xml_write_style (parse_xml_context_t *ctxt,
		 MStyle *style)
790
{
791
	xmlNodePtr  cur, child;
792
	char       *tstr;
793

794
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
795

796 797 798 799 800 801 802 803 804 805 806 807
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_H))
		xml_set_value_int (cur, "HAlign", mstyle_get_align_h (style));
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_V))
		xml_set_value_int (cur, "VAlign", mstyle_get_align_v (style));
	if (mstyle_is_element_set (style, MSTYLE_FIT_IN_CELL))
		xml_set_value_int (cur, "Fit", mstyle_get_fit_in_cell (style));
	if (mstyle_is_element_set (style, MSTYLE_ORIENTATION))
		xml_set_value_int (cur, "Orient", mstyle_get_orientation (style));
	if (mstyle_is_element_set (style, MSTYLE_PATTERN))
		xml_set_value_int (cur, "Shade", mstyle_get_pattern (style));

	if (mstyle_is_element_set (style, MSTYLE_COLOR_FORE)) {
808
/*		if (!style_is_default_fore (mstyle_get_color (style, MSTYLE_COLOR_FORE)))*/
809 810 811
			xml_set_color_value (cur, "Fore", mstyle_get_color (style, MSTYLE_COLOR_FORE));
	}
	if (mstyle_is_element_set (style, MSTYLE_COLOR_BACK)) {
812
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_BACK)))*/
813 814
			xml_set_color_value (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
	}
815
	if (mstyle_is_element_set (style, MSTYLE_COLOR_PATTERN)) {
816
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_PATTERN)))*/
817 818
			xml_set_color_value (cur, "PatternColor", mstyle_get_color (style, MSTYLE_COLOR_PATTERN));
	}
819 820 821 822 823 824 825 826 827 828 829 830 831
	if (mstyle_is_element_set (style, MSTYLE_FORMAT))
		xml_set_value (cur, "Format", mstyle_get_format (style)->format);

	if (mstyle_is_element_set (style, MSTYLE_FONT_NAME) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_BOLD) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_ITALIC) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_SIZE)) {
		const char *fontname;

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

833 834 835 836
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, fontname);
		child = xmlNewChild (cur, ctxt->ns, "Font", tstr);
		if (tstr) xmlFree (tstr);

837 838 839 840 841 842 843 844 845
		if (mstyle_is_element_set (style, MSTYLE_FONT_SIZE))
			xml_set_value_double (child, "Unit",
					      mstyle_get_font_size (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_BOLD))
			xml_set_value_int (child, "Bold",
					   mstyle_get_font_bold (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_ITALIC))
			xml_set_value_int (child, "Italic",
					   mstyle_get_font_italic (style));
Jody Goldberg's avatar
Jody Goldberg committed
846 847 848
		if (mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE))
			xml_set_value_int (child, "Underline",
					   (int)mstyle_get_font_uline (style));
849 850 851
		if (mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH))
			xml_set_value_int (child, "StrikeThrough",
					   mstyle_get_font_strike (style));
852 853 854 855 856
	}

	child = xml_write_style_border (ctxt, style);
	if (child)
		xmlAddChild (cur, child);
857 858

	return cur;
859 860
}

861
static xmlNodePtr
862
xml_write_names (parse_xml_context_t *ctxt, GList *names)
863
{
864
	xmlNodePtr  cur;
865
	char       *tstr;
866 867 868 869 870 871 872 873 874 875 876 877 878 879

	if (!names)
		return NULL;

	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Names", NULL);

	while (names) {
		xmlNodePtr   tmp;
		ExprName    *expr_name = names->data;
		char        *text;

		g_return_val_if_fail (expr_name != NULL, NULL);

		tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Name", NULL);
880 881 882
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, expr_name->name->str);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) xmlFree (tstr);
883 884

		text = expr_name_value (expr_name);
885 886 887
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) xmlFree (tstr);
888 889 890 891 892
		g_free (text);

		xmlAddChild (cur, tmp);
		names = g_list_next (names);
	}
893

894 895 896 897
	return cur;
}

static void
898 899
xml_read_names (parse_xml_context_t *ctxt, xmlNodePtr tree, Workbook *wb,
		Sheet *sheet)
900 901 902 903 904 905 906 907
{
	xmlNodePtr child;

	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);

	child = tree->childs;
	while (child) {
908
		char *name  = NULL;
909 910 911 912 913
		if (child->name && !strcmp (child->name, "Name")) {
			xmlNodePtr bits;

			bits = child->childs;
			while (bits) {
914

915 916 917 918 919 920 921 922 923 924 925
				if (!strcmp (bits->name, "name")) {
					name = xmlNodeGetContent (bits);
				} else {
					char     *txt;
					char     *error;
					g_return_if_fail (name != NULL);

					txt = xmlNodeGetContent (bits);
					g_return_if_fail (txt != NULL);
					g_return_if_fail (!strcmp (bits->name, "value"));

926
					if (!expr_name_create (wb, sheet, name, txt, &error))
927 928
						g_warning (error);

Daniel Veillard's avatar
Daniel Veillard committed
929
					xmlFree (txt);
930
				}
931
				bits = bits->next;
932 933 934 935 936 937
			}
		}
		child = child->next;
	}
}

938
static xmlNodePtr
939
xml_write_summary (parse_xml_context_t *ctxt, SummaryInfo *summary_info)
940 941
{
	GList *items, *m;
942
	char *tstr;
943 944
	xmlNodePtr cur;

945
	if (!summary_info)
946 947
		return NULL;

948
	m = items = summary_info_as_list (summary_info);
949 950 951 952 953 954 955 956 957 958 959 960 961

	if (!items)
		return NULL;

	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Summary", NULL);

	while (items) {
		xmlNodePtr   tmp;
		SummaryItem *sit = items->data;
		if (sit) {
			char *text;

			tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Item", NULL);
962 963 964
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, sit->name);
			xmlNewChild (tmp, ctxt->ns, "name", tstr);
			if (tstr) xmlFree (tstr);
965 966 967

			if (sit->type == SUMMARY_INT) {
				text = g_strdup_printf ("%d", sit->v.i);
968 969 970
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-int", tstr);
				if (tstr) xmlFree (tstr);
971 972
			} else {
				text = summary_item_as_text (sit);
973 974 975
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-string", tstr);
				if (tstr) xmlFree (tstr);
976 977
			}
			g_free (text);
978
			xmlAddChild (cur, tmp);
979 980 981 982 983 984 985 986
		}
		items = g_list_next (items);
	}
	g_list_free (m);
	return cur;
}

static void
987
xml_read_summary (parse_xml_context_t *ctxt, xmlNodePtr tree, SummaryInfo *summary_info)
988
{
989
	xmlNodePtr child;
990

991 992 993
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
994 995 996

	child = tree->childs;
	while (child) {
997
		char *name = NULL;
Miguel de Icaza's avatar
Miguel de Icaza committed
998

999 1000 1001 1002 1003 1004
		if (child->name && !strcmp (child->name, "Item")) {
			xmlNodePtr bits;

			bits = child->childs;
			while (bits) {
				SummaryItem *sit = NULL;
1005

1006
				if (!strcmp (bits->name, "name")) {
1007
					name = xmlNodeGetContent (bits);
1008 1009 1010 1011 1012
				} else {
					char *txt;
					g_return_if_fail (name);

					txt = xmlNodeGetContent (bits);
1013 1014 1015 1016
					if (txt != NULL){
						if (!strcmp (bits->name, "val-string"))
							sit = summary_item_new_string (name, txt);
						else if (!strcmp (bits->name, "val-int"))
Miguel de Icaza's avatar
Miguel de Icaza committed
1017
							sit = summary_item_new_int (name, atoi (txt));
1018

1019
						if (sit)
1020
							summary_info_add (summary_info, sit);
Daniel Veillard's avatar
Daniel Veillard committed
1021
						xmlFree (txt);
1022
					}
1023
				}
1024
				bits = bits->next;
1025 1026
			}
		}
Miguel de Icaza's avatar
Miguel de Icaza committed
1027
		if (name){
1028
			xmlFree (name);
Miguel de Icaza's avatar
Miguel de Icaza committed
1029 1030
			name = NULL;
		}
1031 1032 1033 1034
		child = child->next;
	}
}

Michael Meeks's avatar
Michael Meeks committed
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
static void
xml_set_print_hf (xmlNodePtr node, const char *name,
		  const PrintHF * const hf)
{
	xmlNodePtr  child;

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

	child = xmlNewChild (node, NULL, name, NULL);
1045 1046 1047
	xml_set_value (child, "Left", hf->left_format);
	xml_set_value (child, "Middle", hf->middle_format);
	xml_set_value (child, "Right", hf->right_format);
Michael Meeks's avatar
Michael Meeks committed
1048 1049 1050
}

static void
Arturo Espinosa's avatar
Arturo Espinosa committed
1051
xml_get_print_hf (xmlNodePtr node, PrintHF *const hf)
Michael Meeks's avatar
Michael Meeks committed
1052 1053
{
	char *txt;
1054

Michael Meeks's avatar
Michael Meeks committed
1055 1056 1057 1058
	g_return_if_fail (hf != NULL);
	g_return_if_fail (node != NULL);

	txt = xml_value_get (node, "Left");
1059
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1060 1061
		if (hf->left_format)
			g_free (hf->left_format);
1062
		hf->left_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1063
	}
1064

Michael Meeks's avatar
Michael Meeks committed
1065
	txt = xml_value_get (node, "Middle");
1066
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1067 1068
		if (hf->middle_format)
			g_free (hf->middle_format);
1069
		hf->middle_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1070
	}
Michael Meeks's avatar
Michael Meeks committed
1071 1072

	txt = xml_value_get (node, "Right");
1073
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1074 1075
		if (hf->right_format)
			g_free (hf->right_format);
1076
		hf->right_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1077
	}
Michael Meeks's avatar
Michael Meeks committed
1078 1079
}

1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
static xmlNodePtr
xml_write_attributes (parse_xml_context_t *ctxt, guint n_args, GtkArg *args)
{
	xmlNodePtr cur;
	gint i;
	
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Attributes", NULL);

	for (i=0; i < n_args; args++, i++) {
		xmlNodePtr tmp;
		xmlChar *tstr;
		gchar *str;

		tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Attribute", NULL);

		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, args->name);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) {
			xmlFree (tstr);
		}
		
		xmlNewChild (tmp, ctxt->ns, "type", tstr);
		xml_set_value_int (tmp, "type", args->type);
		
		str = xml_arg_get (args);	
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, str);  
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) {
			xmlFree (tstr);
		}
		
		g_free (str);

		xmlAddChild (cur, tmp);
	}

	return cur;
}

static void
xml_free_arg_list (GList *list)
{
	while (list) {
		if (list->data) {
			g_free (list->data);
		}
		list = list->next;
	}
}

static void
xml_read_attributes (parse_xml_context_t *ctxt, xmlNodePtr tree, GList **list)
{
	xmlNodePtr child;
	GtkArg *arg;
	
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (ctxt->wb != NULL);
	
	child = tree->childs;
	while (child) {
		char *name = NULL;
		int type = 0;
		char *value = NULL;
		
		if (child->name && !strcmp (child->name, "Attribute")) {