1
/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
#include <my_global.h>
17
#include <m_string.h> /* strchr() */
18
#include <m_ctype.h> /* my_isspace() */
23
static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
24
"abcdefghijklmnopqrstuvwxyz"
28
* Maximum length base64_needed_encoded_length()
29
* can handle without overflow.
32
base64_encode_max_arg_length()
36
6827690988321067803 -> 9223372036854775805
37
6827690988321067804 -> -9223372036854775807
39
return 0x5EC0D4C77B03531BLL
42
1589695686 -> 2147483646
43
1589695687 -> -2147483645
51
base64_needed_encoded_length(int length_of_data)
54
nb_base64_chars= (length_of_data + 2) / 3 * 4;
57
nb_base64_chars + /* base64 char incl padding */
58
(nb_base64_chars - 1)/ 76 + /* newlines */
59
1; /* NUL termination of string */
64
* Maximum length base64_needed_decoded_length()
65
* can handle without overflow.
68
base64_decode_max_arg_length()
71
return 0x2AAAAAAAAAAAAAAALL;
79
base64_needed_decoded_length(int length_of_encoded_data)
81
return (int) ceil(length_of_encoded_data * 3 / 4);
86
Encode a data as base64.
88
Note: We require that dst is pre-allocated to correct size.
89
See base64_needed_encoded_length().
93
base64_encode(const void *src, size_t src_len, char *dst)
95
const unsigned char *s= (const unsigned char*)src;
99
for (; i < src_len; len += 4)
121
*dst++= base64_table[(c >> 18) & 0x3f];
122
*dst++= base64_table[(c >> 12) & 0x3f];
124
if (i > (src_len + 1))
127
*dst++= base64_table[(c >> 6) & 0x3f];
132
*dst++= base64_table[(c >> 0) & 0x3f];
141
Base64 decoder stream
143
typedef struct my_base64_decoder_t
145
const char *src; /* Pointer to the current input position */
146
const char *end; /* Pointer to the end of input buffer */
147
uint c; /* Collect bits into this number */
148
int error; /* Error code */
149
uchar state; /* Character number in the current group of 4 */
150
uchar mark; /* Number of padding marks in the current group */
155
Helper table for decoder.
156
-2 means "space character"
157
-1 means "bad character"
158
Non-negative values mean valid base64 encoding character.
163
/*00*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-1,-1,
164
/*10*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
165
/*20*/ -2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* !"#$%&'()*+,-./ */
166
/*30*/ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 0123456789:;<=>? */
167
/*40*/ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* @ABCDEFGHIJKLMNO */
168
/*50*/ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* PQRSTUVWXYZ[\]^_ */
169
/*60*/ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* `abcdefghijklmno */
170
/*70*/ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* pqrstuvwxyz{|}~ */
171
/*80*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
172
/*90*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
173
/*A0*/ -2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
174
/*B0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
175
/*C0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
176
/*D0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
177
/*E0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
178
/*F0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
183
* Skip leading spaces in a base64 encoded stream
184
* and stop on the first non-space character.
185
* decoder->src will point to the first non-space character,
186
* or to the end of the input string.
187
* In case when end-of-input met on unexpected position,
188
* decoder->error is also set to 1.
190
* @param decoder Pointer to MY_BASE64_DECODER
193
* FALSE on success (there are some more non-space input characters)
194
* TRUE on error (end-of-input found)
196
static inline my_bool
197
my_base64_decoder_skip_spaces(MY_BASE64_DECODER *decoder)
199
for ( ; decoder->src < decoder->end; decoder->src++)
201
if (from_base64_table[(uchar) *decoder->src] != -2)
204
if (decoder->state > 0)
205
decoder->error= 1; /* Unexpected end-of-input found */
211
* Convert the next character in a base64 encoded stream
212
* to a number in the range [0..63]
213
* and mix it with the previously collected value in decoder->c.
215
* @param decode base64 decoding stream
219
* TRUE on error (invalid base64 character found)
221
static inline my_bool
222
my_base64_add(MY_BASE64_DECODER *decoder)
226
if ((res= from_base64_table[(uchar) *decoder->src++]) < 0)
227
return (decoder->error= TRUE);
228
decoder->c+= (uint) res;
234
* Get the next character from a base64 encoded stream.
235
* Skip spaces, then scan the next base64 character or a pad character
236
* and collect bits into decoder->c.
238
* @param decoder Pointer to MY_BASE64_DECODER
240
* FALSE on success (a valid base64 encoding character found)
241
* TRUE on error (unexpected character or unexpected end-of-input found)
243
static inline my_bool
244
my_base64_decoder_getch(MY_BASE64_DECODER *decoder)
246
if (my_base64_decoder_skip_spaces(decoder))
247
return TRUE; /* End-of-input */
249
if (!my_base64_add(decoder)) /* Valid base64 character found */
253
/* If we have scanned '=' already, then only '=' is valid */
254
DBUG_ASSERT(decoder->state == 3);
257
return TRUE; /* expected '=', but encoding character found */
264
switch (decoder->state)
269
return TRUE; /* base64 character expected */
274
if (decoder->src[-1] == '=')
276
decoder->error= 0; /* Not an error - it's a pad character */
282
return TRUE; /* base64 character or '=' expected */
288
return TRUE; /* Wrong state, should not happen */
297
* Decode a base64 string
298
* The base64-encoded data in the range ['src','*end_ptr') will be
299
* decoded and stored starting at 'dst'. The decoding will stop
300
* after 'len' characters have been read from 'src', or when padding
301
* occurs in the base64-encoded data. In either case: if 'end_ptr' is
302
* non-null, '*end_ptr' will be set to point to the character after
303
* the last read character, even in the presence of error.
305
* Note: We require that 'dst' is pre-allocated to correct size.
307
* @param src Pointer to base64-encoded string
308
* @param len Length of string at 'src'
309
* @param dst Pointer to location where decoded data will be stored
310
* @param end_ptr Pointer to variable that will refer to the character
311
* after the end of the encoded data that were decoded.
313
* @flags flags e.g. allow multiple chunks
314
* @return Number of bytes written at 'dst', or -1 in case of failure
317
base64_decode(const char *src_base, size_t len,
318
void *dst, const char **end_ptr, int flags)
320
char *d= (char*) dst;
321
MY_BASE64_DECODER decoder;
323
decoder.src= src_base;
324
decoder.end= src_base + len;
333
if (my_base64_decoder_getch(&decoder) ||
334
my_base64_decoder_getch(&decoder) ||
335
my_base64_decoder_getch(&decoder) ||
336
my_base64_decoder_getch(&decoder))
339
*d++= (decoder.c >> 16) & 0xff;
340
*d++= (decoder.c >> 8) & 0xff;
341
*d++= (decoder.c >> 0) & 0xff;
346
if (!(flags & MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS))
352
/* Return error if there are more non-space characters */
354
if (!my_base64_decoder_skip_spaces(&decoder))
358
*end_ptr= decoder.src;
360
return decoder.error ? -1 : (int) (d - (char*) dst);
366
#define require(b) { \
368
printf("Require failed at %s:%d\n", __FILE__, __LINE__); \
381
size_t needed_length;
383
for (i= 0; i < 500; i++)
385
/* Create source data */
386
const size_t src_len= rand() % 1000 + 1;
388
char * src= (char *) malloc(src_len);
394
for (j= 0; j<src_len; j++)
401
needed_length= base64_needed_encoded_length(src_len);
402
str= (char *) malloc(needed_length);
404
for (k= 0; k < needed_length; k++)
405
str[k]= 0xff; /* Fill memory to check correct NUL termination */
406
require(base64_encode(src, src_len, str) == 0);
407
require(needed_length == strlen(str) + 1);
410
dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
412
dst_len= base64_decode(str, strlen(str), dst, NULL);
413
require(dst_len == src_len);
415
if (memcmp(src, dst, src_len) != 0)
417
printf(" --------- src --------- --------- dst ---------\n");
418
for (k= 0; k<src_len; k+=8)
420
printf("%.4x ", (uint) k);
421
for (l=0; l<8 && k+l<src_len; l++)
423
unsigned char c= src[k+l];
424
printf("%.2x ", (unsigned)c);
429
for (l=0; l<8 && k+l<dst_len; l++)
431
unsigned char c= dst[k+l];
432
printf("%.2x ", (unsigned)c);
436
printf("src length: %.8x, dst length: %.8x\n",
437
(uint) src_len, (uint) dst_len);
441
printf("Test succeeded.\n");