[libgsf] OLE: fix order of entries when writing ole files.



commit e65f8cf481ee517f1bd1edffae3ab7c5de214139
Author: Morten Welinder <terra gnome org>
Date:   Thu Dec 8 13:16:04 2011 -0500

    OLE: fix order of entries when writing ole files.
    
    The docs are murky and evidently something actually cares about the
    ordering.  See 665712 for details.

 ChangeLog               |   12 ++++++++
 NEWS                    |    1 +
 gsf/gsf-msole-utils.c   |   70 +++++++++++++++++++++++++++++++++++++++++++++++
 gsf/gsf-msole-utils.h   |    6 ++++
 gsf/gsf-outfile-msole.c |   52 +++++++++++++++++++++++-----------
 5 files changed, 124 insertions(+), 17 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index ec4ff79..71e1878 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2011-12-08  Morten Welinder  <terra gnome org>
+
+	* gsf/gsf-msole-utils.c (gsf_msole_sorting_key_new)
+	(gsf_msole_sorting_key_free, gsf_msole_sorting_key_cmp): New
+	functions.
+
+	* gsf/gsf-outfile-msole.c (make_sorting_name): New function.
+	(gsf_outfile_msole_constructor): New function.
+	(gsf_outfile_msole_class_init): Hook up constructor.
+	(GsfOutfileMSOle): Add a key member.
+	(ole_name_cmp): Use gsf_msole_sorting_key_cmp.  Fixes #665712.
+
 2011-12-07  Morten Welinder  <terra gnome org>
 
 	* gsf/gsf-input-memory.c: Drop HAVE_BROKEN_MMAP -- FreeBSD was
diff --git a/NEWS b/NEWS
index ed00342..2212bed 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Morten:
 	* Ensure GsfOutput::name and GsfInput::name notifications.
 	* Cleanup old code.
 	* Drop support for gnome-vfs and bonobo.
+	* Fix ole2 entry sorting based on patch from Junping Zhang.  [#665712]
 
 Vincent Untz:
 	* New installation method for thumbnailer.  [#651187]
diff --git a/gsf/gsf-msole-utils.c b/gsf/gsf-msole-utils.c
index 0881004..07f1e0c 100644
--- a/gsf/gsf-msole-utils.c
+++ b/gsf/gsf-msole-utils.c
@@ -2434,3 +2434,73 @@ gsf_msole_inflate (GsfInput *input, gsf_off_t offset)
 		g_byte_array_append (res, buffer, pos % VBA_COMPRESSION_WINDOW);
 	return res;
 }
+
+
+struct GsfMSOleSortingKey_ {
+	gunichar2 *name;
+	size_t len;
+};
+
+GsfMSOleSortingKey *
+gsf_msole_sorting_key_new (const char *name)
+{
+	GsfMSOleSortingKey *res = g_new (GsfMSOleSortingKey, 1);
+	size_t name_len;
+	const char *p;
+
+	if (!name)
+		name = "";
+	name_len = strlen (name);
+
+	res->name = g_new (gunichar2, name_len + 1);
+	res->len = 0;
+
+	/* This code is a bit like g_utf8_to_utf16.  */
+
+	for (p = name; *p; p = g_utf8_next_char (p)) {
+		gunichar wc =
+			g_utf8_get_char_validated (p, name_len - (p - name));
+		if (wc & 0x80000000)
+			break; /* Something invalid or incomplete */
+		if (wc < 0x10000) {
+			wc = g_unichar_toupper (wc);
+			/* Let's hope no uppercase char is above 0xffff! */
+			res->name[res->len++] = wc;
+		} else {
+			res->name[res->len++] =	(wc - 0x10000) / 0x400 + 0xd800;
+			res->name[res->len++] =	(wc - 0x10000) % 0x400 + 0xdc00;
+		}
+	}
+	res->name[res->len] = 0;
+
+	return res;
+}
+
+void
+gsf_msole_sorting_key_free (GsfMSOleSortingKey *sk)
+{
+	if (sk) {
+		g_free (sk->name);
+		g_free (sk);
+	}
+}
+
+int
+gsf_msole_sorting_key_cmp (const GsfMSOleSortingKey *a,
+			   const GsfMSOleSortingKey *b)
+{
+	long diff;
+	/* According to the docs length is more important than lexical order */
+	if (a->len != b->len)
+		diff = a->len - b->len;
+	else {
+		const gunichar2 *pa = a->name;
+		const gunichar2 *pb = b->name;
+		while (*pa == *pb && *pa)
+			pa++, pb++;
+		diff = *pa - *pb;
+	}
+
+	/* Note, that diff might not fit "int" */
+	return diff > 0 ? +1 : (diff < 0 ? -1 : 0);
+}
diff --git a/gsf/gsf-msole-utils.h b/gsf/gsf-msole-utils.h
index b3e6940..8a9a8ea 100644
--- a/gsf/gsf-msole-utils.h
+++ b/gsf/gsf-msole-utils.h
@@ -49,6 +49,12 @@ GIConv	    gsf_msole_iconv_open_codepage_for_export  (int codepage_to);
 
 GByteArray *gsf_msole_inflate (GsfInput *input, gsf_off_t offset);
 
+typedef struct GsfMSOleSortingKey_ GsfMSOleSortingKey;
+GsfMSOleSortingKey *gsf_msole_sorting_key_new (const char *name);
+void gsf_msole_sorting_key_free (GsfMSOleSortingKey *sk);
+int gsf_msole_sorting_key_cmp (const GsfMSOleSortingKey *a,
+			       const GsfMSOleSortingKey *b);
+
 G_END_DECLS
 
 #endif /* GSF_MSOLE_UTILS_H */
diff --git a/gsf/gsf-outfile-msole.c b/gsf/gsf-outfile-msole.c
index ecd3a00..1681cac 100644
--- a/gsf/gsf-outfile-msole.c
+++ b/gsf/gsf-outfile-msole.c
@@ -24,6 +24,7 @@
 #include <gsf/gsf-outfile-msole.h>
 #include <gsf/gsf-impl-utils.h>
 #include <gsf/gsf-msole-impl.h>
+#include <gsf/gsf-msole-utils.h>
 #include <gsf/gsf-utils.h>
 
 #include <string.h>
@@ -48,6 +49,8 @@ struct _GsfOutfileMSOle {
 	GsfOutput    	*sink;
 	GsfOutfileMSOle	*root;
 
+	GsfMSOleSortingKey *key;
+
 	MSOleOutfileType type;
 	unsigned	 first_block;
 	unsigned	 blocks;
@@ -80,6 +83,9 @@ gsf_outfile_msole_finalize (GObject *obj)
 	GsfOutfileMSOle *ole = GSF_OUTFILE_MSOLE (obj);
 	GsfOutput *output = GSF_OUTPUT (obj);
 
+	gsf_msole_sorting_key_free (ole->key);
+	ole->key = NULL;
+
 	if (!gsf_output_is_closed (output))
 		gsf_output_close (output);
 
@@ -105,6 +111,7 @@ gsf_outfile_msole_finalize (GObject *obj)
 	default :
 		g_warning ("Unknown file type");
 	}
+
 	parent_class->finalize (obj);
 }
 
