[gnumeric] oo_expr_rangeref_parse should also consider possible external workbooks



commit 9bd752a56f577b4a5794140702f896d1ed9ba2c7
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Fri May 27 13:08:09 2011 -0600

    oo_expr_rangeref_parse should also consider possible external workbooks
    
    2011-05-27  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* openoffice-read.c (oo_cellref_parse): add argument, change
    	all callers, don't create sheets that are in foreign workbooks
    	(odf_parse_external): new
    	(oo_rangeref_parse): add argument, change all callers, consider
    	foreign workbooks
    	(oo_conventions_new): add arguments and create augmented conventions
    	(oo_load_convention): add argument, change all callers
    	(oo_col_start): use oo_warning rather than g_warning
    	(odf_clear_conventions): new, use whenever xin changes
    	(opendoc_content_dtd): add table:table-source

 plugins/openoffice/ChangeLog         |   13 +++
 plugins/openoffice/openoffice-read.c |  184 +++++++++++++++++++++++++--------
 2 files changed, 152 insertions(+), 45 deletions(-)
---
diff --git a/plugins/openoffice/ChangeLog b/plugins/openoffice/ChangeLog
index 7d59d6e..365f709 100644
--- a/plugins/openoffice/ChangeLog
+++ b/plugins/openoffice/ChangeLog
@@ -1,3 +1,16 @@
+2011-05-27  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* openoffice-read.c (oo_cellref_parse): add argument, change
+	all callers, don't create sheets that are in foreign workbooks
+	(odf_parse_external): new
+	(oo_rangeref_parse): add argument, change all callers, consider
+	foreign workbooks
+	(oo_conventions_new): add arguments and create augmented conventions
+	(oo_load_convention): add argument, change all callers
+	(oo_col_start): use oo_warning rather than g_warning
+	(odf_clear_conventions): new, use whenever xin changes
+	(opendoc_content_dtd): add table:table-source
+	
 2011-05-22  Morten Welinder  <terra gnome org>
 
 	* openoffice-write.c (odf_write_ooo_settings): Plug leak.
diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c
index f4f2692..acb7340 100644
--- a/plugins/openoffice/openoffice-read.c
+++ b/plugins/openoffice/openoffice-read.c
@@ -372,6 +372,12 @@ typedef struct {
 } OOParseState;
 
 typedef struct {
+	GnmConventions base;
+	OOParseState *state;
+	GsfXMLIn *xin;
+} ODFConventions;
+
+typedef struct {
 	GOColor from;
 	GOColor to;
 	gnm_float brightness;
@@ -384,6 +390,9 @@ static GsfXMLInNode const * get_dtd (void);
 static GsfXMLInNode const * get_styles_dtd (void);
 static void oo_chart_style_free (OOChartStyle *pointer);
 static OOFormula odf_get_formula_type (GsfXMLIn *xin, char const **str);
+static char const *odf_strunescape (char const *string, GString *target,
+				    G_GNUC_UNUSED GnmConventions const *convs);
+
 
 /* Implementations */
 static void
@@ -1068,7 +1077,8 @@ oo_cellref_check_for_err (GnmCellRef *ref, char const **start)
 }
 
 static char const *
