Re: [gmime-devel] Mapping MIME parts to byte offsets



Okay, so I played around a bit more tonight and came up with the
attached patch that I like a lot and will likely be committing as-is.

The differences between this patch and the last patch are:

Instead of storing header offsets on the GMimeHeaderList, we now store a
substream of the input stream that was fed to the parser (which has the
offsets).

I like this API better because w/o the stream, the offsets are useless.
It should also make what you want to do extremely easy. It's also more
consistent with how I solve the same problem for GMimePart content.

And best of all... it means we don't have to dup the raw headers to
memory anymore. So it's a lot cleaner than what I had before to solve
the same problem, and is also a solution to the problem you had.


This is also safe to add to GMime 2.4 (no one should have been using the
g_mime_header_list_set/has_raw() APIs - altho to be safe, I should add
them back - this was a backport from what I'm working on on trunk).

Jeff

diff --git a/ChangeLog b/ChangeLog
index 9b51304..4680550 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,49 @@
+2009-04-24  Jeffrey Stedfast  <fejj novell com>
+
+	* tests/test-parser.c (test_parser): Updated.
+
+	* 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-09  Jeffrey Stedfast  <fejj novell com>
 
 	* README: Bumped version
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..cf4ade5 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,7 +945,7 @@ 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 {
@@ -972,9 +972,9 @@ 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)) {
+			/* if the mime part has a raw header stream, then it contains the
+			 * message headers as well otherwise it doesn't, so write them now */
 			if ((nwritten = g_mime_header_list_write_to_stream (object->headers, stream)) == -1)
 				return -1;
 			
@@ -1444,13 +1444,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]