[gedit/docstream2: 6/16] Fixed document input stream to pass the tests



commit 4fd3fc7c27a71e0a5be6f79af81bfdf18deabd07
Author: Jesse van den Kieboom <jesse icecrew nl>
Date:   Sat Jan 23 12:13:57 2010 +0100

    Fixed document input stream to pass the tests
    
    There were some problems in the bookkeeping and bytes calculations.
    Also, the mark has been removed in favour of an iter, assuming the
    buffer cannot be modified while saving

 gedit/gedit-document-input-stream.c |  160 ++++++++++++++++-------------------
 1 files changed, 73 insertions(+), 87 deletions(-)
---
diff --git a/gedit/gedit-document-input-stream.c b/gedit/gedit-document-input-stream.c
index 7c65f5a..d815a26 100644
--- a/gedit/gedit-document-input-stream.c
+++ b/gedit/gedit-document-input-stream.c
@@ -35,11 +35,13 @@ G_DEFINE_TYPE (GeditDocumentInputStream, gedit_document_input_stream, G_TYPE_INP
 struct _GeditDocumentInputStreamPrivate
 {
 	GtkTextBuffer *buffer;
-	GtkTextMark   *pos;
+	GtkTextIter    pos;
+	guint          bytes_partial;
 
 	GeditDocumentNewlineType newline_type;
 
 	guint newline_added : 1;
+	guint is_initialized : 1;
 };
 
 enum
@@ -59,28 +61,6 @@ static gboolean   gedit_document_input_stream_close    (GInputStream      *strea
 							GError           **error);
 
 static void
-gedit_document_input_stream_finalize (GObject *object)
-{
-	G_OBJECT_CLASS (gedit_document_input_stream_parent_class)->finalize (object);
-}
-
-static void
-gedit_document_input_stream_dispose (GObject *object)
-{
-	GeditDocumentInputStream *stream = GEDIT_DOCUMENT_INPUT_STREAM (object);
-
-	if (stream->priv->pos != NULL)
-	{
-		gtk_text_buffer_delete_mark (stream->priv->buffer,
-					     stream->priv->pos);
-
-		stream->priv->pos = NULL;
-	}
-
-	G_OBJECT_CLASS (gedit_document_input_stream_parent_class)->dispose (object);
-}
-
-static void
 gedit_document_input_stream_set_property (GObject      *object,
 					  guint         prop_id,
 					  const GValue *value,
@@ -136,8 +116,6 @@ gedit_document_input_stream_class_init (GeditDocumentInputStreamClass *klass)
 
 	g_type_class_add_private (klass, sizeof (GeditDocumentInputStreamPrivate));
 
-	gobject_class->finalize = gedit_document_input_stream_finalize;
-	gobject_class->dispose = gedit_document_input_stream_dispose;
 	gobject_class->get_property = gedit_document_input_stream_get_property;
 	gobject_class->set_property = gedit_document_input_stream_set_property;
 
@@ -178,8 +156,6 @@ gedit_document_input_stream_init (GeditDocumentInputStream *stream)
 	stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
 						    GEDIT_TYPE_DOCUMENT_INPUT_STREAM,
 						    GeditDocumentInputStreamPrivate);
-
-	stream->priv->newline_added = FALSE;
 }
 
 static gsize
@@ -237,15 +213,19 @@ gedit_document_input_stream_get_total_size (GeditDocumentInputStream *stream)
 gsize
 gedit_document_input_stream_tell (GeditDocumentInputStream *stream)
 {
-	GtkTextIter iter;
-
 	g_return_val_if_fail (GEDIT_IS_DOCUMENT_INPUT_STREAM (stream), 0);
 
-	gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
-					  &iter,
-					  stream->priv->pos);
-
-	return gtk_text_iter_get_offset (&iter);
+	/* FIXME: is this potentially inefficient? If yes, we could keep
+	   track of the offset internally, assuming the mark doesn't move
+	   during the operation */
+	if (!stream->priv->is_initialized)
+	{
+		return 0;
+	}
+	else
+	{
+		return gtk_text_iter_get_offset (&stream->priv->pos);
+	}
 }
 
 static const gchar *
@@ -276,86 +256,99 @@ read_line (GeditDocumentInputStream *stream,
 	   gchar                    *outbuf,
 	   gsize                     space_left)
 {
-	GtkTextIter start, next, end;
+	GtkTextIter *start, next, end;
 	gchar *buf;
-	gsize read, bytes, newline_size;
+	gsize read, bytes, newline_size, bytes_to_write;
 	const gchar *newline;
 	gboolean is_last;
 
-	gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
-					  &start,
-					  stream->priv->pos);
+	start = &stream->priv->pos;
 
-	end = next = start;
+	end = next = *start;
 	newline = get_new_line (stream);
 	newline_size = get_new_line_size (stream);
 
-	if (gtk_text_iter_is_end (&start))
+	if (gtk_text_iter_is_end (start))
 		return 0;
 
+	/* Check needed for empty lines */
 	if (!gtk_text_iter_ends_line (&end))
 		gtk_text_iter_forward_to_line_end (&end);
 
 	gtk_text_iter_forward_line (&next);
 
-	buf = gtk_text_iter_get_slice (&start, &end);
+	buf = gtk_text_iter_get_slice (start, &end);
 
 	/* the bytes of a line includes also the newline, so with the
 	   offsets we remove the newline and we add the new newline size */
