[gmime] replaced raw header buf with a stream



commit 2917efe03bbaba0c7a90dd4dab2e761858369916
Author: Jeffrey Stedfast <fejj gnome org>
Date:   Sat Apr 25 09:59:38 2009 -0400

    replaced raw header buf with a stream
    
    2009-04-24  Jeffrey Stedfast  <fejj novell com>
    
    	* gmime/gmime-parser.c (struct _GMimeParserPrivate): Added
    	message_headers_begin/end and changed the meaning of
    	headers_begin/end to be for the current MIME part rather than for
    	the current message itself.
    	(g_mime_parser_init): Init the boolean state variables before
    	calling parser_init() so that parser_init() can use them.
    	(parser_init): Only create a rawbuf if our stream isn't seekable
    	or isn't persistent. Initialize our new message_headers_begin/end.
    	(g_mime_parser_set_persist_stream): If our persist mode has
    	changed, malloc or free our rawbuf.
    	(raw_header_append): Don't append any data if rawbuf is NULL (this
    	means we're keeping track of offsets instead).
    	(parser_step_headers): Always update headers_begin/end since we
    	now always want to keep track of all header begin/end offsets.
    	(parser_step): Update our message_headers_begin/end state.
    	(parser_scan_message_part): Set the mime-part's raw header stream
    	on the message too.
    	(parser_construct_message): Same.
    	(parser_construct_leaf_part): Substream the input stream to get
    	our raw header stream to set on the mime-part's header-list.
    	(parser_construct_multipart): Same.
    
    	* gmime/gmime-header.c (struct _GMimeHeaderList): Instead of
    	having a string buffer holding the raw header block content,
    	instead keep a stream. This not only makes it easy for us to keep
    	track of what the header offsets on disk are should the developer
    	want to know, but it also means we don't necessarily have to use
    	duplicate the header block to memory.
    	(g_mime_header_list_set_stream): New function that replaces the
    	old g_mime_header_list_set_raw() and looks much cleaner.
    	(g_mime_header_list_get_stream): New function to access said
    	stream.
    
    	* gmime/gmime-message.c: Fixed uses of
    	g_mime_header_list_set/has_raw().
    	(g_mime_message_set_mime_part): Set the message's raw header
    	stream to NULL.
    
    	* gmime/gmime-multipart.c: Same.
    
    	* tests/test-parser.c (test_parser): Updated.
---
 ChangeLog               |   44 +++++++++++++
 gmime/gmime-header.c    |   84 +++++++++++++++---------
 gmime/gmime-header.h    |    8 +-
 gmime/gmime-message.c   |   38 +++++++----
 gmime/gmime-multipart.c |    2 +-
 gmime/gmime-parser.c    |  163 +++++++++++++++++++++++++++++++++--------------
 tests/test-parser.c     |    4 +-
 7 files changed, 244 insertions(+), 99 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e64b31e..4a275f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,49 @@
 2009-04-24  Jeffrey Stedfast  <fejj novell com>
 
+	* gmime/gmime-parser.c (struct _GMimeParserPrivate): Added
+	message_headers_begin/end and changed the meaning of
+	headers_begin/end to be for the current MIME part rather than for
+	the current message itself.
+	(g_mime_parser_init): Init the boolean state variables before
+	calling parser_init() so that parser_init() can use them.
+	(parser_init): Only create a rawbuf if our stream isn't seekable
+	or isn't persistent. Initialize our new message_headers_begin/end.
+	(g_mime_parser_set_persist_stream): If our persist mode has
+	changed, malloc or free our rawbuf.
+	(raw_header_append): Don't append any data if rawbuf is NULL (this
+	means we're keeping track of offsets instead).
+	(parser_step_headers): Always update headers_begin/end since we
+	now always want to keep track of all header begin/end offsets.
+	(parser_step): Update our message_headers_begin/end state.
+	(parser_scan_message_part): Set the mime-part's raw header stream
+	on the message too.
+	(parser_construct_message): Same.
+	(parser_construct_leaf_part): Substream the input stream to get
+	our raw header stream to set on the mime-part's header-list.
+	(parser_construct_multipart): Same.
+
+	* gmime/gmime-header.c (struct _GMimeHeaderList): Instead of
+	having a string buffer holding the raw header block content,
+	instead keep a stream. This not only makes it easy for us to keep
+	track of what the header offsets on disk are should the developer
+	want to know, but it also means we don't necessarily have to use
+	duplicate the header block to memory.
+	(g_mime_header_list_set_stream): New function that replaces the
+	old g_mime_header_list_set_raw() and looks much cleaner.
+	(g_mime_header_list_get_stream): New function to access said
+	stream.
+
+	* gmime/gmime-message.c: Fixed uses of
+	g_mime_header_list_set/has_raw().
+	(g_mime_message_set_mime_part): Set the message's raw header
+	stream to NULL.
+
+	* gmime/gmime-multipart.c: Same.
+
+	* tests/test-parser.c (test_parser): Updated.
+
+2009-04-24  Jeffrey Stedfast  <fejj novell com>
+
 	* build/vs2008/config-win32.h.in: New template to replace
 	config.h.win32 so that the version info gets autogenerated when I
 	make a new release. Makes it easier for me to keep it in sync.
