dovecot: Rewrote with separate CRLF/LF-only read functions. The ...

dovecot at dovecot.org dovecot at dovecot.org
Thu Nov 8 01:57:01 EET 2007


details:   http://hg.dovecot.org/dovecot/rev/a9739ce5a7e4
changeset: 6722:a9739ce5a7e4
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Nov 08 01:56:57 2007 +0200
description:
Rewrote with separate CRLF/LF-only read functions. The code is much easier
to read now and it fixes some bugs as well.

diffstat:

1 file changed, 74 insertions(+), 40 deletions(-)
src/lib/istream-crlf.c |  114 +++++++++++++++++++++++++++++++-----------------

diffs (171 lines):

diff -r 9aab8ac958fb -r a9739ce5a7e4 src/lib/istream-crlf.c
--- a/src/lib/istream-crlf.c	Thu Nov 08 00:48:20 2007 +0200
+++ b/src/lib/istream-crlf.c	Thu Nov 08 01:56:57 2007 +0200
@@ -8,8 +8,8 @@ struct crlf_istream {
 	struct istream_private istream;
 
 	struct istream *input;
-	char last_char;
-	unsigned int crlf:1;
+	unsigned int pending_cr:1;
+	unsigned int last_cr:1;
 };
 
 static void i_stream_crlf_destroy(struct iostream_private *stream)
@@ -30,11 +30,11 @@ i_stream_crlf_set_max_buffer_size(struct
 	i_stream_set_max_buffer_size(cstream->input, max_size);
 }
 
-static ssize_t i_stream_crlf_read(struct istream_private *stream)
+static int i_stream_crlf_read_common(struct crlf_istream *cstream)
 {
-	struct crlf_istream *cstream = (struct crlf_istream *)stream;
+	struct istream_private *stream = &cstream->istream;
 	const unsigned char *data;
-	size_t i, dest, size;
+	size_t size;
 	ssize_t ret;
 
 	data = i_stream_get_data(cstream->input, &size);
@@ -52,57 +52,91 @@ static ssize_t i_stream_crlf_read(struct
 
 	if (!i_stream_get_buffer_space(stream, size, NULL))
 		return -2;
+	return 1;
+}
+
+static ssize_t i_stream_crlf_read_crlf(struct istream_private *stream)
+{
+	struct crlf_istream *cstream = (struct crlf_istream *)stream;
+	const unsigned char *data;
+	size_t i, dest, size;
+	ssize_t ret;
+
+	ret = i_stream_crlf_read_common(cstream);
+	if (ret <= 0)
+		return ret;
+
+	data = i_stream_get_data(cstream->input, &size);
+
+	/* @UNSAFE: add missing CRs */
+	dest = stream->pos;
+	for (i = 0; i < size && dest < stream->buffer_size; i++) {
+		if (data[i] == '\n') {
+			if (i == 0) {
+				if (!cstream->last_cr)
+					stream->w_buffer[dest++] = '\r';
+			} else {
+				if (data[i-1] != '\r')
+					stream->w_buffer[dest++] = '\r';
+			}
+			if (dest == stream->buffer_size)
+				break;
+		}
+		stream->w_buffer[dest++] = data[i];
+	}
+	cstream->last_cr = stream->w_buffer[dest-1] == '\r';
+	i_stream_skip(cstream->input, i);
+
+	ret = dest - stream->pos;
+	i_assert(ret != 0);
+	stream->pos = dest;
+	return ret;
+}
+
+static ssize_t i_stream_crlf_read_lf(struct istream_private *stream)
+{
+	struct crlf_istream *cstream = (struct crlf_istream *)stream;
+	const unsigned char *data;
+	size_t i, dest, size;
+	ssize_t ret;
+
+	ret = i_stream_crlf_read_common(cstream);
+	if (ret <= 0)
+		return ret;
+
+	data = i_stream_get_data(cstream->input, &size);
 
 	/* @UNSAFE */
 	dest = stream->pos;
-	if (data[0] == '\n')
-		i = 0;
-	else {
-		if (cstream->last_char == '\r') {
+	if (data[0] == '\n') {
+		stream->w_buffer[dest++] = '\n';
+		cstream->pending_cr = FALSE;
+	} else {
+		if (cstream->pending_cr) {
 			/* CR without LF */
 			stream->w_buffer[dest++] = '\r';
 			if (dest == stream->buffer_size) {
-				cstream->last_char = 0;
+				cstream->pending_cr = FALSE;
 				return 1;
 			}
 		}
 		if (data[0] != '\r')
 			stream->w_buffer[dest++] = data[0];
-		i = 1;
 	}
-	cstream->last_char = data[size-1];
-	for (; i < size && dest < stream->buffer_size; i++) {
-		if (data[i] <= '\r') {
-			if (data[i] == '\n') {
-				if (cstream->crlf) {
-					if (dest + 1 == stream->buffer_size)
-						break;
-					stream->w_buffer[dest++] = '\r';
-				}
-				stream->w_buffer[dest++] = '\n';
-				continue;
-			}
-			if (data[i] == '\r' && data[i-1] != '\r')
-				continue;
-		}
-		if (data[i-1] == '\r') {
-			/* CR without LF */
-			stream->w_buffer[dest++] = '\r';
-			if (dest == stream->buffer_size) {
-				cstream->last_char = 0;
-				break;
-			}
-			if (data[i] == '\r')
-				continue;
-		}
+
+	for (i = 1; i < size && dest < stream->buffer_size; i++) {
+		if (data[i] == '\r' && data[i-1] != '\r')
+			continue;
+
 		stream->w_buffer[dest++] = data[i];
 	}
+	cstream->pending_cr = data[i-1] == '\r';
 	i_stream_skip(cstream->input, i);
 
 	ret = dest - stream->pos;
 	if (ret == 0) {
-		i_assert(cstream->last_char == '\r' && size == 1);
-		return i_stream_crlf_read(stream);
+		i_assert(cstream->pending_cr && size == 1);
+		return i_stream_crlf_read_lf(stream);
 	}
 	stream->pos = dest;
 	return ret;
@@ -132,14 +166,14 @@ i_stream_create_crlf_full(struct istream
 
 	cstream = i_new(struct crlf_istream, 1);
 	cstream->input = input;
-	cstream->crlf = crlf;
 	cstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
 
 	cstream->istream.iostream.destroy = i_stream_crlf_destroy;
 	cstream->istream.iostream.set_max_buffer_size =
 		i_stream_crlf_set_max_buffer_size;
 
-	cstream->istream.read = i_stream_crlf_read;
+	cstream->istream.read = crlf ? i_stream_crlf_read_crlf :
+		i_stream_crlf_read_lf;
 	cstream->istream.seek = i_stream_crlf_seek;
 	cstream->istream.stat = i_stream_crlf_stat;
 


More information about the dovecot-cvs mailing list