Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_base64.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
28#include "nilorea/n_base64.h"
29#include <string.h>
30
32static const unsigned char pr2six[256] =
33 {
34 /* ASCII table */
35 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
36 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
37 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
38 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
39 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
40 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
41 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
42 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
43 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
44 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
45 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
46 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
47 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
48 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
49 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
50 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
51
53static const bool ascii_upper_case_lookup_table[256] =
54 {
55 /* ASCII table , upper from 65 to 90 */
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64
60 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
61 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 256
72};
73
75static const bool ascii_lower_case_lookup_table[256] =
76 {
77 /* ASCII table , upper from 97 to 122 */
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 128
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 256
94};
95
97static const char basis_64[] =
98 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
99
105bool n_isupper(char c) {
106 return ascii_upper_case_lookup_table[(uint8_t)c];
107}
108
114bool n_islower(char c) {
115 return ascii_lower_case_lookup_table[(uint8_t)c];
116}
117
123bool n_isalpha(char c) {
124 return (ascii_lower_case_lookup_table[(uint8_t)c] || ascii_upper_case_lookup_table[(uint8_t)c]);
125}
126
132char n_toupper(char c) {
133 if (ascii_lower_case_lookup_table[(uint8_t)c])
134 return (char)(c - 32);
135 return c;
136}
137
143char n_tolower(char c) {
144 if (ascii_upper_case_lookup_table[(uint8_t)c])
145 return (char)(c + 32);
146 return c;
147}
148
154size_t n_base64_decode_len(N_STR* string) {
155 __n_assert(string, return 0);
156 size_t nbytesdecoded = 0;
157 size_t nprbytes = 0;
158
159 const unsigned char* bufin = (const unsigned char*)string->data;
160 const unsigned char* bufend = bufin + string->written;
161
162 while (pr2six[*(bufin++)] <= 63) {
163 if (bufin > bufend) {
164 n_log(LOG_ERR, "could not detect end of encoded string for N_STR %p", string);
165 return 0;
166 }
167 }
168
169 // Safely calculate the difference
170 if (bufin > (const unsigned char*)string->data) {
171 nprbytes = (size_t)(bufin - (const unsigned char*)string->data - 1);
172 } else {
173 // Handle unexpected cases where subtraction could be invalid
174 n_log(LOG_ERR, "invalid size of 0 for N_STR %p", string);
175 return 0;
176 }
177
178 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
179
180 return nbytesdecoded;
181}
182
189 __n_assert(bufcoded, return NULL);
190
191 size_t nbytesdecoded = 0;
192 size_t nprbytes = 0;
193
194 const unsigned char* bufin = (const unsigned char*)bufcoded->data;
195 const unsigned char* bufend = bufin + bufcoded->written;
196
197 while (pr2six[*(bufin++)] <= 63) {
198 if (bufin > bufend) {
199 n_log(LOG_ERR, "could not detect end of bufcoded string for N_STR %p", bufcoded);
200 return NULL;
201 }
202 }
203
204 // Safely calculate the difference
205 if (bufin > (const unsigned char*)bufcoded->data) {
206 nprbytes = (size_t)(bufin - (const unsigned char*)bufcoded->data - 1);
207 } else {
208 // Handle unexpected cases where subtraction could be invalid
209 n_log(LOG_ERR, "invalid encoded size of 0 for bufcoded N_STR %p", bufcoded);
210 return NULL;
211 }
212
213 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
214
215 N_STR* bufplain = new_nstr(nbytesdecoded + 1);
216 __n_assert(bufplain, return NULL);
217
218 unsigned char* bufout = (unsigned char*)bufplain->data;
219 bufin = (const unsigned char*)bufcoded->data;
220
221 while (nprbytes > 4) {
222 *(bufout++) =
223 (unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
224 *(bufout++) =
225 (unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
226 *(bufout++) =
227 (unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
228 bufin += 4;
229 nprbytes -= 4;
230 }
231
232 /* Note: (nprbytes == 1) would be an error, so just ignore that case */
233 if (nprbytes > 1) {
234 *(bufout++) =
235 (unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
236 }
237 if (nprbytes > 2) {
238 *(bufout++) =
239 (unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
240 }
241 if (nprbytes > 3) {
242 *(bufout++) =
243 (unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
244 }
245
246 *(bufout++) = '\0';
247 nbytesdecoded -= (4 - nprbytes) & 3;
248
249 bufplain->written = nbytesdecoded;
250
251 return bufplain;
252}
253
259size_t n_base64_encode_len(const N_STR* string) {
260 __n_assert(string, return 0);
261
262 return ((string->written + 2) / 3 * 4) + 1;
263}
264
271 __n_assert(input, return NULL);
272
273 size_t i = 0;
274 char* p = NULL;
275 const char* string = input->data;
276 size_t len = input->written;
277
278 size_t output_length = n_base64_encode_len(input);
279 if (output_length == 0) {
280 n_log(LOG_ERR, "invalid encoded size of 0 for N_STR *input %p", input);
281 return NULL;
282 }
283
284 N_STR* encoded = new_nstr(output_length + 1);
285 __n_assert(encoded, return NULL);
286
287 p = encoded->data;
288 for (i = 0; i + 2 < len; i += 3) {
289 *p++ = basis_64[(string[i] >> 2) & 0x3F];
290 *p++ = basis_64[((string[i] & 0x3) << 4) |
291 ((int)(string[i + 1] & 0xF0) >> 4)];
292 *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
293 ((int)(string[i + 2] & 0xC0) >> 6)];
294 *p++ = basis_64[string[i + 2] & 0x3F];
295 }
296 if (i < len) {
297 *p++ = basis_64[(string[i] >> 2) & 0x3F];
298 if (i == (len - 1)) {
299 *p++ = basis_64[((string[i] & 0x3) << 4)];
300 *p++ = '=';
301 } else {
302 *p++ = basis_64[((string[i] & 0x3) << 4) |
303 ((int)(string[i + 1] & 0xF0) >> 4)];
304 *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
305 }
306 *p++ = '=';
307 }
308
309 *p++ = '\0';
310
311 if ((p - encoded->data) > 0) {
312 encoded->written = (size_t)(p - encoded->data) - 1;
313 } else {
314 n_log(LOG_ERR, "invalid size of %d for encoded string from N_STR *input %p", (p - encoded->data), input);
315 free_nstr(&encoded);
316 return NULL;
317 }
318
319 return encoded;
320}
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
char n_tolower(char c)
convert char to lower case
Definition n_base64.c:143
N_STR * n_base64_decode(N_STR *bufcoded)
decode a N_STR *string
Definition n_base64.c:188
bool n_isupper(char c)
test if char c is uppercase
Definition n_base64.c:105
char n_toupper(char c)
convert char to upper case
Definition n_base64.c:132
bool n_islower(char c)
test if char c is lowercase
Definition n_base64.c:114
bool n_isalpha(char c)
test if char c is alphabetic
Definition n_base64.c:123
N_STR * n_base64_encode(N_STR *input)
encode a N_STR *string
Definition n_base64.c:270
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_ERR
error conditions
Definition n_log.h:76
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
Definition n_str.h:68
char * data
the string
Definition n_str.h:63
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:203
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:207
A box including a string and his lenght.
Definition n_str.h:61
size_t n_base64_decode_len(N_STR *string)
get the length of 'string' if it was base64 decoded
Definition n_base64.c:154
static const char basis_64[]
static lookup base64 alphabet
Definition n_base64.c:97
static const bool ascii_upper_case_lookup_table[256]
static upper case lookup ascii table
Definition n_base64.c:53
static const bool ascii_lower_case_lookup_table[256]
static lower case lookup ascii table
Definition n_base64.c:75
size_t n_base64_encode_len(const N_STR *string)
get the length of string if it was base64 encoded
Definition n_base64.c:259
static const unsigned char pr2six[256]
static lookup ascii table
Definition n_base64.c:32
Base64 encoding and decoding functions using N_STR.