diff --git a/gmime/gmime-header.c b/gmime/gmime-header.c
index e518688..23e5014 100644
--- a/gmime/gmime-header.c
+++ b/gmime/gmime-header.c
@@ -65,11 +65,11 @@ struct _GMimeHeader {
 };
 
 struct _GMimeHeaderList {
+	GMimeStream *stream;
 	GHashTable *writers;
 	GHashTable *hash;
 	guint32 version;
 	List list;
-	char *raw;
 };
 
 
@@ -429,7 +429,7 @@ g_mime_header_iter_set_value (GMimeHeaderIter *iter, const char *value)
 	g_free (iter->cursor->value);
 	iter->cursor->value = g_strdup (value);
 	
-	g_mime_header_list_set_raw (iter->hdrlist, NULL);
+	g_mime_header_list_set_stream (iter->hdrlist, NULL);
 	
 	return TRUE;
 }
@@ -534,8 +534,8 @@ g_mime_header_list_new (void)
 	headers->hash = g_hash_table_new (g_mime_strcase_hash,
 					  g_mime_strcase_equal);
 	list_init (&headers->list);
+	headers->stream = NULL;
 	headers->version = 0;
-	headers->raw = NULL;
 	
 	return headers;
 }
@@ -564,7 +564,9 @@ g_mime_header_list_destroy (GMimeHeaderList *headers)
 	
 	g_hash_table_destroy (headers->writers);
 	g_hash_table_destroy (headers->hash);
-	g_free (headers->raw);
+	
+	if (headers->stream)
+		g_object_unref (headers->stream);
 	
 	g_slice_free (GMimeHeaderList, headers);
 }
@@ -592,8 +594,10 @@ g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const ch
 	list_append (&headers->list, (ListNode *) header);
 	g_hash_table_replace (headers->hash, header->name, header);
 	
-	g_free (headers->raw);
-	headers->raw = NULL;
+	if (headers->stream) {
+		g_object_unref (headers->stream);
+		headers->stream = NULL;
+	}
 }
 
 
@@ -621,8 +625,10 @@ g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const cha
 	if (!g_hash_table_lookup (headers->hash, name))
 		g_hash_table_insert (headers->hash, header->name, header);
 	
-	g_free (headers->raw);
-	headers->raw = NULL;
+	if (headers->stream) {
+		g_object_unref (headers->stream);
+		headers->stream = NULL;
+	}
 }
 
 
@@ -696,8 +702,10 @@ g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *
 		g_hash_table_insert (headers->hash, header->name, header);
 	}
 	
-	g_free (headers->raw);
-	headers->raw = NULL;
+	if (headers->stream) {
+		g_object_unref (headers->stream);
+		headers->stream = NULL;
+	}
 }
 
 
@@ -741,8 +749,10 @@ g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
 	list_unlink ((ListNode *) header);
 	g_mime_header_free (header);
 	
-	g_free (headers->raw);
-	headers->raw = NULL;
+	if (headers->stream) {
+		g_object_unref (headers->stream);
+		headers->stream = NULL;
+	}
 	
 	return TRUE;
 }