-oo_cellref_parse (GnmCellRef *ref, char const *start, GnmParsePos const *pp)
+oo_cellref_parse (GnmCellRef *ref, char const *start, GnmParsePos const *pp,
+		  gchar **foreign_sheet)
 {
 	char const *tmp, *ptr = start;
 	GnmSheetSize const *ss;
@@ -1120,18 +1130,24 @@ two_quotes :
 		if (name[0] == 0)
 			return start;
 
-		/* OpenCalc does not pre-declare its sheets, but it does have a
-		 * nice unambiguous format.  So if we find a name that has not
-		 * been added yet add it.  Reorder below. */
-		ref->sheet = workbook_sheet_by_name (pp->wb, name);
-		if (ref->sheet == NULL) {
-			if (strcmp (name, "#REF!") == 0) {
-				ref->sheet = invalid_sheet;
-			} else {
-				/* We can't add it yet since this whole ref */
-				/* may be invalid */
-				new_sheet_name = g_strdup (name);
-				ref->sheet = NULL;
+		if (foreign_sheet != NULL) {
+			/* This is a reference to a foreign workbook */
+			*foreign_sheet = g_strdup (name);
+			ref->sheet = NULL;
+		} else {
+			/* OpenCalc does not pre-declare its sheets, but it does have a
+			 * nice unambiguous format.  So if we find a name that has not
+			 * been added yet add it.  Reorder below. */
+			ref->sheet = workbook_sheet_by_name (pp->wb, name);
+			if (ref->sheet == NULL) {
+				if (strcmp (name, "#REF!") == 0) {
+					ref->sheet = invalid_sheet;
+				} else {
+					/* We can't add it yet since this whole ref */
+					/* may be invalid */
+					new_sheet_name = g_strdup (name);
+					ref->sheet = NULL;
+				}
 			}
 		}
 	} else {
@@ -1167,7 +1183,7 @@ two_quotes :
 	sheet = eval_sheet (ref->sheet, pp->sheet);
 	ss = gnm_sheet_get_size (sheet);
 
-	if (ss->max_cols <= ref->col || ss->max_rows <= ref->row) {
+	if (foreign_sheet == NULL && (ss->max_cols <= ref->col || ss->max_rows <= ref->row)) {
 		int new_cols = ref->col + 1, new_rows = ref->row + 1;
 		GOUndo   * goundo;
 		gboolean err;
@@ -1190,21 +1206,69 @@ two_quotes :
 }
 
 static char const *
-oo_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp)
+odf_parse_external (char const *start, gchar **external,
+		    GnmConventions const *convs)
+{
+	char const *ptr;
+	GString *str;
+
+	/* Source ::= "'" IRI "'" "#" */
+	if (*start != '\'')
+		return start;
+	str = g_string_new (NULL);
+	ptr = odf_strunescape (start, str, convs);
+
+	if (ptr == NULL || *ptr != '#') {
+		g_string_free (str, TRUE);
+		return start;
+	}
+
+	*external = g_string_free (str, FALSE);
+	return (ptr + 1);
+}
+
+static char const *
+oo_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp,
+		   GnmConventions const *convs)
 {
-	char const *ptr = oo_cellref_parse (&ref->a, start, pp);
+	char const *ptr;
+	char *external = NULL;
+	char *external_sheet_1 = NULL;
+	char *external_sheet_2 = NULL;
+	ODFConventions *oconv = (ODFConventions *)convs;
+
+	ptr = odf_parse_external (start, &external, convs);
+
+	ptr = oo_cellref_parse (&ref->a, ptr, pp, 
+				external == NULL ? NULL : &external_sheet_1);
 	if (*ptr == ':')
-		ptr = oo_cellref_parse (&ref->b, ptr+1, pp);
+		ptr = oo_cellref_parse (&ref->b, ptr+1, pp, 
+				external == NULL ? NULL : &external_sheet_2);
 	else
 		ref->b = ref->a;
 	if (ref->b.sheet == invalid_sheet)
 		ref->a.sheet = invalid_sheet;
+	if (external != NULL) {
+		ref->a.sheet = invalid_sheet;
+		if (oconv != NULL)
+			oo_warning (oconv->xin, 
+				    _("Ignoring reference to external "
+				      "workbook '%s'"), 
+				    external);
+		else
+			g_warning (_("Ignoring reference to external "
+				     "workbook '%s'"), 
+				    external);
+		g_free (external);
+		g_free (external_sheet_1);
+		g_free (external_sheet_2);
+	}
 	return ptr;
 }
 
 static char const *
 oo_expr_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp,
-			G_GNUC_UNUSED GnmConventions const *convs)
+			GnmConventions const *convs)
 {
 	char const *ptr;
 	if (*start == '[') {
@@ -1212,7 +1276,7 @@ oo_expr_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *
 			ref->a.sheet = invalid_sheet;
 			return start + 7;
 		}
-		ptr = oo_rangeref_parse (ref, start+1, pp);
+		ptr = oo_rangeref_parse (ref, start+1, pp, convs);
 		if (*ptr == ']')
 			return ptr + 1;
 	}
@@ -1399,10 +1463,11 @@ oo_func_map_in (GnmConventions const *convs, Workbook *scope,
 		char const *name, GnmExprList *args);
 
 static GnmConventions *
