MySQL  8.0.27
Source Code Documentation
base64.h
Go to the documentation of this file.
1 /* Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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, version 2.0,
5  as published by the Free Software Foundation.
6 
7  This program is also distributed with certain software (including
8  but not limited to OpenSSL) that is licensed under separate terms,
9  as designated in a particular file or component or in included license
10  documentation. The authors of MySQL hereby grant you an additional
11  permission to link the program and your derivative works with the
12  separately licensed software that they have included with MySQL.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License, version 2.0, for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22 
23 #ifndef __BASE64_H_INCLUDED__
24 #define __BASE64_H_INCLUDED__
25 
26 /**
27  @file include/base64.h
28 */
29 
30 #include <stddef.h>
31 
32 #include <assert.h>
33 #include <math.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 
40 #include "my_config.h"
41 #include "my_inttypes.h"
42 
43 /* Allow multuple chunks 'AAA= AA== AA==', binlog uses this */
44 #define MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS 1
45 
46 static char base64_table[] =
47  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
48  "abcdefghijklmnopqrstuvwxyz"
49  "0123456789+/";
50 
51 /*
52  Base64 decoder stream
53 */
54 typedef struct my_base64_decoder_t {
55  const char *src; /* Pointer to the current input position */
56  const char *end; /* Pointer to the end of input buffer */
57  uint c; /* Collect bits into this number */
58  int error; /* Error code */
59  uchar state; /* Character number in the current group of 4 */
60  uchar mark; /* Number of padding marks in the current group */
62 
63 /*
64  Helper table for decoder.
65  -2 means "space character"
66  -1 means "bad character"
67  Non-negative values mean valid base64 encoding character.
68 */
69 static int8 from_base64_table[] = {
70  /*00*/ -1, -1, -1, -1, -1, -1, -1, -1,
71  -1, -2, -2, -2, -2, -2, -1, -1,
72  /*10*/ -1, -1, -1, -1, -1, -1, -1, -1,
73  -1, -1, -1, -1, -1, -1, -1, -1,
74  /*20*/ -2, -1, -1, -1, -1, -1, -1, -1,
75  -1, -1, -1, 62, -1, -1, -1, 63, /* !"#$%&'()*+,-./ */
76  /*30*/ 52, 53, 54, 55, 56, 57, 58, 59,
77  60, 61, -1, -1, -1, -1, -1, -1, /* 0123456789:;<=>? */
78  /*40*/ -1, 0, 1, 2, 3, 4, 5, 6,
79  7, 8, 9, 10, 11, 12, 13, 14, /* @ABCDEFGHIJKLMNO */
80  /*50*/ 15, 16, 17, 18, 19, 20, 21, 22,
81  23, 24, 25, -1, -1, -1, -1, -1, /* PQRSTUVWXYZ[\]^_ */
82  /*60*/ -1, 26, 27, 28, 29, 30, 31, 32,
83  33, 34, 35, 36, 37, 38, 39, 40, /* `abcdefghijklmno */
84  /*70*/ 41, 42, 43, 44, 45, 46, 47, 48,
85  49, 50, 51, -1, -1, -1, -1, -1, /* pqrstuvwxyz{|}~ */
86  /*80*/ -1, -1, -1, -1, -1, -1, -1, -1,
87  -1, -1, -1, -1, -1, -1, -1, -1,
88  /*90*/ -1, -1, -1, -1, -1, -1, -1, -1,
89  -1, -1, -1, -1, -1, -1, -1, -1,
90  /*A0*/ -2, -1, -1, -1, -1, -1, -1, -1,
91  -1, -1, -1, -1, -1, -1, -1, -1,
92  /*B0*/ -1, -1, -1, -1, -1, -1, -1, -1,
93  -1, -1, -1, -1, -1, -1, -1, -1,
94  /*C0*/ -1, -1, -1, -1, -1, -1, -1, -1,
95  -1, -1, -1, -1, -1, -1, -1, -1,
96  /*D0*/ -1, -1, -1, -1, -1, -1, -1, -1,
97  -1, -1, -1, -1, -1, -1, -1, -1,
98  /*E0*/ -1, -1, -1, -1, -1, -1, -1, -1,
99  -1, -1, -1, -1, -1, -1, -1, -1,
100  /*F0*/ -1, -1, -1, -1, -1, -1, -1, -1,
101  -1, -1, -1, -1, -1, -1, -1, -1};
102 
103 /**
104  * Skip leading spaces in a base64 encoded stream
105  * and stop on the first non-space character.
106  * decoder->src will point to the first non-space character,
107  * or to the end of the input string.
108  * In case when end-of-input met on unexpected position,
109  * decoder->error is also set to 1.
110  *
111  * @param decoder Pointer to MY_BASE64_DECODER
112  *
113  * @return
114  * false on success (there are some more non-space input characters)
115  * true on error (end-of-input found)
116  */
117 static inline bool my_base64_decoder_skip_spaces(MY_BASE64_DECODER *decoder) {
118  for (; decoder->src < decoder->end; decoder->src++) {
119  if (from_base64_table[(uchar)*decoder->src] != -2) return false;
120  }
121  if (decoder->state > 0)
122  decoder->error = 1; /* Unexpected end-of-input found */
123  return true;
124 }
125 
126 /**
127  * Convert the next character in a base64 encoded stream
128  * to a number in the range [0..63]
129  * and mix it with the previously collected value in decoder->c.
130  *
131  * @param decoder base64 decoding stream
132  *
133  * @return
134  * false on success
135  * true on error (invalid base64 character found)
136  */
137 static inline bool my_base64_add(MY_BASE64_DECODER *decoder) {
138  int res;
139  decoder->c <<= 6;
140  if ((res = from_base64_table[(uchar)*decoder->src++]) < 0)
141  return (decoder->error = true);
142  decoder->c += (uint)res;
143  return false;
144 }
145 
146 /**
147  * Get the next character from a base64 encoded stream.
148  * Skip spaces, then scan the next base64 character or a pad character
149  * and collect bits into decoder->c.
150  *
151  * @param decoder Pointer to MY_BASE64_DECODER
152  * @return
153  * false on success (a valid base64 encoding character found)
154  * true on error (unexpected character or unexpected end-of-input found)
155  */
156 static inline bool my_base64_decoder_getch(MY_BASE64_DECODER *decoder) {
157  if (my_base64_decoder_skip_spaces(decoder)) return true; /* End-of-input */
158 
159  if (!my_base64_add(decoder)) /* Valid base64 character found */
160  {
161  if (decoder->mark) {
162  /* If we have scanned '=' already, then only '=' is valid */
163  assert(decoder->state == 3);
164  decoder->error = 1;
165  decoder->src--;
166  return true; /* expected '=', but encoding character found */
167  }
168  decoder->state++;
169  return false;
170  }
171 
172  /* Process error */
173  switch (decoder->state) {
174  case 0:
175  case 1:
176  decoder->src--;
177  return true; /* base64 character expected */
178 
179  case 2:
180  case 3:
181  if (decoder->src[-1] == '=') {
182  decoder->error = 0; /* Not an error - it's a pad character */
183  decoder->mark++;
184  } else {
185  decoder->src--;
186  return true; /* base64 character or '=' expected */
187  }
188  break;
189 
190  default:
191  assert(0);
192  return true; /* Wrong state, should not happen */
193  }
194 
195  decoder->state++;
196  return false;
197 }
198 
199 /*
200  Calculate how much memory needed for dst of base64_encode()
201 */
202 static inline uint64 base64_needed_encoded_length(uint64 length_of_data) {
203  uint64 nb_base64_chars;
204  if (length_of_data == 0) return 1;
205  nb_base64_chars = (length_of_data + 2) / 3 * 4;
206 
207  return nb_base64_chars + /* base64 char incl padding */
208  (nb_base64_chars - 1) / 76 + /* newlines */
209  1; /* NUL termination of string */
210 }
211 
212 /*
213  Maximum length base64_encode_needed_length() can accept with no overflow.
214 */
216 #if (SIZEOF_VOIDP == 8)
217  /*
218  6827690988321067803 -> 9223372036854775805
219  6827690988321067804 -> -9223372036854775807
220  */
221  return 0x5EC0D4C77B03531BLL;
222 #else
223  /*
224  1589695686 -> 2147483646
225  1589695687 -> -2147483645
226  */
227  return 0x5EC0D4C6;
228 #endif
229 }
230 
231 /*
232  Calculate how much memory needed for dst of base64_decode()
233 */
235  uint64 length_of_encoded_data) {
236  return static_cast<uint64>(
237  ceil(static_cast<double>(length_of_encoded_data * 3 / 4)));
238 }
239 
240 /*
241  Maximum length base64_decode_needed_length() can accept with no overflow.
242 */
244 #if (SIZEOF_VOIDP == 8)
245  return 0x2AAAAAAAAAAAAAAALL;
246 #else
247  return 0x2AAAAAAA;
248 #endif
249 }
250 
251 /*
252  Encode data as a base64 string
253 */
254 static inline int base64_encode(const void *src, size_t src_len, char *dst) {
255  const unsigned char *s = (const unsigned char *)src;
256  size_t i = 0;
257  size_t len = 0;
258 
259  for (; i < src_len; len += 4) {
260  unsigned c;
261 
262  if (len == 76) {
263  len = 0;
264  *dst++ = '\n';
265  }
266 
267  c = s[i++];
268  c <<= 8;
269 
270  if (i < src_len) c += s[i];
271  c <<= 8;
272  i++;
273 
274  if (i < src_len) c += s[i];
275  i++;
276 
277  *dst++ = base64_table[(c >> 18) & 0x3f];
278  *dst++ = base64_table[(c >> 12) & 0x3f];
279 
280  if (i > (src_len + 1))
281  *dst++ = '=';
282  else
283  *dst++ = base64_table[(c >> 6) & 0x3f];
284 
285  if (i > src_len)
286  *dst++ = '=';
287  else
288  *dst++ = base64_table[(c >> 0) & 0x3f];
289  }
290  *dst = '\0';
291 
292  return 0;
293 }
294 
295 /**
296  * Decode a base64 string
297  * The base64-encoded data in the range ['src','*end_ptr') will be
298  * decoded and stored starting at 'dst'. The decoding will stop
299  * after 'len' characters have been read from 'src', or when padding
300  * occurs in the base64-encoded data. In either case: if 'end_ptr' is
301  * non-null, '*end_ptr' will be set to point to the character after
302  * the last read character, even in the presence of error.
303  *
304  * Note: We require that 'dst' is pre-allocated to correct size.
305  *
306  * @param src_base Pointer to base64-encoded string
307  * @param len Length of string at 'src'
308  * @param dst Pointer to location where decoded data will be stored
309  * @param end_ptr Pointer to variable that will refer to the character
310  * after the end of the encoded data that were decoded.
311  * Can be NULL.
312  * @param flags flags e.g. allow multiple chunks
313  * @return Number of bytes written at 'dst', or -1 in case of failure
314  */
315 static inline int64 base64_decode(const char *src_base, size_t len, void *dst,
316  const char **end_ptr, int flags) {
317  char *d = (char *)dst;
318  MY_BASE64_DECODER decoder;
319 
320  decoder.src = src_base;
321  decoder.end = src_base + len;
322  decoder.error = 0;
323  decoder.mark = 0;
324 
325  for (;;) {
326  decoder.c = 0;
327  decoder.state = 0;
328 
329  if (my_base64_decoder_getch(&decoder) ||
330  my_base64_decoder_getch(&decoder) ||
331  my_base64_decoder_getch(&decoder) || my_base64_decoder_getch(&decoder))
332  break;
333 
334  *d++ = (decoder.c >> 16) & 0xff;
335  *d++ = (decoder.c >> 8) & 0xff;
336  *d++ = (decoder.c >> 0) & 0xff;
337 
338  if (decoder.mark) {
339  d -= decoder.mark;
341  decoder.mark = 0;
342  }
343  }
344 
345  /* Return error if there are more non-space characters */
346  decoder.state = 0;
347  if (!my_base64_decoder_skip_spaces(&decoder)) decoder.error = 1;
348 
349  if (end_ptr != nullptr) *end_ptr = decoder.src;
350 
351  return decoder.error ? -1 : (int)(d - (char *)dst);
352 }
353 
354 #endif /* !__BASE64_H_INCLUDED__ */
static int flags[50]
Definition: hp_test1.cc:39
static bool my_base64_decoder_getch(MY_BASE64_DECODER *decoder)
Get the next character from a base64 encoded stream.
Definition: base64.h:156
static uint64 base64_encode_max_arg_length()
Definition: base64.h:215
static bool my_base64_add(MY_BASE64_DECODER *decoder)
Convert the next character in a base64 encoded stream to a number in the range [0....
Definition: base64.h:137
static char base64_table[]
Definition: base64.h:46
static uint64 base64_needed_decoded_length(uint64 length_of_encoded_data)
Definition: base64.h:234
#define MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS
Definition: base64.h:44
struct my_base64_decoder_t MY_BASE64_DECODER
static int8 from_base64_table[]
Definition: base64.h:69
static uint64 base64_needed_encoded_length(uint64 length_of_data)
Definition: base64.h:202
static uint64 base64_decode_max_arg_length()
Definition: base64.h:243
static int64 base64_decode(const char *src_base, size_t len, void *dst, const char **end_ptr, int flags)
Decode a base64 string The base64-encoded data in the range ['src','*end_ptr') will be decoded and st...
Definition: base64.h:315
static bool my_base64_decoder_skip_spaces(MY_BASE64_DECODER *decoder)
Skip leading spaces in a base64 encoded stream and stop on the first non-space character.
Definition: base64.h:117
static int base64_encode(const void *src, size_t src_len, char *dst)
Definition: base64.h:254
if(!(yy_init))
Definition: lexyy.cc:1144
Some integer typedefs for easier portability.
unsigned char uchar
Definition: my_inttypes.h:51
int64_t int64
Definition: my_inttypes.h:67
int8_t int8
Definition: my_inttypes.h:61
uint64_t uint64
Definition: my_inttypes.h:68
Definition: base64.h:54
uchar mark
Definition: base64.h:60
int error
Definition: base64.h:58
uchar state
Definition: base64.h:59
const char * end
Definition: base64.h:56
uint c
Definition: base64.h:57
const char * src
Definition: base64.h:55
unsigned int uint
Definition: uca-dump.cc:29