Patch for TnyGtkTextBufferStream



I'm attaching a patch against tny-gtk-text-buffer-stream.c that
addresses two related problems:

First, the TnyGtkTextBufferStream isn't treating properly non-UTF8
input (in fact, non-UTF8 input could cause a crash).

Second, if a buffer is written to a TnyGtkTextBufferStream divided
into several chunks of bytes (like camel_stream_write_to_stream()
does, for example), chances are that some multibyte UTF-8 characters
are split into two different chunks.

As GtkTextBuffer only admits full UTF-8 chars, this wouldn't work and
those divided UTF-8 chars would be lost.

With this patch, TnyGtkTextBufferStream keeps the trailing bytes of
an input buffer (those that are not full UTF-8 chars) and writes then
with the following buffer.

However if it detects that an input buffer begins with non-UTF-8 text
then in this case it writes it, as there's not much to do about it
anyway.

-- 
Alberto García González
http://people.igalia.com/berto/
Index: libtinymailui-gtk/tny-gtk-text-buffer-stream.c
===================================================================
--- libtinymailui-gtk/tny-gtk-text-buffer-stream.c	(revision 3399)
+++ libtinymailui-gtk/tny-gtk-text-buffer-stream.c	(working copy)
@@ -46,7 +46,7 @@
 {
 	GtkTextBuffer *buffer;
 	GtkTextIter cur;
-
+	GByteArray *pending_bytes;
 };
 
 #define TNY_GTK_TEXT_BUFFER_STREAM_GET_PRIVATE(o)	\
@@ -136,12 +136,30 @@
 {
 	TnyGtkTextBufferStreamPriv *priv = TNY_GTK_TEXT_BUFFER_STREAM_GET_PRIVATE (self);
 	const gchar *end;
+	gint nb_written;
 
-	if (g_utf8_validate (buffer, n, &end))
-		gtk_text_buffer_insert (priv->buffer, &(priv->cur), buffer, (gint)n);
-	else
-		gtk_text_buffer_insert (priv->buffer, &(priv->cur), end, (gint) (end - buffer));
+	g_byte_array_append (priv->pending_bytes, buffer, n);
 
+	/* GtkTextBuffer only accepts full UTF-8 chars, but we might
+	 * receive a single UTF-8 char split into two different
+	 * buffers -see camel_stream_write_to_stream()- so we write
+	 * only the part of the buffer that is valid UTF-8 text and
+	 * leave the rest for later */
+	g_utf8_validate (priv->pending_bytes->data, priv->pending_bytes->len, &end);
+	nb_written = (gint) (end - ((char *) priv->pending_bytes->data));
+
+	/* If the buffer begins with non-UTF8 text it means that it's
+	 * corrupt, so there's not much to do about it: write it anyway.
+	 * (4 is the max length in bytes of a UTF-8 char) */
+	if (nb_written == 0 && priv->pending_bytes->len >= 4) {
+		nb_written = priv->pending_bytes->len;
+	}
+
+	gtk_text_buffer_insert (priv->buffer, &(priv->cur), priv->pending_bytes->data, nb_written);
+
+	/* Leave the unwritten chars in priv->pending_bytes for later */
+	g_byte_array_remove_range (priv->pending_bytes, 0, nb_written);
+
 	return (gssize) n;
 }
 
@@ -154,6 +172,12 @@
 static gint
 tny_gtk_text_buffer_stream_flush_default (TnyStream *self)
 {
+	TnyGtkTextBufferStreamPriv *priv = TNY_GTK_TEXT_BUFFER_STREAM_GET_PRIVATE (self);
+	if (priv->pending_bytes->len > 0) {
+		gtk_text_buffer_insert (priv->buffer, &(priv->cur),
+					priv->pending_bytes->data, priv->pending_bytes->len);
+		g_byte_array_set_size (priv->pending_bytes, 0);
+	}
 	return 0;
 }
 
@@ -211,6 +235,7 @@
 {
 	TnyGtkTextBufferStreamPriv *priv = TNY_GTK_TEXT_BUFFER_STREAM_GET_PRIVATE (self);
 
+	tny_gtk_text_buffer_stream_flush (self);
 	return tny_gtk_text_buffer_stream_reset_priv (priv);
 }
 
@@ -236,6 +261,11 @@
 	g_object_ref (G_OBJECT (buffer));
 	priv->buffer = buffer;
 
+	if (!priv->pending_bytes)
+		priv->pending_bytes = g_byte_array_new ();
+
+	g_byte_array_set_size (priv->pending_bytes, 0);
+
 	tny_gtk_text_buffer_stream_reset_priv (priv);
 
 	return;
@@ -268,6 +298,7 @@
 	TnyGtkTextBufferStreamPriv *priv = TNY_GTK_TEXT_BUFFER_STREAM_GET_PRIVATE (self);
 
 	priv->buffer = NULL;
+	priv->pending_bytes = NULL;
 
 	return;
 }
@@ -278,8 +309,13 @@
 	TnyGtkTextBufferStream *self = (TnyGtkTextBufferStream *)object;	
 	TnyGtkTextBufferStreamPriv *priv = TNY_GTK_TEXT_BUFFER_STREAM_GET_PRIVATE (self);
 
+	if (priv->buffer && priv->pending_bytes)
+		tny_gtk_text_buffer_stream_flush (self);
+
 	if (priv->buffer)
 		g_object_unref (G_OBJECT (priv->buffer));
+	if (priv->pending_bytes)
+		g_byte_array_free (priv->pending_bytes, TRUE);
 
 	(*parent_class->finalize) (object);
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 3399)
+++ ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2008-02-12  Alberto Garcia Gonzalez <agarcia igalia com>
+
+	* libtinymailui-gtk/tny-gtk-text-buffer-stream.c:
+	Write only full UTF-8 characters into the GtkTextBuffer. If an
+	input buffer contains incomplete UTF-8 chars, save those bytes and
+	write them with the following buffer.
+
 2008-02-11  Alberto Garcia Gonzalez <agarcia igalia com>
 
 	* libtinymail-gnomevfs/tny-vfs-stream.c:


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