-oo_conventions_new (void)
+oo_conventions_new (OOParseState *state, GsfXMLIn *xin)
 {
-	GnmConventions *conv = gnm_conventions_new ();
-
+	GnmConventions *conv = gnm_conventions_new_full 
+		(sizeof (ODFConventions));
+	ODFConventions *oconv = (ODFConventions *)conv;
 	conv->decode_ampersands	= TRUE;
 	conv->exp_is_left_associative = TRUE;
 
@@ -1417,12 +1482,14 @@ oo_conventions_new (void)
 	conv->input.range_ref	= oo_expr_rangeref_parse;
 	conv->input.name_validate    = odf_expr_name_validate;
 	conv->sheet_name_sep	= '.';
+	oconv->state            = state;
+	oconv->xin              = xin;
 
 	return conv;
 }
 
 static void
-oo_load_convention (OOParseState *state, OOFormula type)
+oo_load_convention (OOParseState *state, GsfXMLIn *xin, OOFormula type)
 {
 	GnmConventions *convs;
 
@@ -1434,13 +1501,13 @@ oo_load_convention (OOParseState *state, OOFormula type)
 		convs->exp_is_left_associative = TRUE;
 		break;
 	case FORMULA_OLD_OPENOFFICE:
-		convs = oo_conventions_new ();
+		convs = oo_conventions_new (state, xin);
 		convs->sheet_name_sep	= '!'; /* Note that we are using this also as a marker*/
 		                               /* in the function handlers */
 		break;
 	case FORMULA_OPENFORMULA:
 	default:
-		convs = oo_conventions_new ();
+		convs = oo_conventions_new (state, xin);
 		break;
 	}
 
@@ -1455,7 +1522,7 @@ oo_expr_parse_str_try (GsfXMLIn *xin, char const *str,
 	OOParseState *state = (OOParseState *)xin->user_state;
 
 	if (state->convs[type] == NULL)
-		oo_load_convention (state, type);
+		oo_load_convention (state, xin, type);
 	return gnm_expr_parse_str (str, pp, flags,
 				    state->convs[type], perr);
 }
@@ -2192,8 +2259,8 @@ oo_col_start (GsfXMLIn *xin, xmlChar const **attrs)
 		max_cols = oo_extent_sheet_cols (state->pos.sheet, state->pos.eval.col
 						 + repeat_count);
 		if (state->pos.eval.col + repeat_count > max_cols) {
-			g_warning ("Ignoring column information beyond"
-				   " the range we can handle.");
+			oo_warning (xin, _("Ignoring column information beyond"
+					   " column %i"), max_cols);
 			repeat_count = max_cols - state->pos.eval.col - 1;
 		}
 	}