@@ -836,8 +846,10 @@ g_mime_header_list_write_to_stream (const GMimeHeaderList *headers, GMimeStream
 	g_return_val_if_fail (headers != NULL, -1);
 	g_return_val_if_fail (stream != NULL, -1);
 	
-	if (headers->raw)
-		return g_mime_stream_write_string (stream, headers->raw);
+	if (headers->stream) {
+		g_mime_stream_reset (headers->stream);
+		return g_mime_stream_write_to_stream (headers->stream, stream);
+	}
 	
 	header = (GMimeHeader *) headers->list.head;
 	writers = headers->writers;
@@ -878,13 +890,17 @@ g_mime_header_list_to_string (const GMimeHeaderList *headers)
 	
 	g_return_val_if_fail (headers != NULL, NULL);
 	
-	if (headers->raw)
-		return g_strdup (headers->raw);
-	
 	array = g_byte_array_new ();
 	stream = g_mime_stream_mem_new ();
 	g_mime_stream_mem_set_byte_array (GMIME_STREAM_MEM (stream), array);
-	g_mime_header_list_write_to_stream (headers, stream);
+	
+	if (headers->stream) {
+		g_mime_stream_reset (headers->stream);
+		g_mime_stream_write_to_stream (headers->stream, stream);
+	} else {
+		g_mime_header_list_write_to_stream (headers, stream);
+	}
+	
 	g_object_unref (stream);
 	
 	g_byte_array_append (array, (unsigned char *) "", 1);
@@ -926,34 +942,40 @@ g_mime_header_list_register_writer (GMimeHeaderList *headers, const char *name,
 
 
 /**
- * g_mime_header_list_set_raw:
+ * g_mime_header_list_set_stream:
  * @headers: a #GMimeHeaderList
- * @raw: raw mime part header
+ * @stream: a #GMimeStream
  *
- * Set the raw header.
+ * Set the raw header stream.
  **/
 void
-g_mime_header_list_set_raw (GMimeHeaderList *headers, const char *raw)
+g_mime_header_list_set_stream (GMimeHeaderList *headers, GMimeStream *stream)
 {
+	g_return_if_fail (stream == NULL || GMIME_IS_STREAM (stream));
 	g_return_if_fail (headers != NULL);
 	
-	g_free (headers->raw);
-	headers->raw = raw ? g_strdup (raw) : NULL;
+	if (stream)
+		g_object_ref (stream);
+	
+	if (headers->stream)
+		g_object_unref (headers->stream);
+	
+	headers->stream = stream;
 }
 
 
 /**
- * g_mime_header_list_has_raw:
+ * g_mime_header_list_get_stream:
  * @headers: a #GMimeHeaderList
  *
- * Gets whether or not a raw header has been set on @headers.
+ * Gets the raw stream representing @headers.
  *
- * Returns: %TRUE if a raw header is set or %FALSE otherwise.
+ * Returns: a #GMimeStream if set or %NULL otherwise.
  **/
-gboolean
-g_mime_header_list_has_raw (const GMimeHeaderList *headers)
+GMimeStream *
+g_mime_header_list_get_stream (GMimeHeaderList *headers)
 {
-	g_return_val_if_fail (headers != NULL, FALSE);
+	g_return_val_if_fail (headers != NULL, NULL);
 	
-	return headers->raw ? TRUE : FALSE;
+	return headers->stream;
 }
diff --git a/gmime/gmime-header.h b/gmime/gmime-header.h
index ac4b972..1b8fad7 100644
--- a/gmime/gmime-header.h
+++ b/gmime/gmime-header.h
@@ -87,6 +87,7 @@ gboolean g_mime_header_iter_prev (GMimeHeaderIter *iter);
 const char *g_mime_header_iter_get_name (GMimeHeaderIter *iter);
 gboolean g_mime_header_iter_set_value (GMimeHeaderIter *iter, const char *value);
 const char *g_mime_header_iter_get_value (GMimeHeaderIter *iter);
+
 gboolean g_mime_header_iter_remove (GMimeHeaderIter *iter);
 
 
@@ -108,6 +109,9 @@ GMimeHeaderList *g_mime_header_list_new (void);
 
 void g_mime_header_list_destroy (GMimeHeaderList *headers);
 
+void g_mime_header_list_set_stream (GMimeHeaderList *headers, GMimeStream *stream);
+GMimeStream *g_mime_header_list_get_stream (GMimeHeaderList *headers);
+
 void g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value);
 void g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value);
 void g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value);
