MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
base64.c
1 /* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
2 
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.
6 
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.
11 
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 */
15 
16 #include <my_global.h>
17 #include <m_string.h> /* strchr() */
18 #include <m_ctype.h> /* my_isspace() */
19 #include <base64.h>
20 
21 #ifndef MAIN
22 
23 static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
24  "abcdefghijklmnopqrstuvwxyz"
25  "0123456789+/";
26 
31 int
32 base64_encode_max_arg_length()
33 {
34 #if (SIZEOF_INT == 8)
35  /*
36  6827690988321067803 -> 9223372036854775805
37  6827690988321067804 -> -9223372036854775807
38  */
39  return 0x5EC0D4C77B03531BLL
40 #else
41  /*
42  1589695686 -> 2147483646
43  1589695687 -> -2147483645
44  */
45  return 0x5EC0D4C6;
46 #endif
47 }
48 
49 
50 int
51 base64_needed_encoded_length(int length_of_data)
52 {
53  int nb_base64_chars;
54  nb_base64_chars= (length_of_data + 2) / 3 * 4;
55 
56  return
57  nb_base64_chars + /* base64 char incl padding */
58  (nb_base64_chars - 1)/ 76 + /* newlines */
59  1; /* NUL termination of string */
60 }
61 
62 
67 int
68 base64_decode_max_arg_length()
69 {
70 #if (SIZEOF_INT == 8)
71  return 0x2AAAAAAAAAAAAAAALL;
72 #else
73  return 0x2AAAAAAA;
74 #endif
75 }
76 
77 
78 int
79 base64_needed_decoded_length(int length_of_encoded_data)
80 {
81  return (int) ceil(length_of_encoded_data * 3 / 4);
82 }
83 
84 
85 /*
86  Encode a data as base64.
87 
88  Note: We require that dst is pre-allocated to correct size.
89  See base64_needed_encoded_length().
90 */
91 
92 int
93 base64_encode(const void *src, size_t src_len, char *dst)
94 {
95  const unsigned char *s= (const unsigned char*)src;
96  size_t i= 0;
97  size_t len= 0;
98 
99  for (; i < src_len; len += 4)
100  {
101  unsigned c;
102 
103  if (len == 76)
104  {
105  len= 0;
106  *dst++= '\n';
107  }
108 
109  c= s[i++];
110  c <<= 8;
111 
112  if (i < src_len)
113  c += s[i];
114  c <<= 8;
115  i++;
116 
117  if (i < src_len)
118  c += s[i];
119  i++;
120 
121  *dst++= base64_table[(c >> 18) & 0x3f];
122  *dst++= base64_table[(c >> 12) & 0x3f];
123 
124  if (i > (src_len + 1))
125  *dst++= '=';
126  else
127  *dst++= base64_table[(c >> 6) & 0x3f];
128 
129  if (i > src_len)
130  *dst++= '=';
131  else
132  *dst++= base64_table[(c >> 0) & 0x3f];
133  }
134  *dst= '\0';
135 
136  return 0;
137 }
138 
139 
140 /*
141  Base64 decoder stream
142 */
143 typedef struct my_base64_decoder_t
144 {
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 */
152 
153 
154 /*
155  Helper table for decoder.
156  -2 means "space character"
157  -1 means "bad character"
158  Non-negative values mean valid base64 encoding character.
159 */
160 static int8
161 from_base64_table[]=
162 {
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
179 };
180 
181 
196 static inline my_bool
197 my_base64_decoder_skip_spaces(MY_BASE64_DECODER *decoder)
198 {
199  for ( ; decoder->src < decoder->end; decoder->src++)
200  {
201  if (from_base64_table[(uchar) *decoder->src] != -2)
202  return FALSE;
203  }
204  if (decoder->state > 0)
205  decoder->error= 1; /* Unexpected end-of-input found */
206  return TRUE;
207 }
208 
209 
221 static inline my_bool
222 my_base64_add(MY_BASE64_DECODER *decoder)
223 {
224  int res;
225  decoder->c <<= 6;
226  if ((res= from_base64_table[(uchar) *decoder->src++]) < 0)
227  return (decoder->error= TRUE);
228  decoder->c+= (uint) res;
229  return FALSE;
230 }
231 
232 
243 static inline my_bool
244 my_base64_decoder_getch(MY_BASE64_DECODER *decoder)
245 {
246  if (my_base64_decoder_skip_spaces(decoder))
247  return TRUE; /* End-of-input */
248 
249  if (!my_base64_add(decoder)) /* Valid base64 character found */
250  {
251  if (decoder->mark)
252  {
253  /* If we have scanned '=' already, then only '=' is valid */
254  DBUG_ASSERT(decoder->state == 3);
255  decoder->error= 1;
256  decoder->src--;
257  return TRUE; /* expected '=', but encoding character found */
258  }
259  decoder->state++;
260  return FALSE;
261  }
262 
263  /* Process error */
264  switch (decoder->state)
265  {
266  case 0:
267  case 1:
268  decoder->src--;
269  return TRUE; /* base64 character expected */
270  break;
271 
272  case 2:
273  case 3:
274  if (decoder->src[-1] == '=')
275  {
276  decoder->error= 0; /* Not an error - it's a pad character */
277  decoder->mark++;
278  }
279  else
280  {
281  decoder->src--;
282  return TRUE; /* base64 character or '=' expected */
283  }
284  break;
285 
286  default:
287  DBUG_ASSERT(0);
288  return TRUE; /* Wrong state, should not happen */
289  }
290 
291  decoder->state++;
292  return FALSE;
293 }
294 
295 
316 int
317 base64_decode(const char *src_base, size_t len,
318  void *dst, const char **end_ptr, int flags)
319 {
320  char *d= (char*) dst;
321  MY_BASE64_DECODER decoder;
322 
323  decoder.src= src_base;
324  decoder.end= src_base + len;
325  decoder.error= 0;
326  decoder.mark= 0;
327 
328  for ( ; ; )
329  {
330  decoder.c= 0;
331  decoder.state= 0;
332 
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))
337  break;
338 
339  *d++= (decoder.c >> 16) & 0xff;
340  *d++= (decoder.c >> 8) & 0xff;
341  *d++= (decoder.c >> 0) & 0xff;
342 
343  if (decoder.mark)
344  {
345  d-= decoder.mark;
346  if (!(flags & MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS))
347  break;
348  decoder.mark= 0;
349  }
350  }
351 
352  /* Return error if there are more non-space characters */
353  decoder.state= 0;
354  if (!my_base64_decoder_skip_spaces(&decoder))
355  decoder.error= 1;
356 
357  if (end_ptr != NULL)
358  *end_ptr= decoder.src;
359 
360  return decoder.error ? -1 : (int) (d - (char*) dst);
361 }
362 
363 
364 #else /* MAIN */
365 
366 #define require(b) { \
367  if (!(b)) { \
368  printf("Require failed at %s:%d\n", __FILE__, __LINE__); \
369  abort(); \
370  } \
371 }
372 
373 
374 int
375 main(void)
376 {
377  int i;
378  size_t j;
379  size_t k, l;
380  size_t dst_len;
381  size_t needed_length;
382 
383  for (i= 0; i < 500; i++)
384  {
385  /* Create source data */
386  const size_t src_len= rand() % 1000 + 1;
387 
388  char * src= (char *) malloc(src_len);
389  char * s= src;
390  char * str;
391  char * dst;
392 
393  require(src);
394  for (j= 0; j<src_len; j++)
395  {
396  char c= rand();
397  *s++= c;
398  }
399 
400  /* Encode */
401  needed_length= base64_needed_encoded_length(src_len);
402  str= (char *) malloc(needed_length);
403  require(str);
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);
408 
409  /* Decode */
410  dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
411  require(dst);
412  dst_len= base64_decode(str, strlen(str), dst, NULL);
413  require(dst_len == src_len);
414 
415  if (memcmp(src, dst, src_len) != 0)
416  {
417  printf(" --------- src --------- --------- dst ---------\n");
418  for (k= 0; k<src_len; k+=8)
419  {
420  printf("%.4x ", (uint) k);
421  for (l=0; l<8 && k+l<src_len; l++)
422  {
423  unsigned char c= src[k+l];
424  printf("%.2x ", (unsigned)c);
425  }
426 
427  printf(" ");
428 
429  for (l=0; l<8 && k+l<dst_len; l++)
430  {
431  unsigned char c= dst[k+l];
432  printf("%.2x ", (unsigned)c);
433  }
434  printf("\n");
435  }
436  printf("src length: %.8x, dst length: %.8x\n",
437  (uint) src_len, (uint) dst_len);
438  require(0);
439  }
440  }
441  printf("Test succeeded.\n");
442  return 0;
443 }
444 
445 #endif