[gnumeric] Cut-and-paste: use SaX parser for inter-process cut-and-paste.



commit 4b5741eb843315106b3e0b8dc741530036da8889
Author: Morten Welinder <terra gnome org>
Date:   Tue Sep 22 19:45:21 2009 -0400

    Cut-and-paste: use SaX parser for inter-process cut-and-paste.

 ChangeLog               |    9 +
 NEWS                    |    1 +
 src/gui-clipboard.c     |    9 +-
 src/sheet-control-gui.c |    6 +-
 src/xml-io.c            |    4 +-
 src/xml-io.h            |    4 +-
 src/xml-sax-read.c      |  429 ++++++++++++++++++++++++++++++++++++-----------
 src/xml-sax.h           |    8 +-
 8 files changed, 361 insertions(+), 109 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a63f859..2f107b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,17 @@
 2009-09-22  Morten Welinder  <terra gnome org>
 
+	* src/xml-sax-read.c (xml_cellregion_read): Re-implement in SaX
+	land.  Callers changed to supply extra io_context argument needed.
+	(gnm_xml_in_doc_add_subset): New function.
+	(gnm_xml_finish_obj, xml_sax_style_region_end, xml_sax_merge,
+	xml_sax_cell_content): If needed, add to clipboard, not sheet.
+
 	* src/xml-sax-write.c (gnm_cellregion_to_xml): Close the
 	MergedRegions tag.
 
+	* src/xml-io.c (xml_cellregion_read_dom): Renamed from
+	xml_cellregion_read.
+
 2009-09-22  Jean Brefort  <jean brefort normalesup org>
 
 	* component/Gnumeric-embed.xml.in: synchronize with latest
diff --git a/NEWS b/NEWS
index 9806ba8..bbb3b03 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Jean:
 
 Morten:
 	* Fix inter-process pasting of merged regions.
+	* Make inter-process pasting use the sax parser.
 
 --------------------------------------------------------------------------
 Gnumeric 1.9.13
