From: Stephan Bosch Date: Tue, 15 Sep 2020 23:03:53 +0000 (+0200) Subject: lib: base64 - Add base64_encode_get_full_space(). X-Git-Tag: 2.3.13~118 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=334cd2fc2207ca4fe0bcb0e1cc208e1a92a637b1;p=thirdparty%2Fdovecot%2Fcore.git lib: base64 - Add base64_encode_get_full_space(). This translates the space in the destination buffer to the number of bytes that can be encoded at most to complete the full base64 encoding, including padding and newlines if configured. --- diff --git a/src/lib/base64.c b/src/lib/base64.c index de3bfaaeb8..7d41638313 100644 --- a/src/lib/base64.c +++ b/src/lib/base64.c @@ -137,6 +137,80 @@ size_t base64_encode_get_size(struct base64_encoder *enc, size_t src_size) return out_size; } +size_t base64_encode_get_full_space(struct base64_encoder *enc, + size_t dst_space) +{ + bool crlf = HAS_ALL_BITS(enc->flags, BASE64_ENCODE_FLAG_CRLF); + bool no_padding = HAS_ALL_BITS(enc->flags, + BASE64_ENCODE_FLAG_NO_PADDING); + size_t src_space = 0; + + i_assert(enc->w_buf_len <= sizeof(enc->w_buf)); + + if (enc->max_line_len < SIZE_MAX) { + size_t max_line_space, lines, nl_space; + + /* Calculate how many line endings must be added if all space + were used. */ + max_line_space = enc->max_line_len + (crlf ? 2 : 1); + lines = dst_space / max_line_space; + + /* Calculate how much space is used by newline characters and + subtract this from the available space. */ + nl_space = lines * (crlf ? 2 : 1); + if (dst_space <= nl_space) + return 0; + dst_space -= nl_space; + } + + if (dst_space <= enc->w_buf_len) + return 0; + dst_space -= enc->w_buf_len; + + if (enc->pending_lf) + dst_space--; + if (dst_space == 0) + return 0; + + /* Handle sub-position */ + switch (enc->sub_pos) { + case 0: + break; + case 1: + dst_space--; + src_space++; + /* fall through */ + case 2: + if (dst_space < 2) + return src_space; + dst_space -= 2; + src_space++; + break; + default: + i_unreached(); + } + + if (dst_space == 0) + return src_space; + + src_space += dst_space / 4 * 3; + if (no_padding) { + switch (dst_space % 4) { + case 0: + case 1: + break; + case 2: + src_space += 1; + break; + case 3: + src_space += 2; + break; + } + } + + return src_space; +} + static void base64_encode_more_data(struct base64_encoder *enc, const unsigned char *src_c, size_t src_size, diff --git a/src/lib/base64.h b/src/lib/base64.h index e879433f47..ec6ac17ae1 100644 --- a/src/lib/base64.h +++ b/src/lib/base64.h @@ -89,6 +89,12 @@ uoff_t base64_get_full_encoded_size(struct base64_encoder *enc, base64_encode_more() with the indicated src_size. */ size_t base64_encode_get_size(struct base64_encoder *enc, size_t src_size); +/* Translate the space in the destination buffer to the number of bytes that can + be encoded at most to complete the full base64 encoding, including padding + and newlines if configured. */ +size_t base64_encode_get_full_space(struct base64_encoder *enc, + size_t dst_space); + /* Translates binary data into some form of Base64. The src must not point to dest buffer. Returns TRUE when all the provided data is encoded. Returns FALSE when the space in the provided buffer is insufficient. The return value diff --git a/src/lib/test-base64.c b/src/lib/test-base64.c index 662e1f2085..5231c454b5 100644 --- a/src/lib/test-base64.c +++ b/src/lib/test-base64.c @@ -970,7 +970,7 @@ test_base64_random_lowlevel_stream(const struct base64_scheme *b64, struct base64_decoder dec; const unsigned char *buf_p, *buf_begin, *buf_end; int ret; - size_t out_space; + size_t out_space, out_full_size; void *out_data; buffer_t out; @@ -982,12 +982,13 @@ test_base64_random_lowlevel_stream(const struct base64_scheme *b64, buf_end = buf_begin + in_buf_size; base64_encode_init(&enc, b64, enc_flags, max_line_len); + out_full_size = base64_get_full_encoded_size(&enc, in_buf_size); out_space = 0; for (buf_p = buf_begin; buf_p < buf_end; ) { size_t buf_ch, out_ch; size_t left = (buf_end - buf_p); size_t used = buf1->used; - size_t src_pos, out_size; + size_t src_pos, out_size, src_full_space; bool eres; if (chunk_size == 0) { @@ -1005,6 +1006,11 @@ test_base64_random_lowlevel_stream(const struct base64_scheme *b64, if (buf_ch > left) buf_ch = left; + src_full_space = base64_encode_get_full_space( + &enc, out_full_size - used); + test_assert_idx(src_full_space >= (size_t)(buf_end - buf_p), + test_idx); + out_size = base64_encode_get_size(&enc, buf_ch); eres = base64_encode_more(&enc, buf_p, buf_ch, &src_pos, &out); @@ -1020,8 +1026,7 @@ test_base64_random_lowlevel_stream(const struct base64_scheme *b64, /* Verify encode */ - test_assert(base64_get_full_encoded_size(&enc, in_buf_size) == - buf1->used); + test_assert(out_full_size == buf1->used); buffer_set_used_size(buf2, 0); base64_encode_init(&enc, b64, enc_flags, max_line_len);