Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | #include "gate/encode/base64.h" | ||
30 | #include "gate/strings.h" | ||
31 | #include "gate/results.h" | ||
32 | |||
33 | static char const* const base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
34 | static char const base64_nullchar = '='; | ||
35 | |||
36 | 27 | void gate_base64_enc3(char const* inputTriple, char* outputQuad) | |
37 | { | ||
38 | 27 | outputQuad[0] = base64_chars[((gate_uint8_t)inputTriple[0] >> 2) & 0x3f]; | |
39 | 27 | outputQuad[1] = base64_chars[(((gate_uint8_t)inputTriple[0] & 0x03) << 4) | (((gate_uint8_t)inputTriple[1] >> 4) & 0x0f)]; | |
40 | 27 | outputQuad[2] = base64_chars[(((gate_uint8_t)inputTriple[1] & 0x0f) << 2) | (((gate_uint8_t)inputTriple[2] >> 6) & 0x03)]; | |
41 | 27 | outputQuad[3] = base64_chars[(gate_uint8_t)inputTriple[2] & 0x3f]; | |
42 | 27 | } | |
43 | |||
44 | 3 | void gate_base64_enc2(char const* inputTuple, char* outputQuad) | |
45 | { | ||
46 | 3 | outputQuad[0] = base64_chars[((gate_uint8_t)inputTuple[0] >> 2) & 0x3f]; | |
47 | 3 | outputQuad[1] = base64_chars[(((gate_uint8_t)inputTuple[0] & 0x03) << 4) | (((gate_uint8_t)inputTuple[1] >> 4) & 0x0f)]; | |
48 | 3 | outputQuad[2] = base64_chars[((gate_uint8_t)inputTuple[1] & 0x0f) << 2]; | |
49 | 3 | outputQuad[3] = base64_nullchar; | |
50 | 3 | } | |
51 | |||
52 | ✗ | void gate_base64_enc1(char const* inputByte, char* outputQuad) | |
53 | { | ||
54 | ✗ | outputQuad[0] = base64_chars[((gate_uint8_t)inputByte[0] >> 2) & 0x3f]; | |
55 | ✗ | outputQuad[1] = base64_chars[((gate_uint8_t)inputByte[0] & 0x3) << 4]; | |
56 | ✗ | outputQuad[2] = base64_nullchar; | |
57 | ✗ | outputQuad[3] = base64_nullchar; | |
58 | ✗ | } | |
59 | |||
60 | 30 | gate_size_t gate_base64_dec(char const* inputQuad, char* outputTriple) | |
61 | { | ||
62 | 30 | gate_size_t pos1 = gate_str_char_pos(base64_chars, 64, inputQuad[0], 0); | |
63 | 30 | gate_size_t pos2 = gate_str_char_pos(base64_chars, 64, inputQuad[1], 0); | |
64 | 30 | gate_size_t pos3 = gate_str_char_pos(base64_chars, 64, inputQuad[2], 0); | |
65 | 30 | gate_size_t pos4 = gate_str_char_pos(base64_chars, 64, inputQuad[3], 0); | |
66 | 30 | gate_size_t ret = 0; | |
67 | 30 | gate_uint32_t quad = 0; | |
68 | |||
69 | do | ||
70 | { | ||
71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (pos1 == GATE_STR_NPOS) |
72 | { | ||
73 | ✗ | break; | |
74 | } | ||
75 | 30 | quad |= (gate_uint32_t)pos1 << 18; | |
76 | |||
77 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (pos2 == GATE_STR_NPOS) |
78 | { | ||
79 | ✗ | break; | |
80 | } | ||
81 | 30 | quad |= (gate_uint32_t)pos2 << 12; | |
82 | 30 | outputTriple[0] = (char)(gate_uint8_t)((quad >> 16) & 0xff); | |
83 | 30 | ++ret; | |
84 | |||
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (pos3 == GATE_STR_NPOS) |
86 | { | ||
87 | ✗ | break; | |
88 | } | ||
89 | 30 | quad |= (gate_uint32_t)pos3 << 6; | |
90 | 30 | outputTriple[1] = (char)(gate_uint8_t)((quad >> 8) & 0xff); | |
91 | 30 | ++ret; | |
92 | |||
93 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 27 times.
|
30 | if (pos4 == GATE_STR_NPOS) |
94 | { | ||
95 | 3 | break; | |
96 | } | ||
97 | 27 | quad |= (gate_uint32_t)pos4; | |
98 | 27 | outputTriple[2] = (char)(gate_uint8_t)(quad & 0xff); | |
99 | 27 | ++ret; | |
100 | |||
101 | } while (0); | ||
102 | |||
103 | 30 | return ret; | |
104 | } | ||
105 | |||
106 | |||
107 | 1 | gate_result_t gate_base64_encode(gate_string_t const* src, gate_strbuilder_t* dst) | |
108 | { | ||
109 | 1 | gate_result_t ret = GATE_RESULT_OK; | |
110 | 1 | char const* ptr = src->str; | |
111 | 1 | gate_size_t len = src->length; | |
112 | char buffer[4]; | ||
113 | |||
114 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | while (len >= 3) |
115 | { | ||
116 | 9 | gate_base64_enc3(ptr, buffer); | |
117 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | if (4 != gate_strbuilder_append_text(dst, buffer, 4)) |
118 | { | ||
119 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
120 | ✗ | break; | |
121 | } | ||
122 | 9 | len -= 3; | |
123 | 9 | ptr += 3; | |
124 | } | ||
125 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (GATE_SUCCEEDED(ret)) |
126 | { | ||
127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (len == 1) |
128 | { | ||
129 | ✗ | gate_base64_enc1(ptr, buffer); | |
130 | ✗ | if (4 != gate_strbuilder_append_text(dst, buffer, 4)) | |
131 | { | ||
132 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
133 | } | ||
134 | } | ||
135 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (len == 2) |
136 | { | ||
137 | 1 | gate_base64_enc2(ptr, buffer); | |
138 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (4 != gate_strbuilder_append_text(dst, buffer, 4)) |
139 | { | ||
140 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | 1 | return ret; | |
146 | } | ||
147 | 2 | gate_result_t gate_base64_encode_stream(gate_stream_t* src, gate_stream_t* dst) | |
148 | { | ||
149 | gate_result_t ret; | ||
150 | char srcbuffer[GATE_MAX_COPYBUFFER_LENGTH * 3 / 4]; | ||
151 | char dstbuffer[GATE_MAX_COPYBUFFER_LENGTH]; | ||
152 | gate_size_t returned; | ||
153 | gate_size_t converted; | ||
154 | gate_size_t written; | ||
155 | char const* ptrsrc; | ||
156 | char* ptrdst; | ||
157 | |||
158 | for (;;) | ||
159 | { | ||
160 | 2 | ret = gate_stream_read_block(src, srcbuffer, sizeof(srcbuffer), &returned); | |
161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (GATE_FAILED(ret)) |
162 | { | ||
163 | ✗ | break; | |
164 | } | ||
165 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (returned == 0) |
166 | { | ||
167 | 1 | break; | |
168 | } | ||
169 | 1 | ptrsrc = srcbuffer; | |
170 | 1 | ptrdst = dstbuffer; | |
171 | 1 | converted = 0; | |
172 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | while (returned >= 3) |
173 | { | ||
174 | 9 | gate_base64_enc3(ptrsrc, ptrdst); | |
175 | 9 | ptrsrc += 3; | |
176 | 9 | returned -= 3; | |
177 | 9 | ptrdst += 4; | |
178 | 9 | converted += 4; | |
179 | } | ||
180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (returned == 1) |
181 | { | ||
182 | ✗ | gate_base64_enc1(ptrsrc, ptrdst); | |
183 | ✗ | converted += 4; | |
184 | } | ||
185 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (returned == 2) |
186 | { | ||
187 | 1 | gate_base64_enc2(ptrsrc, ptrdst); | |
188 | 1 | converted += 4; | |
189 | } | ||
190 | |||
191 | 1 | ret = gate_stream_write_block(dst, dstbuffer, converted, &written); | |
192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FAILED(ret)) |
193 | { | ||
194 | ✗ | break; | |
195 | } | ||
196 | } | ||
197 | |||
198 | 1 | return ret; | |
199 | } | ||
200 | |||
201 | 1 | gate_result_t gate_base64_encode_buffer(char const* src, gate_size_t srclength, char* dst, gate_size_t* dstlength) | |
202 | { | ||
203 | gate_result_t ret; | ||
204 | 1 | gate_size_t b64length = (srclength / 3) * 4; | |
205 | 1 | char const* ptrsrc = src; | |
206 | 1 | char* ptrdst = dst; | |
207 | |||
208 | do | ||
209 | { | ||
210 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if ((srclength == 0) || (dstlength == NULL)) |
211 | { | ||
212 | ✗ | ret = GATE_RESULT_INVALIDARG; | |
213 | ✗ | break; | |
214 | } | ||
215 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if ((srclength % 3) != 0) |
216 | { | ||
217 | 1 | b64length += 4; | |
218 | } | ||
219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*dstlength < b64length) |
220 | { | ||
221 | ✗ | ret = GATE_RESULT_BUFFERTOOSMALL; | |
222 | ✗ | *dstlength = b64length; | |
223 | ✗ | break; | |
224 | } | ||
225 | 1 | *dstlength = b64length; | |
226 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if ((src == NULL) || (dst == NULL)) |
227 | { | ||
228 | ✗ | ret = GATE_RESULT_INVALIDARG; | |
229 | ✗ | break; | |
230 | } | ||
231 | |||
232 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | while (srclength >= 3) |
233 | { | ||
234 | 9 | gate_base64_enc3(ptrsrc, ptrdst); | |
235 | 9 | ptrsrc += 3; | |
236 | 9 | srclength -= 3; | |
237 | 9 | ptrdst += 4; | |
238 | } | ||
239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (srclength == 1) |
240 | { | ||
241 | ✗ | gate_base64_enc1(ptrsrc, ptrdst); | |
242 | } | ||
243 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (srclength == 2) |
244 | { | ||
245 | 1 | gate_base64_enc2(ptrsrc, ptrdst); | |
246 | } | ||
247 | 1 | ret = GATE_RESULT_OK; | |
248 | } while (0); | ||
249 | |||
250 | 1 | return ret; | |
251 | } | ||
252 | |||
253 | |||
254 | 1 | static gate_size_t gate_base64_decode_block(char const* src, gate_size_t srclength, char* dst, gate_size_t dstlength) | |
255 | { | ||
256 | 1 | gate_size_t ret = 0; | |
257 | gate_size_t tmp; | ||
258 | |||
259 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
11 | while ((srclength >= 4) && (dstlength >= 3)) |
260 | { | ||
261 | 10 | tmp = gate_base64_dec(src, dst); | |
262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (tmp == 0) |
263 | { | ||
264 | ✗ | break; | |
265 | } | ||
266 | 10 | ret += tmp; | |
267 | 10 | src += 4; | |
268 | 10 | srclength -= 4; | |
269 | 10 | dst += tmp; | |
270 | 10 | dstlength -= tmp; | |
271 | } | ||
272 | |||
273 | 1 | return ret; | |
274 | } | ||
275 | |||
276 | 1 | gate_result_t gate_base64_decode(gate_string_t const* src, gate_strbuilder_t* dst) | |
277 | { | ||
278 | gate_result_t ret; | ||
279 | 1 | char const* ptrsrc = src->str; | |
280 | 1 | gate_size_t length = src->length; | |
281 | gate_size_t declength; | ||
282 | char buffer[3]; | ||
283 | |||
284 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if ((length % 4) != 0) |
285 | { | ||
286 | ✗ | ret = GATE_RESULT_INVALIDINPUT; | |
287 | } | ||
288 | else | ||
289 | { | ||
290 | 1 | ret = GATE_RESULT_OK; | |
291 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | while (length != 0) |
292 | { | ||
293 | 10 | declength = gate_base64_dec(ptrsrc, buffer); | |
294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (declength == 0) |
295 | { | ||
296 | ✗ | ret = GATE_RESULT_INVALIDINPUT; | |
297 | ✗ | break; | |
298 | } | ||
299 | 10 | length -= 4; | |
300 | 10 | ptrsrc += 4; | |
301 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if (declength != gate_strbuilder_append_text(dst, buffer, declength)) |
302 | { | ||
303 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
304 | ✗ | break; | |
305 | } | ||
306 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (declength < 3) |
307 | { | ||
308 | 1 | break; | |
309 | } | ||
310 | } | ||
311 | } | ||
312 | |||
313 | 1 | return ret; | |
314 | } | ||
315 | 1 | gate_result_t gate_base64_decode_stream(gate_stream_t* src, gate_stream_t* dst) | |
316 | { | ||
317 | 1 | gate_result_t ret = GATE_RESULT_OK; | |
318 | char srcbuffer[GATE_MAX_COPYBUFFER_LENGTH]; | ||
319 | char dstbuffer[GATE_MAX_COPYBUFFER_LENGTH * 3 / 4]; | ||
320 | gate_size_t returned; | ||
321 | gate_size_t converted; | ||
322 | gate_size_t written; | ||
323 | |||
324 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | while (GATE_SUCCEEDED(ret)) |
325 | { | ||
326 | 2 | ret = gate_stream_read_block(src, srcbuffer, sizeof(srcbuffer), &returned); | |
327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (GATE_FAILED(ret)) |
328 | { | ||
329 | ✗ | break; | |
330 | } | ||
331 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (returned == 0) |
332 | { | ||
333 | 1 | break; | |
334 | } | ||
335 | |||
336 | 1 | converted = gate_base64_decode_block(srcbuffer, returned, dstbuffer, sizeof(dstbuffer)); | |
337 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (converted == 0) |
338 | { | ||
339 | ✗ | ret = GATE_RESULT_INVALIDINPUT; | |
340 | ✗ | break; | |
341 | } | ||
342 | |||
343 | 1 | ret = gate_stream_write_block(dst, dstbuffer, converted, &written); | |
344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FAILED(ret)) |
345 | { | ||
346 | ✗ | break; | |
347 | } | ||
348 | } | ||
349 | |||
350 | 1 | return ret; | |
351 | } | ||
352 | |||
353 | 1 | gate_result_t gate_base64_decode_buffer(char const* src, gate_size_t srclength, char* dst, gate_size_t* dstlength) | |
354 | { | ||
355 | gate_result_t ret; | ||
356 | gate_size_t outlength; | ||
357 | gate_size_t lendecoded; | ||
358 | 1 | char const* ptrsrc = src; | |
359 | 1 | char* ptrdst = dst; | |
360 | |||
361 | do | ||
362 | { | ||
363 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if ((srclength == 0) || (dstlength == NULL)) |
364 | { | ||
365 | ✗ | ret = GATE_RESULT_INVALIDARG; | |
366 | ✗ | break; | |
367 | } | ||
368 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if ((srclength % 4) != 0) |
369 | { | ||
370 | ✗ | srclength -= (srclength % 4); | |
371 | } | ||
372 | 1 | outlength = (srclength / 4) * 3; | |
373 | |||
374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*dstlength < outlength) |
375 | { | ||
376 | ✗ | ret = GATE_RESULT_BUFFERTOOSMALL; | |
377 | ✗ | *dstlength = outlength; | |
378 | ✗ | break; | |
379 | } | ||
380 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if ((src == NULL) || (dst == NULL)) |
381 | { | ||
382 | ✗ | ret = GATE_RESULT_INVALIDARG; | |
383 | ✗ | break; | |
384 | } | ||
385 | |||
386 | 1 | ret = GATE_RESULT_OK; | |
387 | 1 | outlength = 0; | |
388 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
|
11 | while (srclength >= 4) |
389 | { | ||
390 | 10 | lendecoded = gate_base64_dec(ptrsrc, ptrdst); | |
391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (lendecoded == 0) |
392 | { | ||
393 | ✗ | ret = GATE_RESULT_INVALIDINPUT; | |
394 | ✗ | break; | |
395 | } | ||
396 | 10 | ptrsrc += 4; | |
397 | 10 | srclength -= 4; | |
398 | 10 | ptrdst += lendecoded; | |
399 | 10 | outlength += lendecoded; | |
400 | } | ||
401 | 1 | *dstlength = outlength; | |
402 | } while (0); | ||
403 | |||
404 | 1 | return ret; | |
405 | } | ||
406 |