-	bytes = gtk_text_iter_get_offset (&end) - gtk_text_iter_get_offset (&start);
+	bytes = gtk_text_iter_get_bytes_in_line (start) - stream->priv->bytes_partial;
+
+	/* bytes_in_line includes the newlines, so we remove that assuming that
+	   they are single byte characters */
+	bytes = bytes - (gtk_text_iter_get_offset (&next) - gtk_text_iter_get_offset (&end));
 	is_last = gtk_text_iter_is_end (&end);
 
-	/* do not add the new newline_size if there wasn't a previous one */
+	/* bytes_to_write contains the amount of bytes we would like to write.
+	   This means its the amount of bytes in the line (without the newline
+	   in the buffer) + the amount of bytes for the newline we want to
+	   write (newline_size) */
+	bytes_to_write = bytes;
+
+	/* do not add the new newline_size for the last line */
 	if (!is_last)
-		bytes += newline_size;
+		bytes_to_write += newline_size;
 
-	if (bytes > space_left)
+	if (bytes_to_write > space_left)
 	{
 		gchar *ptr;
 		gint offset;
 		gsize to_write;
-
-		/* we don't want to write here the newline so we write what
-		   it is missing in the line and we leave the newline for the
-		   new iteration */
-		to_write = MIN (space_left, (bytes - newline_size));
+		gsize next_size;
+
+		/* Here the line does not fit in the buffer, we thus write
+		   the amount of bytes we can still fit, storing the position
+		   for the next read with the mark. Do not try to write the
+		   new newline in this case, it will be handled in the next
+		   iteration */
+		to_write = MIN (space_left, bytes);
 		ptr = buf;
+		next_size = 0;
+		offset = 0;
 
-		while ((ptr - buf) < to_write)
+		do
+		{
+			read = next_size;
 			ptr = g_utf8_next_char (ptr);
+			next_size = ptr - buf;
 
-		if ((ptr - buf) > to_write)
-			ptr = g_utf8_prev_char (ptr);
+			++offset;
+		} while (next_size <= to_write);
 
-		memcpy (outbuf, buf, (ptr - buf));
-		read = (ptr - buf);
+		memcpy (outbuf, buf, read);
 
-		offset = gtk_text_iter_get_line_offset (&start);
-		gtk_text_iter_set_line_offset (&start, offset + read);
+		/* Note: offset is one past what we wrote */
+		gtk_text_iter_forward_chars (start, offset - 1);
+
+		stream->priv->bytes_partial = read;
 	}
 	else
 	{
-	
-		memcpy (outbuf, buf, bytes - newline_size);
-		read = bytes - newline_size;
+		/* First just copy the bytes without the newline */
+		memcpy (outbuf, buf, bytes);
 
-		/* do not add the newline if there wasn't a previous, this can
-		   happen in the last line */
+		/* Then add the newline, but not for the last line */
 		if (!is_last)
 		{
-			memcpy (outbuf + read, newline, newline_size);
-			read += newline_size;
+			memcpy (outbuf + bytes, newline, newline_size);
 		}
 
-		start = next;
+		read = bytes_to_write;
+		*start = next;
+
+		stream->priv->bytes_partial = 0;
 	}
 
 	g_free (buf);
-
-	gtk_text_buffer_move_mark (stream->priv->buffer,
-				   stream->priv->pos,
-				   &start);
-
 	return read;
 }
 
@@ -368,14 +361,15 @@ gedit_document_input_stream_read (GInputStream  *stream,
 {
 	GeditDocumentInputStream *dstream;
 	gssize space_left, read, n, newline_size;
-	GtkTextIter pos;
+
+	g_return_val_if_fail (GEDIT_IS_DOCUMENT_INPUT_STREAM (stream), -1);
 
 	dstream = GEDIT_DOCUMENT_INPUT_STREAM (stream);
 
 	if (count < 6)
 	{
 		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
-				     "Not enougth space on destiny");
+				     "Not enougth space in destination");
 		return -1;
 	}
 
@@ -383,16 +377,10 @@ gedit_document_input_stream_read (GInputStream  *stream,
 		return -1;
 
 	/* Initialize the mark to the first char in the text buffer */
-	if (dstream->priv->pos == NULL)
+	if (!dstream->priv->is_initialized)
 	{
-		GtkTextIter start;
-
-		gtk_text_buffer_get_start_iter (dstream->priv->buffer, &start);
-
-		dstream->priv->pos = gtk_text_buffer_create_mark (dstream->priv->buffer,
-								  NULL,
-								  &start,
-								  TRUE);
+		gtk_text_buffer_get_start_iter (dstream->priv->buffer, &dstream->priv->pos);
+		dstream->priv->is_initialized = TRUE;
 	}
 
 	space_left = count;
@@ -407,13 +395,10 @@ gedit_document_input_stream_read (GInputStream  *stream,
 
 	/* make sure files are always terminated with \n (see bug #95676). Note
 	   that we strip the trailing \n when loading the file */
-	gtk_text_buffer_get_iter_at_mark (dstream->priv->buffer,
-					  &pos,
-					  dstream->priv->pos);
-
 	newline_size = get_new_line_size (dstream);
 
-	if (gtk_text_iter_is_end (&pos) && space_left >= newline_size &&
+	if (gtk_text_iter_is_end (&dstream->priv->pos) &&
+	    space_left >= newline_size &&
 	    !dstream->priv->newline_added)
 	{
 		const gchar *newline;
@@ -421,6 +406,7 @@ gedit_document_input_stream_read (GInputStream  *stream,
 		newline = get_new_line (dstream);
 
 		memcpy (buffer + read, newline, newline_size);
+
 		read += newline_size;
 		dstream->priv->newline_added = TRUE;
 	}



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