]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: base64 - Restructure encoder to always fill the output buffer as much as possible.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Tue, 3 Sep 2019 16:37:57 +0000 (18:37 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 10 Sep 2019 07:02:37 +0000 (10:02 +0300)
This is not strictly required, but makes the encoder easier to use in streams
and less bug-prone in incremental encoding applications in general.

src/lib/base64.c
src/lib/base64.h

index 9518254e802542a4f283c765402bff3864904f42..60ceb132f95c71d1f95f97cf962823953cdb52dd 100644 (file)
@@ -362,8 +362,7 @@ bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest)
        bool padding = HAS_NO_BITS(enc->flags, BASE64_ENCODE_FLAG_NO_PADDING);
        unsigned char *ptr, *end;
        size_t dst_avail, line_avail, write;
-       unsigned char w_buf[9];
-       unsigned int w_buf_len = 0, w_buf_pos = 0;
+       unsigned int w_buf_pos = 0;
 
        dst_avail = 0;
        if (dest != NULL)
@@ -375,8 +374,6 @@ bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest)
                if (dst_avail == 0)
                        return FALSE;
                i_assert(enc->w_buf_len <= sizeof(enc->w_buf));
-               memcpy(w_buf, enc->w_buf, enc->w_buf_len);
-               w_buf_len += enc->w_buf_len;
        }
 
        i_assert(enc->max_line_len > 0);
@@ -387,22 +384,22 @@ bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest)
        case 0:
                break;
        case 1:
-               i_assert(w_buf_len < (sizeof(w_buf) - 3));
-               w_buf[w_buf_len] = b64enc[enc->buf];
-               w_buf_len ++;
+               i_assert(enc->w_buf_len <= (sizeof(enc->w_buf) - 3));
+               enc->w_buf[enc->w_buf_len] = b64enc[enc->buf];
+               enc->w_buf_len++;
                if (padding) {
-                       w_buf[w_buf_len + 0] =  '=';
-                       w_buf[w_buf_len + 1] =  '=';
-                       w_buf_len += 2;
+                       enc->w_buf[enc->w_buf_len + 0] =  '=';
+                       enc->w_buf[enc->w_buf_len + 1] =  '=';
+                       enc->w_buf_len += 2;
                }
                break;
        case 2:
-               i_assert(w_buf_len < (sizeof(w_buf) - 2));
-               w_buf[w_buf_len] = b64enc[enc->buf];
-               w_buf_len++;
+               i_assert(enc->w_buf_len <= (sizeof(enc->w_buf) - 2));
+               enc->w_buf[enc->w_buf_len] = b64enc[enc->buf];
+               enc->w_buf_len++;
                if (padding) {
-                       w_buf[w_buf_len + 0] =  '=';
-                       w_buf_len++;
+                       enc->w_buf[enc->w_buf_len + 0] =  '=';
+                       enc->w_buf_len++;
                }
                break;
        default:
@@ -410,7 +407,7 @@ bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest)
        }
        enc->sub_pos = 0;
 
-       write = w_buf_len;
+       write = enc->w_buf_len;
        if (enc->max_line_len < SIZE_MAX && line_avail < write) {
                unsigned int lines;
 
@@ -426,30 +423,44 @@ bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest)
        }
 
        i_assert(dest != NULL);
-       if (dst_avail < write)
-               return FALSE;
+       if (write > dst_avail)
+               write = dst_avail;
 
        ptr = buffer_append_space_unsafe(dest, write);
        end = ptr + write;
        if (line_avail > 0) {
-               memcpy(ptr, w_buf, line_avail);
+               memcpy(ptr, enc->w_buf, line_avail);
                ptr += line_avail;
                w_buf_pos += line_avail;
        }
-       while (w_buf_pos < w_buf_len) {
+       while (ptr < end && w_buf_pos < enc->w_buf_len) {
                if (crlf) {
                        ptr[0] = '\r';
                        ptr++;
+                       if (ptr == end) {
+                               i_assert(enc->w_buf_len < sizeof(enc->w_buf));
+                               enc->w_buf[enc->w_buf_len++] = '\n';
+                               break;
+                       }
                }
                ptr[0] = '\n';
                ptr++;
+               if (ptr == end)
+                       break;
 
-               write = I_MIN(w_buf_len - w_buf_pos, enc->max_line_len);
-               memcpy(ptr, &w_buf[w_buf_pos], write);
+               write = I_MIN(enc->w_buf_len - w_buf_pos, enc->max_line_len);
+               write = I_MIN(write, (size_t)(end - ptr));
+               memcpy(ptr, &enc->w_buf[w_buf_pos], write);
                ptr += write;
                w_buf_pos += write;
+               i_assert(ptr <= end);
        }
        i_assert(ptr == end);
+       if (w_buf_pos < enc->w_buf_len) {
+               enc->w_buf_len -= w_buf_pos;
+               memmove(enc->w_buf, enc->w_buf + w_buf_pos, enc->w_buf_len);
+               return FALSE;
+       }
        enc->finished = TRUE;
        return TRUE;
 }
index f777619d8bdfe624018f7db4a39ce3d0f4b70cee..082b76e45bc441549decf073a7d1001eaee9eed0 100644 (file)
@@ -38,7 +38,7 @@ struct base64_encoder {
        unsigned char buf;
        size_t cur_line_len;
 
-       unsigned char w_buf[5];
+       unsigned char w_buf[10];
        unsigned int w_buf_len;
 
        bool finished:1;