@@ -565,23 +572,17 @@ ole_register_child (GsfOutfileMSOle *root, GsfOutfileMSOle *child)
 static gint
 ole_name_cmp (GsfOutfileMSOle const *a, GsfOutfileMSOle const *b)
 {
-	/* According to the docs length is more important than lexical order */
-	char const *a_name = gsf_output_name ((GsfOutput const *)a);
-	char const *b_name = gsf_output_name ((GsfOutput const *)b);
-
-	/* be anal */
-	if (a_name == NULL)
-		return (b_name == NULL) ? 0 : -1;
-	else if (b_name == NULL)
-		return 1;
-	else {
-		unsigned a_len = g_utf8_strlen (a_name, -1);
-		unsigned b_len = g_utf8_strlen (b_name, -1);
-
-		if (a_len != b_len)
-			return a_len - b_len;
-		return g_utf8_collate (a_name, b_name);
-	}
+	return gsf_msole_sorting_key_cmp (a->key, b->key);
+}
+
+static void
+make_sorting_name (GsfOutfileMSOle *ole,
+		   G_GNUC_UNUSED GParamSpec *pspec,
+		   G_GNUC_UNUSED gpointer user)
+{
+	const char *name = gsf_output_name (GSF_OUTPUT (ole));
+	gsf_msole_sorting_key_free (ole->key);
+	ole->key = gsf_msole_sorting_key_new (name);
 }
 
 static void
@@ -648,6 +649,22 @@ gsf_outfile_msole_init (GObject *obj)
 	memset (ole->clsid, 0, sizeof (ole->clsid));
 }
 
+static GObject*
+gsf_outfile_msole_constructor (GType                  type,
+			       guint                  n_construct_properties,
+			       GObjectConstructParam *construct_params)
+{
+	GObject *obj = parent_class->constructor (type,
+						  n_construct_properties,
+						  construct_params);
+	GsfOutfileMSOle *ole = (GsfOutfileMSOle *)obj;
+	g_signal_connect (obj,
+			  "notify::name",
+			  G_CALLBACK (make_sorting_name), NULL);
+	make_sorting_name (ole, NULL, NULL);
+	return obj;
+}
+
 static void
 gsf_outfile_msole_class_init (GObjectClass *gobject_class)
 {
@@ -655,6 +672,7 @@ gsf_outfile_msole_class_init (GObjectClass *gobject_class)
 	GsfOutfileClass *outfile_class = GSF_OUTFILE_CLASS (gobject_class);
 
 	gobject_class->finalize		= gsf_outfile_msole_finalize;
+	gobject_class->constructor	= gsf_outfile_msole_constructor;
 	output_class->Close		= gsf_outfile_msole_close;
 	output_class->Seek		= gsf_outfile_msole_seek;
 	output_class->Write		= gsf_outfile_msole_write;



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