NeoMutt  2020-11-20
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 
45 static 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 
53 // clang-format off
63 const int Index64[128] = {
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 };
73 // clang-format on
74 
88 size_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 
136 int mutt_b64_decode(const char *in, char *out, size_t olen)
137 {
138  if (!in || !out)
139  return -1;
140 
141  int len = 0;
142  unsigned char digit4;
143 
144  do
145  {
146  const unsigned char digit1 = in[0];
147  if ((digit1 > 127) || (base64val(digit1) == BAD))
148  return -1;
149  const unsigned char digit2 = in[1];
150  if ((digit2 > 127) || (base64val(digit2) == BAD))
151  return -1;
152  const unsigned char digit3 = in[2];
153  if ((digit3 > 127) || ((digit3 != '=') && (base64val(digit3) == BAD)))
154  return -1;
155  digit4 = in[3];
156  if ((digit4 > 127) || ((digit4 != '=') && (base64val(digit4) == BAD)))
157  return -1;
158  in += 4;
159 
160  /* digits are already sanity-checked */
161  if (len == olen)
162  return len;
163  *out++ = (base64val(digit1) << 2) | (base64val(digit2) >> 4);
164  len++;
165  if (digit3 != '=')
166  {
167  if (len == olen)
168  return len;
169  *out++ = ((base64val(digit2) << 4) & 0xf0) | (base64val(digit3) >> 2);
170  len++;
171  if (digit4 != '=')
172  {
173  if (len == olen)
174  return len;
175  *out++ = ((base64val(digit3) << 6) & 0xc0) | base64val(digit4);
176  len++;
177  }
178  }
179  } while (*in && digit4 != '=');
180 
181  return len;
182 }
183 
191 size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
192 {
193  if (!buf)
194  return 0;
195 
196  mutt_buffer_alloc(buf, MAX((len * 2), 1024));
197  size_t num = mutt_b64_encode(in, len, buf->data, buf->dsize);
199  return num;
200 }
201 
209 int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
210 {
211  if (!buf)
212  return -1;
213 
215  int olen = mutt_b64_decode(in, buf->data, buf->dsize);
216  /* mutt_from_base64 returns raw bytes, so don't terminate the buffer either */
217  if (olen > 0)
218  buf->dptr = buf->data + olen;
219  else
220  buf->dptr = buf->data;
221 
222  return olen;
223 }
Memory management wrappers.
String manipulation buffer.
Definition: buffer.h:33
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:191
String manipulation functions.
#define MAX(a, b)
Definition: memory.h:30
size_t dsize
Length of data.
Definition: buffer.h:37
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
static const char B64Chars[64]
Characters of the Base64 encoding.
Definition: base64.c:45
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:209
Conversion to/from base64 encoding.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
General purpose object for storing and parsing strings.
#define base64val(ch)
Definition: base64.h:30
const int Index64[128]
Lookup table for Base64 encoding characters.
Definition: base64.c:63
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:136
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:265
#define BAD
Definition: base64.c:40