@@ -122,10 +126,6 @@ void g_mime_header_list_register_writer (GMimeHeaderList *headers, const char *n
 ssize_t g_mime_header_list_write_to_stream (const GMimeHeaderList *headers, GMimeStream *stream);
 char *g_mime_header_list_to_string (const GMimeHeaderList *headers);
 
-/* for internal use only */
-void g_mime_header_list_set_raw (GMimeHeaderList *headers, const char *raw);
-gboolean g_mime_header_list_has_raw (const GMimeHeaderList *headers);
-
 G_END_DECLS
 
 #endif /* __GMIME_HEADER_H__ */
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index 3e450dd..b9ab70b 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -48,10 +48,10 @@
 
 typedef void (* EventCallback) (gpointer sender, gpointer args);
 
-void _internet_address_list_block_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
-void _internet_address_list_unblock_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
-void _internet_address_list_add_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
-void _internet_address_list_remove_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
+extern void _internet_address_list_block_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
+extern void _internet_address_list_unblock_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
+extern void _internet_address_list_add_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
+extern void _internet_address_list_remove_event_handler (InternetAddressList *list, EventCallback callback, gpointer user_data);
 
 
 static void g_mime_message_class_init (GMimeMessageClass *klass);
@@ -790,7 +790,7 @@ message_prepend_header (GMimeObject *object, const char *header, const char *val
 		g_mime_header_list_prepend (object->headers, header, value);
 	
 	if (message->mime_part)
-		g_mime_header_list_set_raw (message->mime_part->headers, NULL);
+		g_mime_header_list_set_stream (message->mime_part->headers, NULL);
 }
 
 static void
@@ -812,7 +812,7 @@ message_append_header (GMimeObject *object, const char *header, const char *valu
 		g_mime_header_list_append (object->headers, header, value);
 	
 	if (message->mime_part)
-		g_mime_header_list_set_raw (message->mime_part->headers, NULL);
+		g_mime_header_list_set_stream (message->mime_part->headers, NULL);
 }
 
 static void
@@ -834,7 +834,7 @@ message_set_header (GMimeObject *object, const char *header, const char *value)
 		g_mime_header_list_set (object->headers, header, value);
 	
 	if (message->mime_part)
-		g_mime_header_list_set_raw (message->mime_part->headers, NULL);
+		g_mime_header_list_set_stream (message->mime_part->headers, NULL);
 }
 
 static const char *
@@ -927,7 +927,7 @@ message_remove_header (GMimeObject *object, const char *header)
 	}
 	
 	if (message->mime_part)
-		g_mime_header_list_set_raw (message->mime_part->headers, NULL);
+		g_mime_header_list_set_stream (message->mime_part->headers, NULL);
 	
 	return GMIME_OBJECT_CLASS (parent_class)->remove_header (object, header);
 }
@@ -945,10 +945,15 @@ message_get_headers (GMimeObject *object)
 	stream = g_mime_stream_mem_new ();
 	g_mime_stream_mem_set_byte_array (GMIME_STREAM_MEM (stream), ba);
 	
