[gedit] Fix issue with windows line endings and chunk read
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gedit] Fix issue with windows line endings and chunk read
- Date: Sat, 30 Oct 2010 11:36:19 +0000 (UTC)
commit 6996dea67a9ca786cd8411d50b914e359f5522c8
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Tue Oct 19 00:14:34 2010 +0200
Fix issue with windows line endings and chunk read
The issue occurs when a \r\n is present exactly on the chunk size boundary. This
means that first a \r will be inserted in the buffer, and with a separate insert
a \n. GtkTextBuffer handles this as two separate lines, leaving us with an
additional unwanted newline. Fixes #626739.
gedit/gedit-document-output-stream.c | 123 +++++++++++++++++++++++++++++-----
tests/document-output-stream.c | 33 +++++++++
2 files changed, 138 insertions(+), 18 deletions(-)
---
diff --git a/gedit/gedit-document-output-stream.c b/gedit/gedit-document-output-stream.c
index 2dbd05d..9212828 100644
--- a/gedit/gedit-document-output-stream.c
+++ b/gedit/gedit-document-output-stream.c
@@ -60,15 +60,19 @@ enum
G_DEFINE_TYPE (GeditDocumentOutputStream, gedit_document_output_stream, G_TYPE_OUTPUT_STREAM)
-static gssize gedit_document_output_stream_write (GOutputStream *stream,
- const void *buffer,
- gsize count,
- GCancellable *cancellable,
- GError **error);
+static gssize gedit_document_output_stream_write (GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
-static gboolean gedit_document_output_stream_close (GOutputStream *stream,
- GCancellable *cancellable,
- GError **error);
+static gboolean gedit_document_output_stream_close (GOutputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+static gboolean gedit_document_output_stream_flush (GOutputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
static void
gedit_document_output_stream_set_property (GObject *object,
@@ -155,6 +159,7 @@ gedit_document_output_stream_class_init (GeditDocumentOutputStreamClass *klass)
stream_class->write_fn = gedit_document_output_stream_write;
stream_class->close_fn = gedit_document_output_stream_close;
+ stream_class->flush = gedit_document_output_stream_flush;
g_object_class_install_property (object_class,
PROP_DOCUMENT,
@@ -273,7 +278,7 @@ end_append_text_to_document (GeditDocumentOutputStream *stream)
remove_ending_newline (stream);
gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (stream->priv->doc),
- FALSE);
+ FALSE);
gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (stream->priv->doc));
}
@@ -294,7 +299,9 @@ gedit_document_output_stream_write (GOutputStream *stream,
gboolean valid;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ {
return -1;
+ }
ostream = GEDIT_DOCUMENT_OUTPUT_STREAM (stream);
@@ -304,7 +311,8 @@ gedit_document_output_stream_write (GOutputStream *stream,
gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (ostream->priv->doc));
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (ostream->priv->doc),
- &ostream->priv->pos);
+ &ostream->priv->pos);
+
ostream->priv->is_initialized = TRUE;
}
@@ -312,12 +320,17 @@ gedit_document_output_stream_write (GOutputStream *stream,
{
len = ostream->priv->buflen + count;
text = g_new (gchar , len + 1);
+
memcpy (text, ostream->priv->buffer, ostream->priv->buflen);
memcpy (text + ostream->priv->buflen, buffer, count);
+
text[len] = '\0';
+
g_free (ostream->priv->buffer);
+
ostream->priv->buffer = NULL;
ostream->priv->buflen = 0;
+
freetext = TRUE;
}
else
@@ -345,32 +358,103 @@ gedit_document_output_stream_write (GOutputStream *stream,
}
else
{
- /* TODO: we cuould escape invalid text and tag it in red
+ /* TODO: we could escape invalid text and tag it in red
* and make the doc readonly.
*/
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
- _("Invalid UTF-8 sequence in input"));
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Invalid UTF-8 sequence in input"));
if (freetext)
+ {
g_free (text);
+ }
return -1;
}
}
+ else
+ {
+ gchar *ptr;
+
+ /* Note: this is a workaround for a 'bug' in GtkTextBuffer where
+ inserting first a \r and then in a second insert, a \n,
+ will result in two lines being added instead of a single
+ one */
+
+ ptr = g_utf8_find_prev_char (text, text + len);
+
+ if (ptr && *ptr == '\r' && ptr - text == len - 1)
+ {
+ ostream->priv->buffer = g_new (gchar, 1);
+ ostream->priv->buffer[0] = '\r';
+ ostream->priv->buflen = 1;
+
+ --len;
+ }
+ }
gtk_text_buffer_insert (GTK_TEXT_BUFFER (ostream->priv->doc),
- &ostream->priv->pos, text, len);
+ &ostream->priv->pos,
+ text,
+ len);
if (freetext)
+ {
g_free (text);
+ }
return count;
}
static gboolean
+gedit_document_output_stream_flush (GOutputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GeditDocumentOutputStream *ostream;
+
+ ostream = GEDIT_DOCUMENT_OUTPUT_STREAM (stream);
+
+ if (ostream->priv->is_closed)
+ {
+ return TRUE;
+ }
+
+ if (ostream->priv->buflen == 0)
+ {
+ return TRUE;
+ }
+ else if (ostream->priv->buflen == 1 && *ostream->priv->buffer == '\r')
+ {
+ /* See special case above, flush this */
+ gtk_text_buffer_insert (GTK_TEXT_BUFFER (ostream->priv->doc),
+ &ostream->priv->pos,
+ "\r",
+ 1);
+
+ g_free (ostream->priv->buffer);
+ ostream->priv->buffer = NULL;
+ ostream->priv->buflen = 0;
+
+ return TRUE;
+ }
+ else
+ {
+ /* Conversion error */
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Incomplete UTF-8 sequence in input"));
+
+ return FALSE;
+ }
+}
+
+static gboolean
gedit_document_output_stream_close (GOutputStream *stream,
- GCancellable *cancellable,
- GError **error)
+ GCancellable *cancellable,
+ GError **error)
{
GeditDocumentOutputStream *ostream = GEDIT_DOCUMENT_OUTPUT_STREAM (stream);
@@ -382,8 +466,11 @@ gedit_document_output_stream_close (GOutputStream *stream,
if (ostream->priv->buflen > 0)
{
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
- _("Incomplete UTF-8 sequence in input"));
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Incomplete UTF-8 sequence in input"));
+
return FALSE;
}
diff --git a/tests/document-output-stream.c b/tests/document-output-stream.c
index 57d42c6..eb9acf7 100644
--- a/tests/document-output-stream.c
+++ b/tests/document-output-stream.c
@@ -56,6 +56,10 @@ test_consecutive_write (const gchar *inbuf,
n += w;
} while (w != 0);
+ g_output_stream_flush (out, NULL, &err);
+
+ g_assert_no_error (err);
+
g_object_get (G_OBJECT (doc), "text", &b, NULL);
g_assert_cmpstr (inbuf, ==, b);
@@ -116,6 +120,34 @@ test_big_char ()
GEDIT_DOCUMENT_NEWLINE_TYPE_LF);
}
+static void
+test_boundary ()
+{
+ GeditDocument *doc;
+ GOutputStream *out;
+ gint line_count;
+ GError *err = NULL;
+
+ doc = gedit_document_new ();
+ out = gedit_document_output_stream_new (doc);
+
+ g_output_stream_write (out, "\r", 1, NULL, NULL);
+ g_output_stream_write (out, "\n", 1, NULL, NULL);
+
+ g_output_stream_flush (out, NULL, &err);
+ g_assert_no_error (err);
+
+ line_count = gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (doc));
+
+ g_assert_cmpint (line_count, ==, 2);
+
+ g_output_stream_close (out, NULL, &err);
+ g_assert_no_error (err);
+
+ g_object_unref (doc);
+ g_object_unref (out);
+}
+
int main (int argc,
char *argv[])
{
@@ -127,6 +159,7 @@ int main (int argc,
g_test_add_func ("/document-output-stream/consecutive", test_consecutive);
g_test_add_func ("/document-output-stream/consecutive_tnewline", test_consecutive_tnewline);
g_test_add_func ("/document-output-stream/big-char", test_big_char);
+ g_test_add_func ("/document-output-stream/test-boundary", test_boundary);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]