changeset 20592:b42d619d85c7

istream-base64-encoder: Implemented proper stat function that returns the encoded size of the stream. For Base64 encoding, the size of the encoded data can be determined from the input data size exactly.
author Stephan Bosch <stephan@dovecot.fi>
date Sat, 06 Aug 2016 17:59:10 +0200
parents 07fa25c2da86
children 8afdd7adf237
files src/lib/istream-base64-encoder.c src/lib/test-istream-base64-encoder.c
diffstat 2 files changed, 49 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/istream-base64-encoder.c	Mon Aug 08 15:51:17 2016 +0300
+++ b/src/lib/istream-base64-encoder.c	Sat Aug 06 17:59:10 2016 +0200
@@ -143,6 +143,35 @@
 	i_stream_default_seek_nonseekable(stream, v_offset, mark);
 }
 
+static int
+i_stream_base64_encoder_stat(struct istream_private *stream,
+	bool exact ATTR_UNUSED)
+{
+	struct base64_encoder_istream *bstream =
+		(struct base64_encoder_istream *)stream;
+	const struct stat *st;
+	off_t newlines, size;
+
+	if (i_stream_stat(stream->parent, exact, &st) < 0) {
+		stream->istream.stream_errno = stream->parent->stream_errno;
+		return -1;
+	}
+
+	stream->statbuf = *st;
+	
+	/* calculate size of encoded data */
+	size = (st->st_size / 3) * 4 +
+		((st->st_size % 3) == 0 ? 0 : 4);
+
+	/* update size with added newlines */
+	newlines = (size / bstream->chars_per_line - 1) +
+		((size % bstream->chars_per_line) == 0 ? 0 : 1);
+	size += newlines * (bstream->crlf ? 2 : 1);
+
+	stream->statbuf.st_size = size;
+	return 0;
+}
+
 struct istream *
 i_stream_create_base64_encoder(struct istream *input,
 			       unsigned int chars_per_line, bool crlf)
@@ -158,6 +187,7 @@
 
 	bstream->istream.read = i_stream_base64_encoder_read;
 	bstream->istream.seek = i_stream_base64_encoder_seek;
+	bstream->istream.stat = i_stream_base64_encoder_stat;
 
 	bstream->istream.istream.readable_fd = FALSE;
 	bstream->istream.istream.blocking = input->blocking;
--- a/src/lib/test-istream-base64-encoder.c	Mon Aug 08 15:51:17 2016 +0300
+++ b/src/lib/test-istream-base64-encoder.c	Sat Aug 06 17:59:10 2016 +0200
@@ -13,9 +13,22 @@
 } tests[] = {
 	{ "hello world", 80, FALSE, "aGVsbG8gd29ybGQ=" },
 	{ "hello world", 4, FALSE, "aGVs\nbG8g\nd29y\nbGQ=" },
-	{ "hello world", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGQ=", },
+	{ "hello world", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGQ=" },
+	{ "hello worlds", 80, FALSE, "aGVsbG8gd29ybGRz" },
+	{ "hello worlds", 4, FALSE, "aGVs\nbG8g\nd29y\nbGRz" },
+	{ "hello worlds", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGRz" },
+	{ "hell world", 80, FALSE, "aGVsbCB3b3JsZA==" },
+	{ "hell world", 4, FALSE, "aGVs\nbCB3\nb3Js\nZA==" },
+	{ "hell world", 4, TRUE, "aGVs\r\nbCB3\r\nb3Js\r\nZA==" },
+	{ "hello to the world!!", 80, FALSE,
+		"aGVsbG8gdG8gdGhlIHdvcmxkISE=" },
+	{ "hello to the world!!", 8, FALSE,
+		"aGVsbG8g\ndG8gdGhl\nIHdvcmxk\nISE=" },
+	{ "hello to the world!!", 8, TRUE,
+		"aGVsbG8g\r\ndG8gdGhl\r\nIHdvcmxk\r\nISE=" },
 };
 
+
 static const char *hello = "hello world";
 
 static void encode_test(const char *text, unsigned int chars_per_line,
@@ -24,6 +37,7 @@
 	unsigned int i, text_len = strlen(text);
 	struct istream *input, *input_data;
 	const unsigned char *data;
+	uoff_t stream_size;
 	size_t size;
 	ssize_t ret;
 
@@ -43,6 +57,10 @@
 	data = i_stream_get_data(input, &size);
 	test_assert(size == strlen(output) && memcmp(data, output, size) == 0);
 
+	ret = i_stream_get_size(input, TRUE, &stream_size);
+	test_assert(ret > 0);
+	test_assert(size == stream_size);
+
 	i_stream_unref(&input);
 	i_stream_unref(&input_data);
 }