dovecot-2.2: Added istream-base64-decoder.
dovecot at dovecot.org
dovecot at dovecot.org
Fri Aug 10 06:51:22 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/39b1b519c033
changeset: 14845:39b1b519c033
user: Timo Sirainen <tss at iki.fi>
date: Fri Aug 10 06:45:25 2012 +0300
description:
Added istream-base64-decoder.
diffstat:
src/lib/Makefile.am | 4 +-
src/lib/istream-base64-decoder.c | 131 ++++++++++++++++++++++++++++++++++
src/lib/istream-base64-encoder.c | 2 +-
src/lib/istream-base64-encoder.h | 8 --
src/lib/istream-base64.h | 10 ++
src/lib/test-istream-base64-decoder.c | 69 +++++++++++++++++
src/lib/test-istream-base64-encoder.c | 2 +-
src/lib/test-lib.c | 1 +
src/lib/test-lib.h | 1 +
9 files changed, 217 insertions(+), 11 deletions(-)
diffs (truncated from 308 to 300 lines):
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/Makefile.am
--- a/src/lib/Makefile.am Fri Aug 10 06:03:11 2012 +0300
+++ b/src/lib/Makefile.am Fri Aug 10 06:45:25 2012 +0300
@@ -54,6 +54,7 @@
iostream-rawlog.c \
iso8601-date.c \
istream.c \
+ istream-base64-decoder.c \
istream-base64-encoder.c \
istream-chain.c \
istream-concat.c \
@@ -178,7 +179,7 @@
iostream-rawlog-private.h \
iso8601-date.h \
istream.h \
- istream-base64-encoder.h \
+ istream-base64.h \
istream-chain.h \
istream-concat.h \
istream-crlf.h \
@@ -263,6 +264,7 @@
test-hash-format.c \
test-hex-binary.c \
test-iso8601-date.c \
+ test-istream-base64-decoder.c \
test-istream-base64-encoder.c \
test-istream-concat.c \
test-istream-crlf.c \
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/istream-base64-decoder.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-base64-decoder.c Fri Aug 10 06:45:25 2012 +0300
@@ -0,0 +1,131 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "base64.h"
+#include "istream-private.h"
+#include "istream-base64.h"
+
+struct base64_decoder_istream {
+ struct istream_private istream;
+};
+
+static int i_stream_read_parent(struct istream_private *stream)
+{
+ size_t size;
+ ssize_t ret;
+
+ size = i_stream_get_data_size(stream->parent);
+ if (size >= 4)
+ return 1;
+
+ /* we have less than one base64 block.
+ see if there is more data available. */
+ ret = i_stream_read(stream->parent);
+ if (ret <= 0) {
+ stream->istream.stream_errno = stream->parent->stream_errno;
+ stream->istream.eof = stream->parent->eof;
+ return ret;
+ }
+ size = i_stream_get_data_size(stream->parent);
+ i_assert(size != 0);
+ return 1;
+}
+
+static int
+i_stream_base64_try_decode_block(struct base64_decoder_istream *bstream)
+{
+ struct istream_private *stream = &bstream->istream;
+ const unsigned char *data;
+ size_t size, avail, buffer_avail, pos;
+ buffer_t buf;
+
+ data = i_stream_get_data(stream->parent, &size);
+ if (size == 0)
+ return 0;
+
+ i_stream_try_alloc(stream, (size+3)/4*3, &avail);
+ buffer_avail = stream->buffer_size - stream->pos;
+
+ if ((size + 3) / 4 * 3 > buffer_avail) {
+ /* can't fit everything to destination buffer.
+ write as much as we can. */
+ size = (buffer_avail / 3) * 4;
+ if (size == 0)
+ return -2;
+ }
+
+ buffer_create_data(&buf, stream->w_buffer + stream->pos, buffer_avail);
+ if (base64_decode(data, size, &pos, &buf) < 0) {
+ stream->istream.stream_errno = EINVAL;
+ return -1;
+ }
+
+ stream->pos += buf.used;
+ i_stream_skip(stream->parent, pos);
+ return pos > 0 ? 1 : 0;
+}
+
+static ssize_t i_stream_base64_decoder_read(struct istream_private *stream)
+{
+ struct base64_decoder_istream *bstream =
+ (struct base64_decoder_istream *)stream;
+ size_t pre_count, post_count;
+ int ret;
+
+ do {
+ ret = i_stream_read_parent(stream);
+ if (ret <= 0) {
+ if (ret < 0 && stream->istream.stream_errno == 0 &&
+ i_stream_get_data_size(stream->parent) > 0) {
+ /* base64 input with a partial block */
+ stream->istream.stream_errno = EINVAL;
+ }
+ return ret;
+ }
+
+ /* encode as many blocks as fits into destination buffer */
+ pre_count = stream->pos - stream->skip;
+ while ((ret = i_stream_base64_try_decode_block(bstream)) > 0) ;
+ post_count = stream->pos - stream->skip;
+ } while (ret == 0);
+
+ if (ret < 0)
+ return ret;
+
+ i_assert(post_count > pre_count);
+ return post_count - pre_count;
+}
+
+static void
+i_stream_base64_decoder_seek(struct istream_private *stream,
+ uoff_t v_offset, bool mark)
+{
+ if (v_offset < stream->istream.v_offset) {
+ /* seeking backwards - go back to beginning and seek
+ forward from there. */
+ stream->parent_expected_offset = stream->parent_start_offset;
+ stream->skip = stream->pos = 0;
+ stream->istream.v_offset = 0;
+ i_stream_seek(stream->parent, 0);
+ }
+ i_stream_default_seek_nonseekable(stream, v_offset, mark);
+}
+
+struct istream *
+i_stream_create_base64_decoder(struct istream *input)
+{
+ struct base64_decoder_istream *bstream;
+
+ bstream = i_new(struct base64_decoder_istream, 1);
+ bstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
+
+ bstream->istream.read = i_stream_base64_decoder_read;
+ bstream->istream.seek = i_stream_base64_decoder_seek;
+
+ bstream->istream.istream.readable_fd = FALSE;
+ bstream->istream.istream.blocking = input->blocking;
+ bstream->istream.istream.seekable = input->seekable;
+ return i_stream_create(&bstream->istream, input,
+ i_stream_get_fd(input));
+}
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/istream-base64-encoder.c
--- a/src/lib/istream-base64-encoder.c Fri Aug 10 06:03:11 2012 +0300
+++ b/src/lib/istream-base64-encoder.c Fri Aug 10 06:45:25 2012 +0300
@@ -4,7 +4,7 @@
#include "buffer.h"
#include "base64.h"
#include "istream-private.h"
-#include "istream-base64-encoder.h"
+#include "istream-base64.h"
struct base64_encoder_istream {
struct istream_private istream;
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/istream-base64-encoder.h
--- a/src/lib/istream-base64-encoder.h Fri Aug 10 06:03:11 2012 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-#ifndef ISTREAM_BASE64_H
-#define ISTREAM_BASE64_H
-
-struct istream *
-i_stream_create_base64_encoder(struct istream *input,
- unsigned int chars_per_line, bool crlf);
-
-#endif
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/istream-base64.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-base64.h Fri Aug 10 06:45:25 2012 +0300
@@ -0,0 +1,10 @@
+#ifndef ISTREAM_BASE64_H
+#define ISTREAM_BASE64_H
+
+struct istream *
+i_stream_create_base64_encoder(struct istream *input,
+ unsigned int chars_per_line, bool crlf);
+struct istream *
+i_stream_create_base64_decoder(struct istream *input);
+
+#endif
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/test-istream-base64-decoder.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/test-istream-base64-decoder.c Fri Aug 10 06:45:25 2012 +0300
@@ -0,0 +1,69 @@
+/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "str.h"
+#include "istream-private.h"
+#include "istream-base64.h"
+
+struct {
+ const char *input;
+ const char *output;
+} tests[] = {
+ { "aGVsbG8gd29ybGQ=", "hello world" },
+ { "\naGVs\nbG8g\nd29y\nbGQ=\n", "hello world" },
+ { " aGVs \r\n bG8g \r\n d29y \t \r\n bGQ= \r\n\r\n", "hello world" },
+};
+
+static void
+decode_test(const char *base64_input, const char *output, bool broken_input)
+{
+ unsigned int base64_input_len = strlen(base64_input);
+ struct istream *input_data, *input;
+ const unsigned char *data;
+ size_t i, size;
+ int ret = 0;
+
+ input_data = test_istream_create_data(base64_input, base64_input_len);
+ test_istream_set_allow_eof(input_data, FALSE);
+ input = i_stream_create_base64_decoder(input_data);
+
+ for (i = 1; i <= base64_input_len; i++) {
+ test_istream_set_size(input_data, i);
+ while ((ret = i_stream_read(input)) > 0) ;
+ if (ret == -1 && broken_input)
+ break;
+ test_assert(ret == 0);
+ }
+ if (ret == 0) {
+ test_istream_set_allow_eof(input_data, TRUE);
+ while ((ret = i_stream_read(input)) > 0) ;
+ }
+ test_assert(ret == -1);
+ test_assert((input->stream_errno == 0 && !broken_input) ||
+ (input->stream_errno == EINVAL && broken_input));
+
+ data = i_stream_get_data(input, &size);
+ test_assert(size == strlen(output) && memcmp(data, output, size) == 0);
+ i_stream_unref(&input);
+ i_stream_unref(&input_data);
+}
+
+void test_istream_base64_decoder(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ test_begin(t_strdup_printf("istream base64 decoder %u", i+1));
+ decode_test(tests[i].input, tests[i].output, FALSE);
+ test_end();
+ }
+ test_begin("istream base64 decoder error");
+ decode_test("foo", "", TRUE);
+ decode_test("Zm9vC", "foo", TRUE);
+ decode_test("Zm9v!", "foo", TRUE);
+ decode_test("Zm9!v", "", TRUE);
+ decode_test("Zm9 v", "", TRUE);
+ decode_test("Zm 9v", "", TRUE);
+ decode_test("Z m9v", "", TRUE);
+ test_end();
+}
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/test-istream-base64-encoder.c
--- a/src/lib/test-istream-base64-encoder.c Fri Aug 10 06:03:11 2012 +0300
+++ b/src/lib/test-istream-base64-encoder.c Fri Aug 10 06:45:25 2012 +0300
@@ -3,7 +3,7 @@
#include "test-lib.h"
#include "str.h"
#include "istream-private.h"
-#include "istream-base64-encoder.h"
+#include "istream-base64.h"
static const char *hello = "hello world";
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/test-lib.c
--- a/src/lib/test-lib.c Fri Aug 10 06:03:11 2012 +0300
+++ b/src/lib/test-lib.c Fri Aug 10 06:45:25 2012 +0300
@@ -14,6 +14,7 @@
test_hash_format,
test_hex_binary,
test_iso8601_date,
+ test_istream_base64_decoder,
test_istream_base64_encoder,
test_istream_concat,
test_istream_crlf,
diff -r 51a9846bb2bd -r 39b1b519c033 src/lib/test-lib.h
--- a/src/lib/test-lib.h Fri Aug 10 06:03:11 2012 +0300
+++ b/src/lib/test-lib.h Fri Aug 10 06:45:25 2012 +0300
More information about the dovecot-cvs
mailing list