diff --git a/src/gui-clipboard.c b/src/gui-clipboard.c
index add27d8..4a6c39f 100644
--- a/src/gui-clipboard.c
+++ b/src/gui-clipboard.c
@@ -347,8 +347,13 @@ table_content_received (GtkClipboard *clipboard, GtkSelectionData *sel,
 	} else if (sel->target == gdk_atom_intern (GNUMERIC_ATOM_NAME,
 						   FALSE)) {
 		/* The data is the gnumeric specific XML interchange format */
-		content = xml_cellregion_read (wbc, pt->sheet,
-					       (const char *)sel->data, sel->length);
+		GOIOContext *io_context =
+			go_io_context_new (GO_CMD_CONTEXT (wbcg));
+		content = xml_cellregion_read
+			(wbc, io_context,
+			 pt->sheet,
+			 (const char *)sel->data, sel->length);
+		g_object_unref (io_context);
 	} else if (sel->target == gdk_atom_intern (OOO_ATOM_NAME, FALSE) ||
 		   sel->target == gdk_atom_intern (OOO_ATOM_NAME_WINDOWS, FALSE) ||
 		   sel->target == gdk_atom_intern (OOO11_ATOM_NAME, FALSE)) {
diff --git a/src/sheet-control-gui.c b/src/sheet-control-gui.c
index 77344c1..4124492 100644
--- a/src/sheet-control-gui.c
+++ b/src/sheet-control-gui.c
@@ -3304,8 +3304,12 @@ scg_drag_receive_cellregion (SheetControlGUI *scg, double x, double y,
 			     const char *data, unsigned len)
 {
 	GnmCellRegion *content;
+	GOIOContext *io_context =
+		go_io_context_new (GO_CMD_CONTEXT (scg->wbcg));
 
-	content = xml_cellregion_read (scg_wbc (scg), scg_sheet (scg), data, len);
+	content = xml_cellregion_read (scg_wbc (scg), io_context,
+				       scg_sheet (scg), data, len);
+	g_object_unref (io_context);
 	if (content != NULL) {
 		scg_paste_cellregion (scg, x, y, content);
 		cellregion_unref (content);
diff --git a/src/xml-io.c b/src/xml-io.c
index 48e0e8f..065988d 100644
--- a/src/xml-io.c
+++ b/src/xml-io.c
@@ -2097,7 +2097,7 @@ xml_read_clipboard_cell (XmlParseContext *ctxt, xmlNodePtr tree,
 }
 
 /**
- * xml_clipboard_read :
+ * xml_cellregion_read_dom :
  * @wbc : where to report errors.
  * @buffer : the buffer to parse.
  * @length : the size of the buffer.
@@ -2108,7 +2108,7 @@ xml_read_clipboard_cell (XmlParseContext *ctxt, xmlNodePtr tree,
  * returns a GnmCellRegion on success or NULL on failure.
  */
 GnmCellRegion *
-xml_cellregion_read (WorkbookControl *wbc, Sheet *sheet, const char *buffer, int length)
+xml_cellregion_read_dom (WorkbookControl *wbc, Sheet *sheet, const char *buffer, int length)
 {
 	XmlParseContext *ctxt;
 	xmlNode		*l, *clipboard;
diff --git a/src/xml-io.h b/src/xml-io.h
index 6f493b1..2370085 100644
--- a/src/xml-io.h
+++ b/src/xml-io.h
@@ -39,8 +39,8 @@ XmlParseContext *xml_parse_ctx_new     (xmlDoc		*doc,
 void		 xml_parse_ctx_destroy (XmlParseContext *ctxt);
 
 
-GnmCellRegion *xml_cellregion_read  (WorkbookControl *context, Sheet *sheet,
-				     const char *buffer, int length);
+GnmCellRegion *xml_cellregion_read_dom  (WorkbookControl *context, Sheet *sheet,
+					 const char *buffer, int length);
 
 GnmStyle      *xml_read_style     (XmlParseContext *ctxt, xmlNodePtr tree,
 				   gboolean leave_empty);
diff --git a/src/xml-sax-read.c b/src/xml-sax-read.c
index af7fa1c..f002855 100644
--- a/src/xml-sax-read.c
+++ b/src/xml-sax-read.c
@@ -49,6 +49,7 @@
 #include "selection.h"
 #include "command-context.h"
 #include "workbook-view.h"
+#include "workbook-control.h"
 #include "workbook.h"
 #include "sheet-object-impl.h"
 #include "sheet-object-cell-comment.h"
@@ -59,6 +60,7 @@
 #include "application.h"
 #include "xml-io.h"
 #include "gutils.h"
+#include "clipboard.h"
 
 #include <goffice/goffice.h>
 
@@ -277,6 +279,7 @@ typedef struct {
 	GnumericXMLVersion version;
 	gsf_off_t last_progress_update;
 	GnmConventions *convs;
+	gboolean do_progress;
 
 	Sheet *sheet;
 	double sheet_zoom;
@@ -343,6 +346,8 @@ typedef struct {
 	int sheet_rows, sheet_cols;
 
 	GnmPageBreaks *page_breaks;
+
+	GnmCellRegion *clipboard;
 } XMLSaxParseState;
 
 static void
@@ -352,7 +357,7 @@ maybe_update_progress (GsfXMLIn *xin)
 	GsfInput *input = gsf_xml_in_get_input (xin);
 	gsf_off_t pos = gsf_input_tell (input);
 
-	if (pos >= state->last_progress_update + 10000) {
+	if (state->do_progress && pos >= state->last_progress_update + 10000) {
 		go_io_value_progress_update (state->context, pos);
 		state->last_progress_update = pos;
 	}
@@ -375,8 +380,15 @@ static void
 gnm_xml_finish_obj (GsfXMLIn *xin)
 {
 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
-	sheet_object_set_sheet (state->so, state->sheet);
-	g_object_unref (state->so);
+	GnmCellRegion *cr = state->clipboard;
+
+	if (cr) {
+		cr->objects = g_slist_prepend (cr->objects, state->so);
+	} else {
+		sheet_object_set_sheet (state->so, state->sheet);
+		g_object_unref (state->so);
+	}
+
 	state->so = NULL;
 }
 
@@ -1294,7 +1306,15 @@ xml_sax_style_region_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 	g_return_if_fail (state->style != NULL);
 	g_return_if_fail (state->sheet != NULL);
 
-	if (state->version >= GNM_XML_V6 || state->version <= GNM_XML_V2)
+	if (state->clipboard) {
+		GnmCellRegion *cr = state->clipboard;
+		GnmStyleRegion *sr = g_new (GnmStyleRegion, 1);
+
+		sr->range = state->style_range;
+		sr->style = state->style;
+
+		cr->styles = g_slist_prepend (cr->styles, sr);
+	} else if (state->version >= GNM_XML_V6 || state->version <= GNM_XML_V2)
 		sheet_style_set_range (state->sheet, &state->style_range,
 				       state->style);
 	else
@@ -1760,7 +1780,7 @@ xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
  */
 static void
 xml_cell_set_array_expr (XMLSaxParseState *state,
-			 GnmCell *cell, char const *text,
+			 GnmCell *cell, GnmCellCopy *cc, char const *text,
 			 int const cols, int const rows)
 {
 	GnmParsePos pp;
@@ -1772,10 +1792,15 @@ xml_cell_set_array_expr (XMLSaxParseState *state,
 				    NULL);
 
 	g_return_if_fail (texpr != NULL);
-	gnm_cell_set_array_formula (cell->base.sheet,
-				    cell->pos.col, cell->pos.row,
-				    cell->pos.col + cols-1, cell->pos.row + rows-1,
-				    texpr);
+
+	if (cell)
+		gnm_cell_set_array_formula (cell->base.sheet,
+					    cell->pos.col, cell->pos.row,
+					    cell->pos.col + cols - 1,
+					    cell->pos.row + rows - 1,
+					    texpr);
+	else
+		cc->texpr = texpr;
 }
 
 /**
@@ -1786,7 +1811,8 @@ xml_cell_set_array_expr (XMLSaxParseState *state,
  *     If it is not a member of an array return TRUE.
  */
 static gboolean
-xml_not_used_old_array_spec (XMLSaxParseState *state, GnmCell *cell,
+xml_not_used_old_array_spec (XMLSaxParseState *state,
+			     GnmCell *cell, GnmCellCopy *cc,
 			     char const *content)
 {
 	long rows, cols, row, col;
@@ -1820,7 +1846,8 @@ xml_not_used_old_array_spec (XMLSaxParseState *state, GnmCell *cell,
 
 	if (row == 0 && col == 0) {
 		*expr_end = '\0';
-		xml_cell_set_array_expr (state, cell, content+2, rows, cols);
+		xml_cell_set_array_expr (state, cell, cc,
+					 content + 2, rows, cols);
 	}
 
 	return FALSE;
@@ -1831,8 +1858,12 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 {
 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
 
-	gboolean is_new_cell, is_post_52_array = FALSE;
-	GnmCell *cell;
+	gboolean is_new_cell = FALSE, is_post_52_array = FALSE;
+
+	GnmParsePos pos;
+	GnmCell *cell = NULL; /* Regular case */
+	GnmCellCopy *cc = NULL; /* Clipboard case */
+	GnmCellRegion *cr = state->clipboard;
 
 	int const col = state->cell.col;
 	int const row = state->cell.row;
@@ -1859,12 +1890,21 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 
 	maybe_update_progress (xin);
 
-	cell = sheet_cell_get (state->sheet, col, row);
-	if ((is_new_cell = (cell == NULL)))
-		cell = sheet_cell_create (state->sheet, col, row);
-
-	if (cell == NULL)
-		return;
+	if (cr) {
+		cc = gnm_cell_copy_new (cr,
+					col - cr->base.col,
+					row - cr->base.row);
+		parse_pos_init (&pos, NULL, state->sheet, col, row);
+	} else {
+		cell = sheet_cell_get (state->sheet, col, row);
+		is_new_cell = (cell == NULL);
+		if (is_new_cell) {
+			cell = sheet_cell_create (state->sheet, col, row);
+			if (cell == NULL)
+				return;
+		}
+		parse_pos_init_cell (&pos, cell);
+	}
 
 	is_post_52_array = (array_cols > 0) && (array_rows > 0);
 
@@ -1874,43 +1914,49 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 		if (is_post_52_array) {
 			g_return_if_fail (content[0] == '=');
 
-			xml_cell_set_array_expr (state, cell, content+1,
+			xml_cell_set_array_expr (state, cell, cc, content+1,
 						 array_cols, array_rows);
 		} else if (state->version >= GNM_XML_V3 ||
-			   xml_not_used_old_array_spec (state, cell, content)) {
+			   xml_not_used_old_array_spec (state, cell, cc, content)) {
 			if (value_type > 0) {
 				GnmValue *v = value_new_from_string (value_type, content, value_fmt, FALSE);
 				if (v == NULL) {
 					g_warning ("Unable to parse \"%s\" as type %d.",
 						   content, value_type);
-					gnm_cell_set_text (cell, content);
-				} else
+					v = value_new_string (content);
+				}
+				if (cell)
 					gnm_cell_set_value (cell, v);
+				else
+					cc->val = v;
 			} else {
 				const char *expr_start = gnm_expr_char_start_p (content);
 				if (expr_start && *expr_start) {
 					GnmParseError perr;
-					GnmParsePos pos;
 					GnmExprTop const *texpr;
 
 					parse_error_init (&perr);
 					texpr = gnm_expr_parse_str (expr_start,
-								    parse_pos_init_cell (&pos, cell),
+								    &pos,
 								    GNM_EXPR_PARSE_DEFAULT,
 								    state->convs,
 								    &perr);
-					if (texpr) {
+					if (texpr && cell) {
 						gnm_cell_set_expr (cell, texpr);
 						gnm_expr_top_unref (texpr);
-					} else {
+					} else if (texpr)
+						cc->texpr = texpr;
+					else {
 						g_warning ("Unparsable expression for %s: %s\n",
 							   cell_name (cell),
 							   content);
 						gnm_cell_set_value (cell, value_new_string (content));
 					}
 					parse_error_free (&perr);
-				} else
+				} else if (cell)
 					gnm_cell_set_text (cell, content);
+				else
+					cc->val = value_new_string (content);
 			}
 		}
 
@@ -1919,15 +1965,18 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 			GnmExprTop const *texpr =
 				g_hash_table_lookup (state->expr_map, id);
 			if (texpr == NULL) {
-				if (gnm_cell_has_expr (cell)) {
-					GnmExprTop const *texpr =
-						cell->base.texpr;
+				if (cc)
+					texpr = cc->texpr;
+				else if (gnm_cell_has_expr (cell)) {
+					texpr = cell->base.texpr;
+				} else
+					g_warning ("XML-IO : Shared expression with no expression ??");
+				if (texpr) {
 					gnm_expr_top_ref (texpr);
 					g_hash_table_insert (state->expr_map,
 							     id,
 							     (gpointer)texpr);
-				} else
-					g_warning ("XML-IO : Shared expression with no expression ??");
+				}
 			} else if (!is_post_52_array)
 				g_warning ("XML-IO : Duplicate shared expression");
 		}
@@ -1935,10 +1984,17 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 		GnmExprTop const *texpr = g_hash_table_lookup (state->expr_map,
 			GINT_TO_POINTER (expr_id));
 
-		if (texpr != NULL)
-			gnm_cell_set_expr (cell, texpr);
-		else
+		if (!texpr) {
+			texpr = gnm_expr_top_new_constant (value_new_int (0));
 			g_warning ("XML-IO : Missing shared expression");
+		}
+
+		if (cell)
+			gnm_cell_set_expr (cell, texpr);
+		else {
+			cc->texpr = texpr;
+			gnm_expr_top_ref (texpr);
+		}
 	} else if (is_new_cell)
 		/*
 		 * Only set to empty if this is a new cell.
@@ -1954,13 +2010,21 @@ static void
 xml_sax_merge (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 {
 	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
-
+	GnmCellRegion *cr = state->clipboard;
+	Sheet *sheet = state->sheet;
 	GnmRange r;
+
 	g_return_if_fail (xin->content->len > 0);
 
-	if (range_parse (&r, xin->content->str, gnm_sheet_get_size (state->sheet)))
-		gnm_sheet_merge_add (state->sheet, &r, FALSE,
-			GO_CMD_CONTEXT (state->context));
+	if (range_parse (&r, xin->content->str, gnm_sheet_get_size (sheet))) {
+		if (cr) {
+			cr->merged = g_slist_prepend (cr->merged,
+						      gnm_range_dup (&r));
+		} else {
+			gnm_sheet_merge_add (sheet, &r, FALSE,
+					     GO_CMD_CONTEXT (state->context));
+		}
+	}
 }
 
 static void
@@ -2555,9 +2619,88 @@ GSF_XML_IN_NODE_FULL (START, WB, GNM, "Workbook", GSF_XML_NO_CONTENT, TRUE, TRUE
   GSF_XML_IN_NODE (WB, WB_DATE, GNM, "DateConvention", GSF_XML_CONTENT, NULL, &xml_sax_old_dateconvention),
   GSF_XML_IN_NODE (WB, GODOC, -1, "GODoc", GSF_XML_NO_CONTENT, &xml_sax_go_doc, NULL),
     GSF_XML_IN_NODE (WB, DOCUMENTMETA, OO_NS_OFFICE, "document-meta", GSF_XML_NO_CONTENT, &xml_sax_document_meta, NULL),
-  { NULL }
+  GSF_XML_IN_NODE_END
 };
 
+static void
+xml_sax_clipboardrange_start (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	XMLSaxParseState *state = (XMLSaxParseState *)xin->user_state;
+	int cols = -1, rows = -1, base_col = -1, base_row = -1;
+	GnmCellRegion *cr;
+
+	cr = state->clipboard = cellregion_new (state->sheet);
+
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
+		if (gnm_xml_attr_int (attrs, "Cols", &cols) ||
+		    gnm_xml_attr_int (attrs, "Rows", &rows) ||
+		    gnm_xml_attr_int (attrs, "BaseCol", &base_col) ||
+		    gnm_xml_attr_int (attrs, "BaseRow", &base_row) ||
+		    gnm_xml_attr_bool (attrs, "NotAsContent", &cr->not_as_contents))
+			; /* Nothing */
+		else if (attr_eq (attrs[0], "DateConvention")) {
+			GODateConventions const *date_conv =
+				go_date_conv_from_str (CXML2C (attrs[1]));
+			if (date_conv)
+				cr->date_conv = date_conv;
+			else
+				g_printerr ("Ignoring invalid date conventions.\n");
+		}
+	}
+
+	if (cols <= 0 || rows <= 0 || base_col < 0 || base_row < 0) {
+		g_printerr ("Invalid clipboard contents.\n");
+	} else {
+		cr->cols = cols;
+		cr->rows = rows;
+		cr->base.col = base_col;
+		cr->base.row = base_row;
+	}
+}
+
+static GsfXMLInNode clipboard_dtd[] = {
+	GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
+	GSF_XML_IN_NODE_FULL (START, CLIPBOARDRANGE, GNM, "ClipboardRange", GSF_XML_NO_CONTENT, TRUE, TRUE, xml_sax_clipboardrange_start, NULL, 0),
+	  /* We insert "Styles" (etc) */
+	GSF_XML_IN_NODE_END
+};
+
+static void
+gnm_xml_in_doc_add_subset (GsfXMLInDoc *doc, GsfXMLInNode *dtd,
+			   const char *id, const char *new_parent)
+{
+	GHashTable *parents = g_hash_table_new (g_str_hash, g_str_equal);
+	GsfXMLInNode end_node = GSF_XML_IN_NODE_END;
+	GArray *new_dtd = g_array_new (FALSE, FALSE, sizeof (GsfXMLInNode));
+
+	for (; dtd->id; dtd++) {
+		GsfXMLInNode node = *dtd;
+
+		if (g_str_equal (id, dtd->id)) {
+			g_hash_table_insert (parents,
+					     (gpointer)id,
+					     (gpointer)id);
+			if (new_parent)
+				node.parent_id = new_parent;
+		} else if (g_hash_table_lookup (parents, dtd->parent_id))
+			g_hash_table_insert (parents,
+					     (gpointer)dtd->id,
+					     (gpointer)dtd->id);
+		else
+			continue;
+
+		g_array_append_val (new_dtd, node);
+	}
+
+	g_array_append_val (new_dtd, end_node);
+
+	gsf_xml_in_doc_add_nodes (doc, (GsfXMLInNode*)(new_dtd->data));
+
+	g_array_free (new_dtd, TRUE);
+	g_hash_table_destroy (parents);
+}
+
+
 static gboolean
 xml_sax_unknown (GsfXMLIn *xin, xmlChar const *elem, xmlChar const **attrs)
 {
@@ -2576,6 +2719,124 @@ xml_sax_unknown (GsfXMLIn *xin, xmlChar const *elem, xmlChar const **attrs)
 	return FALSE;
 }
 
+typedef enum {
+	READ_FULL_FILE,
+	READ_CLIPBOARD
+} ReadFileWhat;
+
+static gboolean
+read_file_common (ReadFileWhat what, XMLSaxParseState *state,
+		  GOIOContext *io_context,
+		  WorkbookView *wb_view, Sheet *sheet,
+		  GsfInput *input)
+{
+	GsfXMLInDoc     *doc;
+	GnmLocale       *locale;
+	gboolean         ok;
+
+	g_return_val_if_fail (IS_WORKBOOK_VIEW (wb_view), FALSE);
+	g_return_val_if_fail (GSF_IS_INPUT (input), FALSE);
+
+	/* init */
+	state->context = io_context;
+	state->wb_view = wb_view;
+	state->wb = sheet ? sheet->workbook : wb_view_get_workbook (wb_view);
+	state->sheet = sheet;
+	state->version = GNM_XML_UNKNOWN;
+	state->last_progress_update = 0;
+	state->convs = gnm_xml_io_conventions ();
+	state->attribute.name = state->attribute.value = NULL;
+	state->name.name = state->name.value = state->name.position = NULL;
+	state->style_range_init = FALSE;
+	state->style = NULL;
+	state->cell.row = state->cell.col = -1;
+	state->seen_cell_contents = FALSE;
+	state->array_rows = state->array_cols = -1;
+	state->expr_id = -1;
+	state->value_type = -1;
+	state->value_fmt = NULL;
+	state->filter = NULL;
+	state->validation.title = state->validation.msg = NULL;
+	state->validation.texpr[0] = state->validation.texpr[1] = NULL;
+	state->cond.texpr[0] = state->cond.texpr[1] = NULL;
+	state->cond_save_style = NULL;
+	state->expr_map = g_hash_table_new_full
+		(g_direct_hash, g_direct_equal,
+		 NULL, (GFreeFunc)gnm_expr_top_unref);
+	state->delayed_names = NULL;
+	state->so = NULL;
+	state->page_breaks = NULL;
+	state->clipboard = NULL;
+
+	switch (what) {
+	case READ_FULL_FILE:
+		state->do_progress = TRUE;
+		doc = gsf_xml_in_doc_new (gnumeric_1_0_dtd, content_ns);
+		break;
+	case READ_CLIPBOARD:
+		state->do_progress = FALSE;
+		doc = gsf_xml_in_doc_new (clipboard_dtd, content_ns);
+		if (!doc)
+			break;
+		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
+					   "SHEET_STYLES",
+					   "CLIPBOARDRANGE");
+		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
+					   "SHEET_CELLS",
+					   "CLIPBOARDRANGE");
+		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
+					   "SHEET_MERGED_REGIONS",
+					   "CLIPBOARDRANGE");
+		gnm_xml_in_doc_add_subset (doc, gnumeric_1_0_dtd,
+					   "SHEET_OBJECTS",
+					   "CLIPBOARDRANGE");
+		break;
+	default:
+		g_assert_not_reached ();
+		return FALSE;
+	}
+
+	if (doc == NULL)
+		return FALSE;
+
+	gsf_xml_in_doc_set_unknown_handler (doc, &xml_sax_unknown);
+
+	go_doc_init_read (GO_DOC (state->wb), input);
+	gsf_input_seek (input, 0, G_SEEK_SET);
+
+	if (state->do_progress) {
+		go_io_progress_message (state->context,
+					_("Reading file..."));
+		go_io_value_progress_set (state->context,
+					  gsf_input_size (input), 0);
+	}
+
+	locale = gnm_push_C_locale ();
+	ok = gsf_xml_in_doc_parse (doc, input, state);
+	handle_delayed_names (state);
+	gnm_pop_C_locale (locale);
+
+	go_doc_end_read (GO_DOC (state->wb));
+
+	if (state->do_progress)
+		go_io_progress_unset (state->context);
+
+	if (!ok) {
+		go_io_error_string (state->context,
+				    _("XML document not well formed!"));
+	}
+
+	/* cleanup */
+	g_hash_table_destroy (state->expr_map);
+	gnm_conventions_free (state->convs);
+
+	gsf_xml_in_doc_free (doc);
+
+	return ok;
+}
+
+/* ------------------------------------------------------------------------- */
+
 static GsfInput *
 maybe_gunzip (GsfInput *input)
 {
@@ -2676,84 +2937,52 @@ gnm_xml_file_open (GOFileOpener const *fo, GOIOContext *io_context,
 		   gpointer wb_view, GsfInput *input)
 {
 	XMLSaxParseState state;
-	GsfXMLInDoc     *doc;
-	GnmLocale       *locale;
-	gboolean         ok;
-
-	g_return_if_fail (IS_WORKBOOK_VIEW (wb_view));
-	g_return_if_fail (GSF_IS_INPUT (input));
-
-	doc = gsf_xml_in_doc_new (gnumeric_1_0_dtd, content_ns);
-	if (doc == NULL)
-		return;
-	gsf_xml_in_doc_set_unknown_handler (doc, &xml_sax_unknown);
-
-	/* init */
-	state.context = io_context;
-	state.wb_view = wb_view;
-	state.wb = wb_view_get_workbook (wb_view);
-	state.sheet = NULL;
-	state.version = GNM_XML_UNKNOWN;
-	state.last_progress_update = 0;
-	state.convs = gnm_xml_io_conventions ();
-	state.attribute.name = state.attribute.value = NULL;
-	state.name.name = state.name.value = state.name.position = NULL;
-	state.style_range_init = FALSE;
-	state.style = NULL;
-	state.cell.row = state.cell.col = -1;
-	state.seen_cell_contents = FALSE;
-	state.array_rows = state.array_cols = -1;
-	state.expr_id = -1;
-	state.value_type = -1;
-	state.value_fmt = NULL;
-	state.filter = NULL;
-	state.validation.title = state.validation.msg = NULL;
-	state.validation.texpr[0] = state.validation.texpr[1] = NULL;
-	state.cond.texpr[0] = state.cond.texpr[1] = NULL;
-	state.cond_save_style = NULL;
-	state.expr_map = g_hash_table_new_full
-		(g_direct_hash, g_direct_equal,
-		 NULL, (GFreeFunc)gnm_expr_top_unref);
-	state.delayed_names = NULL;
-	state.so = NULL;
-	state.page_breaks = NULL;
+	gboolean ok;
 
 	g_object_ref (input);
 	input = maybe_gunzip (input);
 	input = maybe_convert (input, FALSE);
-	go_doc_init_read (GO_DOC (state.wb), input);
-	gsf_input_seek (input, 0, G_SEEK_SET);
 
-	go_io_progress_message (state.context, _("Reading file..."));
-	go_io_value_progress_set (state.context, gsf_input_size (input), 0);
-
-	locale = gnm_push_C_locale ();
-	ok = gsf_xml_in_doc_parse (doc, input, &state);
-	handle_delayed_names (&state);
-	gnm_pop_C_locale (locale);
-	go_doc_end_read (GO_DOC (state.wb));
+	ok = read_file_common (READ_FULL_FILE, &state,
+			       io_context, wb_view, NULL,
+			       input);
 
-	go_io_progress_unset (state.context);
+	g_object_unref (input);
 
 	if (ok) {
 		workbook_queue_all_recalc (state.wb);
+
 		workbook_set_saveinfo
 			(state.wb,
 			 GO_FILE_FL_AUTO,
 			 go_file_saver_for_id ("Gnumeric_XmlIO:sax"));
-	} else {
-		go_io_error_string (io_context, _("XML document not well formed!"));
 	}
+}
 
-	g_object_unref (input);
+/* ------------------------------------------------------------------------- */
 
-	/* cleanup */
-	g_hash_table_destroy (state.expr_map);
-	gnm_conventions_free (state.convs);
+GnmCellRegion *
+xml_cellregion_read (WorkbookControl *wbc, GOIOContext *io_context,
+		     Sheet *sheet,
+		     const char *buffer, int length)
+{
+	WorkbookView *wb_view;
+	GsfInput *input;
+	XMLSaxParseState state;
+	gboolean ok;
 
-	gsf_xml_in_doc_free (doc);
+	wb_view = wb_control_view (wbc);
+	input = gsf_input_memory_new (buffer, length, FALSE);
+	ok = read_file_common (READ_CLIPBOARD, &state,
+			       io_context, wb_view, sheet,
+			       input);
+	g_object_unref (input);
+
+	return state.clipboard;
 }
 
+/* ------------------------------------------------------------------------- */
+
 static gboolean
 gnm_xml_probe_element (const xmlChar *name,
 		       G_GNUC_UNUSED const xmlChar *prefix,
diff --git a/src/xml-sax.h b/src/xml-sax.h
index edcbb50..67955e5 100644
--- a/src/xml-sax.h
+++ b/src/xml-sax.h
@@ -21,8 +21,12 @@ SheetObject *gnm_xml_in_cur_obj   (GsfXMLIn const *xin);
 Sheet	    *gnm_xml_in_cur_sheet (GsfXMLIn const *xin);
 
 
-GsfOutputMemory *
-	gnm_cellregion_to_xml	(GnmCellRegion const *cr);
+GsfOutputMemory *gnm_cellregion_to_xml	(GnmCellRegion const *cr);
+
+GnmCellRegion *xml_cellregion_read (WorkbookControl *wbc,
+				    GOIOContext *io_context,
+				    Sheet *sheet,
+				    const char *buffer, int length);
 
 void      gnm_xml_sax_read_init (void);
 void      gnm_xml_sax_write_init (void);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]