@@ -5234,10 +5301,11 @@ oo_db_range_start (GsfXMLIn *xin, xmlChar const **attrs)
 
 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
 		if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_TABLE, "target-range-address")) {
-			char const *ptr = oo_cellref_parse (&ref.a, CXML2C (attrs[1]), &state->pos);
+			char const *ptr = oo_cellref_parse 
+				(&ref.a, CXML2C (attrs[1]), &state->pos, NULL);
 			if (ref.a.sheet != invalid_sheet &&
 			    ':' == *ptr &&
-			    '\0' == *oo_cellref_parse (&ref.b, ptr+1, &state->pos) &&
+			    '\0' == *oo_cellref_parse (&ref.b, ptr+1, &state->pos, NULL) &&
 			    ref.b.sheet != invalid_sheet) {
 				state->filter = gnm_filter_new 
 					(ref.a.sheet, range_init_rangeref (&r, &ref));
@@ -5556,7 +5624,8 @@ od_draw_control_start (GsfXMLIn *xin, xmlChar const **attrs)
 				GnmRangeRef ref;
 				char const *ptr = oo_rangeref_parse
 					(&ref, oc->linked_cell,
-					 parse_pos_init_sheet (&pp, state->pos.sheet));
+					 parse_pos_init_sheet (&pp, state->pos.sheet),
+					 NULL);
 				if (ptr != oc->linked_cell 
 				    && ref.a.sheet != invalid_sheet) {
 					GnmValue *v = value_new_cellrange
@@ -5594,7 +5663,8 @@ od_draw_control_start (GsfXMLIn *xin, xmlChar const **attrs)
 					GnmRangeRef ref;
 					char const *ptr = oo_rangeref_parse
 						(&ref, oc->source_cell_range,
-						 parse_pos_init_sheet (&pp, state->pos.sheet));
+						 parse_pos_init_sheet (&pp, state->pos.sheet),
+						 NULL);
 					if (ptr != oc->source_cell_range && 
 					    ref.a.sheet != invalid_sheet) {
 						GnmValue *v = value_new_cellrange
@@ -5631,6 +5701,17 @@ pop_hash (GSList **list, GHashTable **hash)
 }
 
 static void
+odf_clear_conventions (OOParseState *state)
+{
+	gint i;
+	for (i = 0; i < NUM_FORMULAE_SUPPORTED; i++)
+		if (state->convs[i] != NULL) {
+			gnm_conventions_unref (state->convs[i]);
+			state->convs[i] = NULL;
+		}
+}
+
+static void
 od_draw_object (GsfXMLIn *xin, xmlChar const **attrs)
 {
 	OOParseState *state = (OOParseState *)xin->user_state;
@@ -5717,8 +5798,10 @@ od_draw_object (GsfXMLIn *xin, xmlChar const **attrs)
 	if (content != NULL) {
 		GsfXMLInDoc *doc =
 			gsf_xml_in_doc_new (get_styles_dtd (), gsf_ooo_ns);
+		odf_clear_conventions (state); /* contain references to xin */
 		gsf_xml_in_doc_parse (doc, content, state);
 		gsf_xml_in_doc_free (doc);
+		odf_clear_conventions (state); /* contain references to xin */
 		g_object_unref (content);
 	}
 
@@ -5726,8 +5809,10 @@ od_draw_object (GsfXMLIn *xin, xmlChar const **attrs)
 	if (content != NULL) {
 		GsfXMLInDoc *doc =
 			gsf_xml_in_doc_new (get_dtd (), gsf_ooo_ns);
+		odf_clear_conventions (state); /* contain references to xin */
 		gsf_xml_in_doc_parse (doc, content, state);
 		gsf_xml_in_doc_free (doc);
+		odf_clear_conventions (state); /* contain references to xin */
 		g_object_unref (content);
 	}
 	if (state->debug)
@@ -6064,8 +6149,10 @@ oo_plot_assign_dim (GsfXMLIn *xin, xmlChar const *range, int dim_type, char cons
 
 	if (NULL != range) {
 		GnmRangeRef ref;
-		char const *ptr = oo_rangeref_parse (&ref, CXML2C (range),
-			parse_pos_init_sheet (&pp, state->pos.sheet));
+		char const *ptr = oo_rangeref_parse 
+			(&ref, CXML2C (range),
+			 parse_pos_init_sheet (&pp, state->pos.sheet),
+			 NULL);
 		if (ptr == CXML2C (range) || ref.a.sheet == invalid_sheet)
 			return;
 		v = value_new_cellrange (&ref.a, &ref.b, 0, 0);
@@ -6201,8 +6288,9 @@ oo_plot_area (GsfXMLIn *xin, xmlChar const **attrs)
 		GnmEvalPos  ep;
 		GnmRangeRef ref;
 		Sheet	   *dummy;
-		char const *ptr = oo_rangeref_parse (&ref, CXML2C (source_range_str),
-			parse_pos_init_sheet (&pp, state->pos.sheet));
+		char const *ptr = oo_rangeref_parse 
+			(&ref, CXML2C (source_range_str),
+			 parse_pos_init_sheet (&pp, state->pos.sheet), NULL);
 		if (ptr != CXML2C (source_range_str) 
 		    && ref.a.sheet != invalid_sheet) {
 			gnm_rangeref_normalize (&ref,
@@ -6406,8 +6494,11 @@ oo_plot_series (GsfXMLIn *xin, xmlChar const **attrs)
 					GnmValue *v;
 					GnmExprTop const *texpr;
 					GnmParsePos pp;
-					char const *ptr = oo_rangeref_parse (&ref, CXML2C (attrs[1]),
-									     parse_pos_init_sheet (&pp, state->pos.sheet));
+					char const *ptr = oo_rangeref_parse 
+						(&ref, CXML2C (attrs[1]),
+						 parse_pos_init_sheet 
+						 (&pp, state->pos.sheet),
+						 NULL);
 					if (ptr == CXML2C (attrs[1]) || 
 					    ref.a.sheet == invalid_sheet)
 						return;
@@ -6454,7 +6545,8 @@ oo_plot_series (GsfXMLIn *xin, xmlChar const **attrs)
 			GnmRangeRef ref;
 			char const *ptr = oo_rangeref_parse
 				(&ref, CXML2C (label),
-				 parse_pos_init_sheet (&pp, state->pos.sheet));
+				 parse_pos_init_sheet (&pp, state->pos.sheet),
+				 NULL);
 			if (ptr == CXML2C (label) 
 			    || ref.a.sheet == invalid_sheet)
 				texpr = oo_expr_parse_str (xin, label,
@@ -6644,7 +6736,8 @@ odf_store_data (OOParseState *state, gchar const *str, GogObject *obj, int dim)
 		GnmRangeRef ref;
 		char const *ptr = oo_rangeref_parse
 			(&ref, CXML2C (str),
-			 parse_pos_init (&pp, state->pos.wb, NULL, 0, 0));
+			 parse_pos_init (&pp, state->pos.wb, NULL, 0, 0),
+			 NULL);
 		if (ptr != CXML2C (str) && ref.a.sheet != invalid_sheet) {
 			GnmValue *v = value_new_cellrange (&ref.a, &ref.b, 0, 0);
 			GnmExprTop const *texpr = gnm_expr_top_new_constant (v);
@@ -7110,7 +7203,8 @@ odf_line (GsfXMLIn *xin, xmlChar const **attrs)
 			GnmRangeRef ref;
 			char const *ptr = oo_rangeref_parse
 				(&ref, CXML2C (attrs[1]),
-				 parse_pos_init_sheet (&pp, state->pos.sheet));
+				 parse_pos_init_sheet (&pp, state->pos.sheet),
+				 NULL);
 			if (ptr != CXML2C (attrs[1]) 
 			    && ref.a.sheet != invalid_sheet) {
 				cell_base.end.col = ref.a.col;
@@ -8097,6 +8191,7 @@ static GsfXMLInNode const opendoc_content_dtd [] =
 	        GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_OOO_COORDINATE_REGION, OO_NS_CHART_OOO, "coordinate-region", GSF_XML_NO_CONTENT, NULL, NULL),
 #endif
 	    GSF_XML_IN_NODE (SPREADSHEET, TABLE, OO_NS_TABLE, "table", GSF_XML_NO_CONTENT, &oo_table_start, &oo_table_end),
+	      GSF_XML_IN_NODE (TABLE, TABLE_SOURCE, OO_NS_TABLE, "table-source", GSF_XML_NO_CONTENT, NULL, NULL),
 	      GSF_XML_IN_NODE (TABLE, FORMS, OO_NS_OFFICE, "forms", GSF_XML_NO_CONTENT, NULL, NULL),
 	        GSF_XML_IN_NODE (FORMS, FORM, OO_NS_FORM, "form", GSF_XML_NO_CONTENT, NULL, NULL),
 	          GSF_XML_IN_NODE (FORM, FORM_PROPERTIES, OO_NS_FORM, "properties", GSF_XML_NO_CONTENT, NULL, NULL),
@@ -9156,6 +9251,7 @@ openoffice_file_open (GOFileOpener const *fo, GOIOContext *io_context,
 		GsfXMLInDoc *doc = gsf_xml_in_doc_new (styles_dtd, gsf_ooo_ns);
 		gsf_xml_in_doc_parse (doc, styles, &state);
 		gsf_xml_in_doc_free (doc);
+		odf_clear_conventions (&state); /* contain references to xin */
 		g_object_unref (styles);
 	}
 
@@ -9203,6 +9299,7 @@ openoffice_file_open (GOFileOpener const *fo, GOIOContext *io_context,
 				(opendoc_settings_dtd, gsf_ooo_ns);
 			gsf_xml_in_doc_parse (sdoc, settings, &state);
 			gsf_xml_in_doc_free (sdoc);
+			odf_clear_conventions (&state); /* contain references to xin */
 			g_object_unref (settings);
 		}
 		if (state.settings.stack != NULL) {
@@ -9236,6 +9333,7 @@ openoffice_file_open (GOFileOpener const *fo, GOIOContext *io_context,
 	} else
 		go_io_error_string (io_context, _("XML document not well formed!"));
 	gsf_xml_in_doc_free (doc);
+	odf_clear_conventions (&state);
 
 	go_io_progress_unset (state.context);
 	g_free (state.last_error);
@@ -9271,10 +9369,6 @@ openoffice_file_open (GOFileOpener const *fo, GOIOContext *io_context,
 		sheet_flag_recompute_spans (workbook_sheet_by_index (state.pos.wb, i));
 	workbook_queue_all_recalc (state.pos.wb);
 
-	for (i = 0; i < NUM_FORMULAE_SUPPORTED; i++)
-		if (state.convs[i] != NULL)
-			gnm_conventions_unref (state.convs[i]);
-
 	gnm_pop_C_locale (locale);
 }
 



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