Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_base64.c
Go to the documentation of this file.
1
9#include "nilorea/n_base64.h"
10#include <string.h>
11
13static const unsigned char pr2six[256] =
14 {
15 /* ASCII table */
16 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
17 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
18 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
19 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
20 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
21 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
22 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
23 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
24 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
25 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
26 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
27 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
28 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
29 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
30 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
31 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
32
34static const bool ascii_upper_case_lookup_table[256] =
35 {
36 /* ASCII table , upper from 65 to 90 */
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64
41 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
42 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 256
53};
54
56static const bool ascii_lower_case_lookup_table[256] =
57 {
58 /* ASCII table , upper from 97 to 122 */
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, // 64
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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
66 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 128
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,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 256
75};
76
78static const char basis_64[] =
79 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
80
86bool n_isupper(char c) {
87 return ascii_upper_case_lookup_table[(uint8_t)c];
88}
89
95bool n_islower(char c) {
96 return ascii_lower_case_lookup_table[(uint8_t)c];
97}
98
104bool n_isalpha(char c) {
105 return (ascii_lower_case_lookup_table[(uint8_t)c] || ascii_upper_case_lookup_table[(uint8_t)c]);
106}
107
113char n_toupper(char c) {
114 if (ascii_lower_case_lookup_table[(uint8_t)c])
115 return (char)(c - 32);
116 return c;
117}
118
124char n_tolower(char c) {
125 if (ascii_upper_case_lookup_table[(uint8_t)c])
126 return (char)(c + 32);
127 return c;
128}
129
135size_t n_base64_decode_len(N_STR* string) {
136 __n_assert(string, return 0);
137 size_t nbytesdecoded = 0;
138 size_t nprbytes = 0;
139
140 const unsigned char* bufin = (const unsigned char*)string->data;
141 const unsigned char* bufend = bufin + string->length; // End of the buffer
142
143 while (pr2six[*(bufin++)] <= 63) {
144 if (bufin >= bufend) {
145 n_log(LOG_ERR, "could not detect end of encoded string for N_STR %p", string);
146 return 0;
147 }
148 }
149
150 // Safely calculate the difference
151 if (bufin > (const unsigned char*)string->data) {
152 nprbytes = (size_t)(bufin - (const unsigned char*)string->data - 1);
153 } else {
154 // Handle unexpected cases where subtraction could be invalid
155 n_log(LOG_ERR, "invalid size of 0 for N_STR %p", string);
156 return 0;
157 }
158
159 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
160
161 return nbytesdecoded;
162}
163
170 __n_assert(bufcoded, return NULL);
171
172 size_t nbytesdecoded = 0;
173 size_t nprbytes = 0;
174
175 const unsigned char* bufin = (const unsigned char*)bufcoded->data;
176 const unsigned char* bufend = bufin + bufcoded->length; // End of the buffer
177
178 while (pr2six[*(bufin++)] <= 63) {
179 if (bufin >= bufend) {
180 n_log(LOG_ERR, "could not detect end of bufcoded string for N_STR %p", bufcoded);
181 return NULL;
182 }
183 }
184
185 // Safely calculate the difference
186 if (bufin > (const unsigned char*)bufcoded->data) {
187 nprbytes = (size_t)(bufin - (const unsigned char*)bufcoded->data - 1);
188 } else {
189 // Handle unexpected cases where subtraction could be invalid
190 n_log(LOG_ERR, "invalid encoded size of 0 for bufcoded N_STR %p", bufcoded);
191 return NULL;
192 }
193
194 nbytesdecoded = ((nprbytes + 3) / 4) * 3;
195
196 N_STR* bufplain = new_nstr(nbytesdecoded + 1);
197 __n_assert(bufplain, return NULL);
198
199 unsigned char* bufout = (unsigned char*)bufplain->data;
200 bufin = (const unsigned char*)bufcoded->data;
201
202 while (nprbytes > 4) {
203 *(bufout++) =
204 (unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
205 *(bufout++) =
206 (unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
207 *(bufout++) =
208 (unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
209 bufin += 4;
210 nprbytes -= 4;
211 }
212
213 /* Note: (nprbytes == 1) would be an error, so just ignore that case */
214 if (nprbytes > 1) {
215 *(bufout++) =
216 (unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
217 }
218 if (nprbytes > 2) {
219 *(bufout++) =
220 (unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
221 }
222 if (nprbytes > 3) {
223 *(bufout++) =
224 (unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
225 }
226
227 *(bufout++) = '\0';
228 nbytesdecoded -= (4 - nprbytes) & 3;
229
230 bufplain->written = nbytesdecoded;
231
232 return bufplain;
233}
234
240size_t n_base64_encode_len(N_STR* string) {
241 __n_assert(string, return 0);
242
243 return ((string->written + 2) / 3 * 4) + 1;
244}
245
252 __n_assert(input, return NULL);
253
254 size_t i = 0;
255 char* p = NULL;
256 char* string = input->data;
257 size_t len = input->written;
258
259 size_t output_length = n_base64_encode_len(input);
260 if (output_length == 0) {
261 n_log(LOG_ERR, "invalid encoded size of 0 for N_STR *input %p", input);
262 return NULL;
263 }
264
265 N_STR* encoded = new_nstr(output_length + 1);
266 __n_assert(encoded, return NULL);
267
268 p = encoded->data;
269 for (i = 0; i < len - 2; i += 3) {
270 *p++ = basis_64[(string[i] >> 2) & 0x3F];
271 *p++ = basis_64[((string[i] & 0x3) << 4) |
272 ((int)(string[i + 1] & 0xF0) >> 4)];
273 *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
274 ((int)(string[i + 2] & 0xC0) >> 6)];
275 *p++ = basis_64[string[i + 2] & 0x3F];
276 }
277 if (i < len) {
278 *p++ = basis_64[(string[i] >> 2) & 0x3F];
279 if (i == (len - 1)) {
280 *p++ = basis_64[((string[i] & 0x3) << 4)];
281 *p++ = '=';
282 } else {
283 *p++ = basis_64[((string[i] & 0x3) << 4) |
284 ((int)(string[i + 1] & 0xF0) >> 4)];
285 *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
286 }
287 *p++ = '=';
288 }
289
290 *p++ = '\0';
291
292 if ((p - encoded->data) > 0) {
293 encoded->written = (size_t)(p - encoded->data);
294 } else {
295 n_log(LOG_ERR, "invalid size of %d for encoded string from N_STR *input %p", (p - encoded->data), input);
296 free_nstr(&encoded);
297 return NULL;
298 }
299
300 return encoded;
301}
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:256
char n_tolower(char c)
is_alpha
Definition n_base64.c:124
N_STR * n_base64_decode(N_STR *bufcoded)
decode a N_STR *string
Definition n_base64.c:169
bool n_isupper(char c)
test if char c is uppercase
Definition n_base64.c:86
char n_toupper(char c)
is_alpha
Definition n_base64.c:113
bool n_islower(char c)
test if char c is lowercase
Definition n_base64.c:95
bool n_isalpha(char c)
is_alpha
Definition n_base64.c:104
N_STR * n_base64_encode(N_STR *input)
encode a N_STR *string
Definition n_base64.c:251
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:70
#define LOG_ERR
error conditions
Definition n_log.h:57
size_t written
size of the written data inside the string
Definition n_str.h:45
char * data
the string
Definition n_str.h:41
size_t length
length of string (in case we wanna keep information after the 0 end of string value)
Definition n_str.h:43
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:176
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:180
A box including a string and his lenght.
Definition n_str.h:39
size_t n_base64_decode_len(N_STR *string)
get the length of 'input' if it was base64 decoded
Definition n_base64.c:135
static const char basis_64[]
static lookup base64 alphabet
Definition n_base64.c:78
static const bool ascii_upper_case_lookup_table[256]
static upper case lookup ascii table
Definition n_base64.c:34
size_t n_base64_encode_len(N_STR *string)
get the length of string if it was base64 encoded
Definition n_base64.c:240
static const bool ascii_lower_case_lookup_table[256]
static lower case lookup ascii table
Definition n_base64.c:56
static const unsigned char pr2six[256]
static lookup ascii table
Definition n_base64.c:13
Base64 encoding and decoding functions using N_STR.