-	if (message->mime_part && g_mime_header_list_has_raw (message->mime_part->headers)) {
+	if (message->mime_part && g_mime_header_list_get_stream (message->mime_part->headers)) {
 		/* if the mime part has raw headers, then it contains the message headers as well */
 		g_mime_header_list_write_to_stream (message->mime_part->headers, stream);
 	} else {
+		/* Note: if the user changed the mime_part's headers,
+		 * we need to unset our cached header stream or it
+		 * won't reflect the changes. */
+		g_mime_header_list_set_stream (object->headers, NULL);
+		
 		g_mime_header_list_write_to_stream (object->headers, stream);
 		if (message->mime_part) {
 			if (g_mime_object_get_header (message->mime_part, "Content-Type"))
@@ -972,9 +977,12 @@ message_write_to_stream (GMimeObject *object, GMimeStream *stream)
 	ssize_t nwritten, total = 0;
 	
 	if (message->mime_part) {
-		if (!g_mime_header_list_has_raw (message->mime_part->headers)) {
-			/* if the mime part has raw headers, then it contains the message
-			 * headers as well otherwise it doesn't, so write them now */
+		if (!g_mime_header_list_get_stream (message->mime_part->headers)) {
+			/* Note: if the user changed the mime_part's headers,
+			 * we need to unset our cached header stream or it
+			 * won't reflect the changes. */
+			g_mime_header_list_set_stream (object->headers, NULL);
+			
 			if ((nwritten = g_mime_header_list_write_to_stream (object->headers, stream)) == -1)
 				return -1;
 			
@@ -1444,13 +1452,15 @@ g_mime_message_set_mime_part (GMimeMessage *message, GMimeObject *mime_part)
 	g_return_if_fail (GMIME_IS_OBJECT (mime_part));
 	
 	g_object_ref (mime_part);
-	g_mime_header_list_set_raw (mime_part->headers, NULL);
+	g_mime_header_list_set_stream (mime_part->headers, NULL);
 	
 	if (message->mime_part) {
-		g_mime_header_list_set_raw (message->mime_part->headers, NULL);
+		g_mime_header_list_set_stream (message->mime_part->headers, NULL);
 		g_object_unref (message->mime_part);
 	}
 	
+	g_mime_header_list_set_stream (((GMimeObject *) message)->headers, NULL);
+	
 	message->mime_part = mime_part;
 }
 
diff --git a/gmime/gmime-multipart.c b/gmime/gmime-multipart.c
index 32ef7b0..a5d26d8 100644
--- a/gmime/gmime-multipart.c
+++ b/gmime/gmime-multipart.c
@@ -244,7 +244,7 @@ multipart_write_to_stream (GMimeObject *object, GMimeStream *stream)
 	 * not, then it's a broken multipart and so we don't want to
 	 * alter it or we'll completely break the output) */
 	boundary = g_mime_object_get_content_type_parameter (object, "boundary");
-	if (!boundary && !g_mime_header_list_has_raw (object->headers)) {
+	if (!boundary && !g_mime_header_list_get_stream (object->headers)) {
 		g_mime_multipart_set_boundary (multipart, NULL);
 		boundary = g_mime_object_get_content_type_parameter (object, "boundary");
 	}
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index cb58a98..f196ca1 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -153,6 +153,10 @@ struct _GMimeParserPrivate {
 	size_t rawleft;
 	
 	/* current message headerblock offsets */
+	gint64 message_headers_begin;
+	gint64 message_headers_end;
+	
+	/* current mime-part headerblock offsets */
 	gint64 headers_begin;
 	gint64 headers_end;
 	
@@ -298,16 +302,16 @@ static void
 g_mime_parser_init (GMimeParser *parser, GMimeParserClass *klass)
 {
 	parser->priv = g_new (struct _GMimeParserPrivate, 1);
-	parser_init (parser, NULL);
+	parser->priv->respect_content_length = FALSE;
+	parser->priv->persist_stream = TRUE;
+	parser->priv->have_regex = FALSE;
+	parser->priv->scan_from = FALSE;
 	
 #if defined (HAVE_GLIB_REGEX)
 	parser->priv->regex = NULL;
 #endif
 	
-	parser->priv->scan_from = FALSE;
-	parser->priv->have_regex = FALSE;
-	parser->priv->persist_stream = TRUE;
-	parser->priv->respect_content_length = FALSE;
+	parser_init (parser, NULL);
 }
 
 static void
@@ -359,9 +363,18 @@ parser_init (GMimeParser *parser, GMimeStream *stream)
 	priv->headerleft = HEADER_INIT_SIZE - 1;
 	priv->headerptr = priv->headerbuf;
 	
-	priv->rawbuf = g_malloc (HEADER_RAW_INIT_SIZE);
-	priv->rawleft = HEADER_RAW_INIT_SIZE - 1;
-	priv->rawptr = priv->rawbuf;
+	if (offset == -1 || !priv->persist_stream) {
+		priv->rawbuf = g_malloc (HEADER_RAW_INIT_SIZE);
+		priv->rawleft = HEADER_RAW_INIT_SIZE - 1;
+		priv->rawptr = priv->rawbuf;
+	} else {
+		priv->rawbuf = NULL;
+		priv->rawptr = NULL;
+		priv->rawleft = 0;
+	}
+	
+	priv->message_headers_begin = -1;
+	priv->message_headers_end = -1;
 	
 	priv->headers_begin = -1;
 	priv->headers_end = -1;
@@ -501,9 +514,33 @@ g_mime_parser_get_persist_stream (GMimeParser *parser)
 void
 g_mime_parser_set_persist_stream (GMimeParser *parser, gboolean persist)
 {
+	struct _GMimeParserPrivate *priv;
+	
 	g_return_if_fail (GMIME_IS_PARSER (parser));
 	
-	parser->priv->persist_stream = persist;
+	priv = parser->priv;
+	
+	if (priv->persist_stream == persist)
+		return;
+	
+	if (persist) {
+		priv->persist_stream = TRUE;
+		
+		if (priv->seekable && !priv->rawbuf) {
+			priv->rawbuf = g_malloc (HEADER_RAW_INIT_SIZE);
+			priv->rawleft = HEADER_RAW_INIT_SIZE - 1;
+			priv->rawptr = priv->rawbuf;
+		}
+	} else {
+		priv->persist_stream = FALSE;
+		
+		if (priv->rawbuf) {
+			g_free (priv->rawbuf);
+			priv->rawbuf = NULL;
+			priv->rawptr = NULL;
+			priv->rawleft = 0;
+		}
+	}
 }
 
 
@@ -849,25 +886,29 @@ next_alloc_size (size_t n)
 } G_STMT_END
 
 #define raw_header_append(priv, start, len) G_STMT_START {                \
-	if (priv->rawleft <= len) {                                       \
-		size_t hlen, hoff;                                        \
+	if (priv->rawbuf) {                                               \
+		if (priv->rawleft <= len) {                               \
+			size_t hlen, hoff;                                \
+			                                                  \
+			hoff = priv->rawptr - priv->rawbuf;               \
+			hlen = next_alloc_size (hoff + len + 1);          \
+			                                                  \
+			priv->rawbuf = g_realloc (priv->rawbuf, hlen);    \
+			priv->rawptr = priv->rawbuf + hoff;               \
+			priv->rawleft = (hlen - 1) - hoff;                \
+		}                                                         \
 		                                                          \
-		hoff = priv->rawptr - priv->rawbuf;                       \
-		hlen = next_alloc_size (hoff + len + 1);                  \
-		                                                          \
-		priv->rawbuf = g_realloc (priv->rawbuf, hlen);            \
-		priv->rawptr = priv->rawbuf + hoff;                       \
-		priv->rawleft = (hlen - 1) - hoff;                        \
+		memcpy (priv->rawptr, start, len);                        \
+		priv->rawptr += len;                                      \
+		priv->rawleft -= len;                                     \
 	}                                                                 \
-	                                                                  \
-	memcpy (priv->rawptr, start, len);                                \
-	priv->rawptr += len;                                              \
-	priv->rawleft -= len;                                             \
 } G_STMT_END
 
 #define raw_header_reset(priv) G_STMT_START {                             \
-	priv->rawleft += priv->rawptr - priv->rawbuf;                     \
-	priv->rawptr = priv->rawbuf;                                      \
+	if (priv->rawbuf) {                                               \
+		priv->rawleft += priv->rawptr - priv->rawbuf;             \
+		priv->rawptr = priv->rawbuf;                              \
+	}                                                                 \
 } G_STMT_END
 
 static void
@@ -955,10 +996,8 @@ parser_step_headers (GMimeParser *parser)
 	raw_header_reset (priv);
 	header_raw_clear (&priv->headers);
 	tail = (HeaderRaw *) &priv->headers;
-	priv->header_offset = parser_offset (priv, NULL);
-	
-	if (priv->headers_begin == -1)
-		priv->headers_begin = parser_offset (priv, NULL);
+	priv->headers_begin = parser_offset (priv, NULL);
+	priv->header_offset = priv->headers_begin;
 	
 	inptr = priv->inptr;
 	inend = priv->inend;
@@ -1089,33 +1128,30 @@ parser_step_headers (GMimeParser *parser)
 	if (priv->headerptr > priv->headerbuf)
 		header_parse (parser, &tail);
 	
-	if (priv->headers_end == -1)
-		priv->headers_end = parser_offset (priv, start);
-	
+	priv->headers_end = parser_offset (priv, start);
 	priv->state = GMIME_PARSER_STATE_HEADERS_END;
-	*priv->rawptr = '\0';
+	if (priv->rawbuf)
+		*priv->rawptr = '\0';
 	priv->inptr = inptr;
 	
 	return 0;
 	
  next_message:
 	
-	if (priv->headers_end == -1)
-		priv->headers_end = parser_offset (priv, start);
-	
+	priv->headers_end = parser_offset (priv, start);
 	priv->state = GMIME_PARSER_STATE_COMPLETE;
-	*priv->rawptr = '\0';
+	if (priv->rawbuf)
+		*priv->rawptr = '\0';
 	priv->inptr = start;
 	
 	return 0;
 	
  content_start:
 	
-	if (priv->headers_end == -1)
-		priv->headers_end = parser_offset (priv, start);
-	
+	priv->headers_end = parser_offset (priv, start);
 	priv->state = GMIME_PARSER_STATE_CONTENT;
-	*priv->rawptr = '\0';
+	if (priv->rawbuf)
+		*priv->rawptr = '\0';
 	priv->inptr = start;
 	
 	return 0;
@@ -1210,20 +1246,25 @@ parser_step (GMimeParser *parser)
 	case GMIME_PARSER_STATE_ERROR:
 		break;
 	case GMIME_PARSER_STATE_INIT:
-		parser->priv->headers_begin = -1;
-		parser->priv->headers_end = -1;
+		priv->message_headers_begin = -1;
+		priv->message_headers_end = -1;
 		if (priv->scan_from)
 			priv->state = GMIME_PARSER_STATE_FROM;
 		else
 			priv->state = GMIME_PARSER_STATE_HEADERS;
 		break;
 	case GMIME_PARSER_STATE_FROM:
-		parser->priv->headers_begin = -1;
-		parser->priv->headers_end = -1;
+		priv->message_headers_begin = -1;
+		priv->message_headers_end = -1;
 		parser_step_from (parser);
 		break;
 	case GMIME_PARSER_STATE_HEADERS:
 		parser_step_headers (parser);
+		
+		if (priv->message_headers_begin == -1) {
+			priv->message_headers_begin = priv->headers_begin;
+			priv->message_headers_end = priv->headers_end;
+		}
 		break;
 	case GMIME_PARSER_STATE_HEADERS_END:
 		if (parser_skip_line (parser) == -1)
@@ -1460,6 +1501,7 @@ parser_scan_message_part (GMimeParser *parser, GMimeMessagePart *mpart, int *fou
 	ContentType *content_type;
 	GMimeMessage *message;
 	GMimeObject *object;
+	GMimeStream *stream;
 	HeaderRaw *header;
 	
 	g_assert (priv->state == GMIME_PARSER_STATE_CONTENT);
@@ -1489,6 +1531,10 @@ parser_scan_message_part (GMimeParser *parser, GMimeMessagePart *mpart, int *fou
 	content_type_destroy (content_type);
 	message->mime_part = object;
 	
+	/* set the same raw header stream on the message's header-list */
+	if ((stream = g_mime_header_list_get_stream (object->headers)))
+		g_mime_header_list_set_stream (((GMimeObject *) message)->headers, stream);
+	
 	g_mime_message_part_set_message (mpart, message);
 	g_object_unref (message);
 }
@@ -1498,6 +1544,7 @@ parser_construct_leaf_part (GMimeParser *parser, ContentType *content_type, int
 {
 	struct _GMimeParserPrivate *priv = parser->priv;
 	GMimeObject *object;
+	GMimeStream *stream;
 	HeaderRaw *header;
 	
 	g_assert (priv->state >= GMIME_PARSER_STATE_HEADERS_END);
@@ -1520,7 +1567,15 @@ parser_construct_leaf_part (GMimeParser *parser, ContentType *content_type, int
 	
 	header_raw_clear (&priv->headers);
 	
-	g_mime_header_list_set_raw (object->headers, priv->rawbuf);
+	/* set the raw header stream on the header-list */
+	if (priv->persist_stream && priv->seekable)
+		stream = g_mime_stream_substream (priv->stream, priv->headers_begin, priv->headers_end);
+	else
+		stream = g_mime_stream_mem_new_with_buffer (priv->rawbuf, priv->rawptr - priv->rawbuf);
+	
+	g_mime_header_list_set_stream (object->headers, stream);
+	g_object_unref (stream);
+	
 	raw_header_reset (priv);
 	
 	if (priv->state == GMIME_PARSER_STATE_HEADERS_END) {
@@ -1654,6 +1709,7 @@ parser_construct_multipart (GMimeParser *parser, ContentType *content_type, int
 	GMimeMultipart *multipart;
 	const char *boundary;
 	GMimeObject *object;
+	GMimeStream *stream;
 	HeaderRaw *header;
 	
 	g_assert (priv->state >= GMIME_PARSER_STATE_HEADERS_END);
@@ -1668,7 +1724,15 @@ parser_construct_multipart (GMimeParser *parser, ContentType *content_type, int
 	
 	header_raw_clear (&priv->headers);
 	
-	g_mime_header_list_set_raw (object->headers, priv->rawbuf);
+	/* set the raw header stream on the header-list */
+	if (priv->persist_stream && priv->seekable)
+		stream = g_mime_stream_substream (priv->stream, priv->headers_begin, priv->headers_end);
+	else
+		stream = g_mime_stream_mem_new_with_buffer (priv->rawbuf, priv->rawptr - priv->rawbuf);
+	
+	g_mime_header_list_set_stream (object->headers, stream);
+	g_object_unref (stream);
+	
 	raw_header_reset (priv);
 	
 	multipart = (GMimeMultipart *) object;
@@ -1758,6 +1822,7 @@ parser_construct_message (GMimeParser *parser)
 	ContentType *content_type;
 	GMimeMessage *message;
 	GMimeObject *object;
+	GMimeStream *stream;
 	HeaderRaw *header;
 	char *endptr;
 	int found;
@@ -1802,6 +1867,10 @@ parser_construct_message (GMimeParser *parser)
 	content_type_destroy (content_type);
 	message->mime_part = object;
 	
+	/* set the same raw header stream on the message's header-list */
+	if ((stream = g_mime_header_list_get_stream (object->headers)))
+		g_mime_header_list_set_stream (((GMimeObject *) message)->headers, stream);
+	
 	if (priv->scan_from) {
 		priv->state = GMIME_PARSER_STATE_FROM;
 		parser_pop_boundary (parser);
@@ -1896,7 +1965,7 @@ g_mime_parser_get_headers_begin (GMimeParser *parser)
 {
 	g_return_val_if_fail (GMIME_IS_PARSER (parser), -1);
 	
-	return parser->priv->headers_begin;
+	return parser->priv->message_headers_begin;
 }
 
 
@@ -1915,5 +1984,5 @@ g_mime_parser_get_headers_end (GMimeParser *parser)
 {
 	g_return_val_if_fail (GMIME_IS_PARSER (parser), -1);
 	
-	return parser->priv->headers_end;
+	return parser->priv->message_headers_end;
 }
diff --git a/tests/test-parser.c b/tests/test-parser.c
index 213a771..f2562ff 100644
--- a/tests/test-parser.c
+++ b/tests/test-parser.c
@@ -129,11 +129,11 @@ test_parser (GMimeStream *stream)
 	{
 		GMimeStream *stream;
 		
-		g_mime_header_list_set_raw (GMIME_OBJECT (message)->headers, NULL);
+		g_mime_header_list_set_stream (GMIME_OBJECT (message)->headers, NULL);
 		
 		fprintf (stdout, "\nTesting preservation of headers...\n\n");
 		stream = g_mime_stream_file_new (stdout);
-		/*g_mime_header_set_raw (GMIME_OBJECT (message)->headers, NULL);*/
+		/*g_mime_header_set_stream (GMIME_OBJECT (message)->headers, NULL);*/
 		g_mime_header_list_write_to_stream (GMIME_OBJECT (message)->headers, stream);
 		g_mime_stream_flush (stream);
 		GMIME_STREAM_FILE (stream)->fp = NULL;



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