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