MySQL 8.3.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 /*
217 6827690988321067803 -> 9223372036854775805
218 6827690988321067804 -> -9223372036854775807
219 */
220 return 0x5EC0D4C77B03531BLL;
221}
222
223/*
224 Calculate how much memory needed for dst of base64_decode()
225*/
227 uint64 length_of_encoded_data) {
228 return static_cast<uint64>(
229 ceil(static_cast<double>(length_of_encoded_data * 3 / 4)));
230}
231
232/*
233 Maximum length base64_decode_needed_length() can accept with no overflow.
234*/
236 return 0x2AAAAAAAAAAAAAAALL;
237}
238
239/*
240 Encode data as a base64 string
241*/
242static inline int base64_encode(const void *src, size_t src_len, char *dst) {
243 const unsigned char *s = (const unsigned char *)src;
244 size_t i = 0;
245 size_t len = 0;
246
247 for (; i < src_len; len += 4) {
248 unsigned c;
249
250 if (len == 76) {
251 len = 0;
252 *dst++ = '\n';
253 }
254
255 c = s[i++];
256 c <<= 8;
257
258 if (i < src_len) c += s[i];
259 c <<= 8;
260 i++;
261
262 if (i < src_len) c += s[i];
263 i++;
264
265 *dst++ = base64_table[(c >> 18) & 0x3f];
266 *dst++ = base64_table[(c >> 12) & 0x3f];
267
268 if (i > (src_len + 1))
269 *dst++ = '=';
270 else
271 *dst++ = base64_table[(c >> 6) & 0x3f];
272
273 if (i > src_len)
274 *dst++ = '=';
275 else
276 *dst++ = base64_table[(c >> 0) & 0x3f];
277 }
278 *dst = '\0';
279
280 return 0;
281}
282
283/**
284 * Decode a base64 string
285 * The base64-encoded data in the range ['src','*end_ptr') will be
286 * decoded and stored starting at 'dst'. The decoding will stop
287 * after 'len' characters have been read from 'src', or when padding
288 * occurs in the base64-encoded data. In either case: if 'end_ptr' is
289 * non-null, '*end_ptr' will be set to point to the character after
290 * the last read character, even in the presence of error.
291 *
292 * Note: We require that 'dst' is pre-allocated to correct size.
293 *
294 * @param src_base Pointer to base64-encoded string
295 * @param len Length of string at 'src'
296 * @param dst Pointer to location where decoded data will be stored
297 * @param end_ptr Pointer to variable that will refer to the character
298 * after the end of the encoded data that were decoded.
299 * Can be NULL.
300 * @param flags flags e.g. allow multiple chunks
301 * @return Number of bytes written at 'dst', or -1 in case of failure
302 */
303static inline int64 base64_decode(const char *src_base, size_t len, void *dst,
304 const char **end_ptr, int flags) {
305 char *d = (char *)dst;
306 MY_BASE64_DECODER decoder;
307
308 decoder.src = src_base;
309 decoder.end = src_base + len;
310 decoder.error = 0;
311 decoder.mark = 0;
312
313 for (;;) {
314 decoder.c = 0;
315 decoder.state = 0;
316
317 if (my_base64_decoder_getch(&decoder) ||
318 my_base64_decoder_getch(&decoder) ||
320 break;
321
322 *d++ = (decoder.c >> 16) & 0xff;
323 *d++ = (decoder.c >> 8) & 0xff;
324 *d++ = (decoder.c >> 0) & 0xff;
325
326 if (decoder.mark) {
327 d -= decoder.mark;
329 decoder.mark = 0;
330 }
331 }
332
333 /* Return error if there are more non-space characters */
334 decoder.state = 0;
335 if (!my_base64_decoder_skip_spaces(&decoder)) decoder.error = 1;
336
337 if (end_ptr != nullptr) *end_ptr = decoder.src;
338
339 return decoder.error ? -1 : (int)(d - (char *)dst);
340}
341
342#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 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:226
#define MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS
Definition: base64.h:44
constexpr uint64 base64_decode_max_arg_length()
Definition: base64.h:235
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 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:303
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
constexpr uint64 base64_encode_max_arg_length()
Definition: base64.h:215
static int base64_encode(const void *src, size_t src_len, char *dst)
Definition: base64.h:242
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