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 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
27#include "nilorea/n_base64.h"
28#include <string.h>
29
31static const unsigned char pr2six[256] =
32 {
33 /* ASCII table */
34 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
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, 62, 64, 64, 64, 63,
37 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
38 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
39 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
40 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
42 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 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
52static const bool ascii_upper_case_lookup_table[256] =
53 {
54 /* ASCII table , upper from 65 to 90 */
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, // 64
59 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 // 256
71};
72
74static const bool ascii_lower_case_lookup_table[256] =
75 {
76 /* ASCII table , upper from 97 to 122 */
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, // 64
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
84 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 128
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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 // 256
93};
94
96static const char basis_64[] =
97 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
98
104bool n_isupper(char c) {
105 return ascii_upper_case_lookup_table[(uint8_t)c];
106}
107
113bool n_islower(char c) {
114 return ascii_lower_case_lookup_table[(uint8_t)c];
115}
116
122bool n_isalpha(char c) {
123 return (ascii_lower_case_lookup_table[(uint8_t)c] || ascii_upper_case_lookup_table[(uint8_t)c]);
124}
125
131char n_toupper(char c) {
132 if (ascii_lower_case_lookup_table[(uint8_t)c])
133 return (char)(c - 32);
134 return c;
135}
136
142char n_tolower(char c) {
143 if (ascii_upper_case_lookup_table[(uint8_t)c])
144 return (char)(c + 32);
145 return c;
146}
147
153size_t n_base64_decode_len(N_STR* string) {
154 __n_assert(string, return 0);
155 size_t nbytesdecoded = 0;
156 size_t nprbytes = 0;
157
158 const unsigned char* bufin = (const unsigned char*)string->data;
159 const unsigned char* bufend = bufin + string->written;
160
161 while (pr2six[*(bufin++)] <= 63) {
162 if (bufin > bufend) {
163 n_log(LOG_ERR, "could not detect end of encoded string for N_STR %p", string);
164 return 0;
165 }
166 }
167
168 // Safely calculate the difference
169 if (bufin > (const unsigned char*)string->data) {
170 nprbytes = (size_t)(bufin - (const unsigned char*)string->data - 1);
171 } else {
172 // Handle unexpected cases where subtraction could be invalid
173 n_log(LOG_ERR, "invalid size of 0 for N_STR %p", string);
174 return 0;
175 }
176
177 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
178
179 return nbytesdecoded;
180}
181
188 __n_assert(bufcoded, return NULL);
189
190 size_t nbytesdecoded = 0;
191 size_t nprbytes = 0;
192
193 const unsigned char* bufin = (const unsigned char*)bufcoded->data;
194 const unsigned char* bufend = bufin + bufcoded->written;
195
196 while (pr2six[*(bufin++)] <= 63) {
197 if (bufin > bufend) {
198 n_log(LOG_ERR, "could not detect end of bufcoded string for N_STR %p", bufcoded);
199 return NULL;
200 }
201 }
202
203 // Safely calculate the difference
204 if (bufin > (const unsigned char*)bufcoded->data) {
205 nprbytes = (size_t)(bufin - (const unsigned char*)bufcoded->data - 1);
206 } else {
207 // Handle unexpected cases where subtraction could be invalid
208 n_log(LOG_ERR, "invalid encoded size of 0 for bufcoded N_STR %p", bufcoded);
209 return NULL;
210 }
211
212 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
213
214 N_STR* bufplain = new_nstr(nbytesdecoded + 1);
215 __n_assert(bufplain, return NULL);
216
217 unsigned char* bufout = (unsigned char*)bufplain->data;
218 bufin = (const unsigned char*)bufcoded->data;
219
220 while (nprbytes > 4) {
221 *(bufout++) =
222 (unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
223 *(bufout++) =
224 (unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
225 *(bufout++) =
226 (unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
227 bufin += 4;
228 nprbytes -= 4;
229 }
230
231 /* Note: (nprbytes == 1) would be an error, so just ignore that case */
232 if (nprbytes > 1) {
233 *(bufout++) =
234 (unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
235 }
236 if (nprbytes > 2) {
237 *(bufout++) =
238 (unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
239 }
240 if (nprbytes > 3) {
241 *(bufout++) =
242 (unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
243 }
244
245 *(bufout++) = '\0';
246 nbytesdecoded -= (4 - nprbytes) & 3;
247
248 bufplain->written = nbytesdecoded;
249
250 return bufplain;
251}
252
258size_t n_base64_encode_len(const N_STR* string) {
259 __n_assert(string, return 0);
260
261 return ((string->written + 2) / 3 * 4) + 1;
262}
263
270 __n_assert(input, return NULL);
271
272 size_t i = 0;
273 char* p = NULL;
274 const char* string = input->data;
275 size_t len = input->written;
276
277 size_t output_length = n_base64_encode_len(input);
278 if (output_length == 0) {
279 n_log(LOG_ERR, "invalid encoded size of 0 for N_STR *input %p", input);
280 return NULL;
281 }
282
283 N_STR* encoded = new_nstr(output_length + 1);
284 __n_assert(encoded, return NULL);
285
286 p = encoded->data;
287 for (i = 0; i + 2 < len; i += 3) {
288 *p++ = basis_64[(string[i] >> 2) & 0x3F];
289 *p++ = basis_64[((string[i] & 0x3) << 4) |
290 ((int)(string[i + 1] & 0xF0) >> 4)];
291 *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
292 ((int)(string[i + 2] & 0xC0) >> 6)];
293 *p++ = basis_64[string[i + 2] & 0x3F];
294 }
295 if (i < len) {
296 *p++ = basis_64[(string[i] >> 2) & 0x3F];
297 if (i == (len - 1)) {
298 *p++ = basis_64[((string[i] & 0x3) << 4)];
299 *p++ = '=';
300 } else {
301 *p++ = basis_64[((string[i] & 0x3) << 4) |
302 ((int)(string[i + 1] & 0xF0) >> 4)];
303 *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
304 }
305 *p++ = '=';
306 }
307
308 *p++ = '\0';
309
310 if ((p - encoded->data) > 0) {
311 encoded->written = (size_t)(p - encoded->data) - 1;
312 } else {
313 n_log(LOG_ERR, "invalid size of %d for encoded string from N_STR *input %p", (p - encoded->data), input);
314 free_nstr(&encoded);
315 return NULL;
316 }
317
318 return encoded;
319}
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
char n_tolower(char c)
convert char to lower case
Definition n_base64.c:142
N_STR * n_base64_decode(N_STR *bufcoded)
decode a N_STR *string
Definition n_base64.c:187
bool n_isupper(char c)
test if char c is uppercase
Definition n_base64.c:104
char n_toupper(char c)
convert char to upper case
Definition n_base64.c:131
bool n_islower(char c)
test if char c is lowercase
Definition n_base64.c:113
bool n_isalpha(char c)
test if char c is alphabetic
Definition n_base64.c:122
N_STR * n_base64_encode(N_STR *input)
encode a N_STR *string
Definition n_base64.c:269
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_ERR
error conditions
Definition n_log.h:75
size_t written
size of the written data inside the string
Definition n_str.h:66
char * data
the string
Definition n_str.h:62
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:201
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:206
A box including a string and his lenght.
Definition n_str.h:60
size_t n_base64_decode_len(N_STR *string)
get the length of 'string' if it was base64 decoded
Definition n_base64.c:153
static const char basis_64[]
static lookup base64 alphabet
Definition n_base64.c:96
static const bool ascii_upper_case_lookup_table[256]
static upper case lookup ascii table
Definition n_base64.c:52
static const bool ascii_lower_case_lookup_table[256]
static lower case lookup ascii table
Definition n_base64.c:74
size_t n_base64_encode_len(const N_STR *string)
get the length of string if it was base64 encoded
Definition n_base64.c:258
static const unsigned char pr2six[256]
static lookup ascii table
Definition n_base64.c:31
Base64 encoding and decoding functions using N_STR.