NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
base64.c
Go to the documentation of this file.
1
34#include "config.h"
35#include "base64.h"
36#include "buffer.h"
37#include "memory.h"
38#include "string2.h"
39
40#define BAD -1
41
45static const char B64Chars[64] = {
46 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
47 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
48 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
49 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
50 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
51};
52
62const int Index64[128] = {
63 // clang-format off
64 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
65 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
66 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
67 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
68 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
69 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
70 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
71 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
72 // clang-format on
73};
74
88size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
89{
90 if (!in || !out)
91 return 0;
92
93 unsigned char *begin = (unsigned char *) out;
94 const unsigned char *inu = (const unsigned char *) in;
95
96 while ((inlen >= 3) && (outlen > 4))
97 {
98 *out++ = B64Chars[inu[0] >> 2];
99 *out++ = B64Chars[((inu[0] << 4) & 0x30) | (inu[1] >> 4)];
100 *out++ = B64Chars[((inu[1] << 2) & 0x3c) | (inu[2] >> 6)];
101 *out++ = B64Chars[inu[2] & 0x3f];
102 outlen -= 4;
103 inlen -= 3;
104 inu += 3;
105 }
106
107 /* clean up remainder */
108 if ((inlen > 0) && (outlen > 4))
109 {
110 unsigned char fragment;
111
112 *out++ = B64Chars[inu[0] >> 2];
113 fragment = (inu[0] << 4) & 0x30;
114 if (inlen > 1)
115 fragment |= inu[1] >> 4;
116 *out++ = B64Chars[fragment];
117 *out++ = (inlen < 2) ? '=' : B64Chars[(inu[1] << 2) & 0x3c];
118 *out++ = '=';
119 }
120 *out = '\0';
121 return out - (char *) begin;
122}
123
136int mutt_b64_decode(const char *in, char *out, size_t olen)
137{
138 if (!in || !*in || !out)
139 return -1;
140
141 int len = 0;
142
143 for (; *in; in += 4)
144 {
145 const unsigned char digit1 = in[0];
146 if ((digit1 > 127) || (base64val(digit1) == BAD))
147 return -1;
148 const unsigned char digit2 = in[1];
149 if ((digit2 > 127) || (base64val(digit2) == BAD))
150 return -1;
151
152 /* The 3rd and 4th bytes can be terminating padding chars ('='). Some
153 * mailers don't properly terminate base64-encoded strings, so we allow for
154 * the input string to terminate without padding. */
155 const unsigned char digit3 = in[2] ? in[2] : '=';
156 if ((digit3 > 127) || ((digit3 != '=') && (base64val(digit3) == BAD)))
157 return -1;
158 const unsigned char digit4 = (digit3 == '=') ? '=' : in[3];
159 if ((digit4 > 127) || ((digit4 != '=') && (base64val(digit4) == BAD)))
160 return -1;
161
162 /* digits are already sanity-checked */
163 if (len == olen)
164 return len;
165 *out++ = (base64val(digit1) << 2) | (base64val(digit2) >> 4);
166 len++;
167 if (digit3 != '=')
168 {
169 if (len == olen)
170 return len;
171 *out++ = ((base64val(digit2) << 4) & 0xf0) | (base64val(digit3) >> 2);
172 len++;
173 if (digit4 != '=')
174 {
175 if (len == olen)
176 return len;
177 *out++ = ((base64val(digit3) << 6) & 0xc0) | base64val(digit4);
178 len++;
179 }
180 }
181
182 /* did we reach the end? */
183 if (digit4 == '=')
184 {
185 break;
186 }
187 }
188
189 return len;
190}
191
199size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
200{
201 if (!buf)
202 return 0;
203
204 mutt_buffer_alloc(buf, MAX((len * 2), 1024));
205 size_t num = mutt_b64_encode(in, len, buf->data, buf->dsize);
207 return num;
208}
209
217int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
218{
219 if (!buf)
220 return -1;
221
223 int olen = mutt_b64_decode(in, buf->data, buf->dsize);
224 /* mutt_from_base64 returns raw bytes, so don't terminate the buffer either */
225 if (olen > 0)
226 mutt_buffer_seek(buf, olen);
227 else
228 mutt_buffer_seek(buf, 0);
229
230 return olen;
231}
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:88
size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:199
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:136
const int Index64[128]
Lookup table for Base64 encoding characters.
Definition: base64.c:62
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:217
static const char B64Chars[64]
Characters of the Base64 encoding.
Definition: base64.c:45
#define BAD
Definition: base64.c:40
Conversion to/from base64 encoding.
#define base64val(ch)
Definition: base64.h:30
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:483
General purpose object for storing and parsing strings.
Memory management wrappers.
#define MAX(a, b)
Definition: memory.h:30
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
String manipulation functions.
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35