MySQL 8.1.0
Source Code Documentation
base64.h
Go to the documentation of this file.
1/* Copyright (c) 2003, 2023, 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
46static char base64_table[] =
47 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
48 "abcdefghijklmnopqrstuvwxyz"
49 "0123456789+/";
50
51/*
52 Base64 decoder stream
53*/
54typedef 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*/
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 */
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 */
137static 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 */
156static 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*/
202static 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*/
254static 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 */
315static 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) ||
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