GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/base64.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 163 197 82.7%
Functions: 11 11 100.0%
Branches: 64 98 65.3%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, 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 #include "gate/debugging.h"
33
34 static char const* const base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
35 static char const base64_nullchar = '=';
36
37 84 void gate_base64_enc3(char const* inputTriple, char* outputQuad)
38 {
39 84 outputQuad[0] = base64_chars[((gate_uint8_t)inputTriple[0] >> 2) & 0x3f];
40 84 outputQuad[1] = base64_chars[(((gate_uint8_t)inputTriple[0] & 0x03) << 4) | (((gate_uint8_t)inputTriple[1] >> 4) & 0x0f)];
41 84 outputQuad[2] = base64_chars[(((gate_uint8_t)inputTriple[1] & 0x0f) << 2) | (((gate_uint8_t)inputTriple[2] >> 6) & 0x03)];
42 84 outputQuad[3] = base64_chars[(gate_uint8_t)inputTriple[2] & 0x3f];
43 84 }
44
45 6 void gate_base64_enc2(char const* inputTuple, char* outputQuad)
46 {
47 6 outputQuad[0] = base64_chars[((gate_uint8_t)inputTuple[0] >> 2) & 0x3f];
48 6 outputQuad[1] = base64_chars[(((gate_uint8_t)inputTuple[0] & 0x03) << 4) | (((gate_uint8_t)inputTuple[1] >> 4) & 0x0f)];
49 6 outputQuad[2] = base64_chars[((gate_uint8_t)inputTuple[1] & 0x0f) << 2];
50 6 outputQuad[3] = base64_nullchar;
51 6 }
52
53 3 void gate_base64_enc1(char const* inputByte, char* outputQuad)
54 {
55 3 outputQuad[0] = base64_chars[((gate_uint8_t)inputByte[0] >> 2) & 0x3f];
56 3 outputQuad[1] = base64_chars[((gate_uint8_t)inputByte[0] & 0x3) << 4];
57 3 outputQuad[2] = base64_nullchar;
58 3 outputQuad[3] = base64_nullchar;
59 3 }
60
61 60 gate_size_t gate_base64_dec(char const* inputQuad, char* outputTriple)
62 {
63 60 gate_size_t pos1 = gate_str_char_pos(base64_chars, 64, inputQuad[0], 0);
64 60 gate_size_t pos2 = gate_str_char_pos(base64_chars, 64, inputQuad[1], 0);
65 60 gate_size_t pos3 = gate_str_char_pos(base64_chars, 64, inputQuad[2], 0);
66 60 gate_size_t pos4 = gate_str_char_pos(base64_chars, 64, inputQuad[3], 0);
67 60 gate_size_t ret = 0;
68 60 gate_uint32_t quad = 0;
69
70 do
71 {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (pos1 == GATE_STR_NPOS)
73 {
74 break;
75 }
76 60 quad |= (gate_uint32_t)pos1 << 18;
77
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (pos2 == GATE_STR_NPOS)
79 {
80 break;
81 }
82 60 quad |= (gate_uint32_t)pos2 << 12;
83 60 outputTriple[0] = (char)(gate_uint8_t)((quad >> 16) & 0xff);
84 60 ++ret;
85
86
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 57 times.
60 if (pos3 == GATE_STR_NPOS)
87 {
88 3 break;
89 }
90 57 quad |= (gate_uint32_t)pos3 << 6;
91 57 outputTriple[1] = (char)(gate_uint8_t)((quad >> 8) & 0xff);
92 57 ++ret;
93
94
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (pos4 == GATE_STR_NPOS)
95 {
96 3 break;
97 }
98 54 quad |= (gate_uint32_t)pos4;
99 54 outputTriple[2] = (char)(gate_uint8_t)(quad & 0xff);
100 54 ++ret;
101
102 } while (0);
103
104 60 return ret;
105 }
106
107
108 5 gate_result_t gate_base64_encode(gate_string_t const* src, gate_strbuilder_t* dst)
109 {
110 5 gate_result_t ret = GATE_RESULT_OK;
111 5 char const* ptr = src->str;
112 5 gate_size_t len = src->length;
113 char buffer[4];
114
115
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 5 times.
53 while (len >= 3)
116 {
117 48 gate_base64_enc3(ptr, buffer);
118
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (4 != gate_strbuilder_append_text(dst, buffer, 4))
119 {
120 ret = GATE_RESULT_OUTOFMEMORY;
121 break;
122 }
123 48 len -= 3;
124 48 ptr += 3;
125 }
126
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (GATE_SUCCEEDED(ret))
127 {
128
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (len == 1)
129 {
130 1 gate_base64_enc1(ptr, buffer);
131
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (4 != gate_strbuilder_append_text(dst, buffer, 4))
132 {
133 ret = GATE_RESULT_OUTOFMEMORY;
134 }
135 }
136
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (len == 2)
137 {
138 4 gate_base64_enc2(ptr, buffer);
139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (4 != gate_strbuilder_append_text(dst, buffer, 4))
140 {
141 ret = GATE_RESULT_OUTOFMEMORY;
142 }
143 }
144 }
145
146 5 return ret;
147 }
148 4 gate_result_t gate_base64_encode_stream(gate_stream_t* src, gate_stream_t* dst)
149 {
150 gate_result_t ret;
151 char srcbuffer[GATE_MAX_COPYBUFFER_LENGTH * 3 / 4];
152 char dstbuffer[GATE_MAX_COPYBUFFER_LENGTH];
153 gate_size_t returned;
154 gate_size_t converted;
155 gate_size_t written;
156
157 for (;;)
158 2 {
159 4 char const* ptrsrc = srcbuffer;
160 4 char* ptrdst = dstbuffer;
161 4 ret = gate_stream_read_block(src, srcbuffer, sizeof(srcbuffer), &returned);
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(ret))
163 {
164 break;
165 }
166
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (returned == 0)
167 {
168 2 break;
169 }
170 2 converted = 0;
171
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 while (returned >= 3)
172 {
173 18 gate_base64_enc3(ptrsrc, ptrdst);
174 18 ptrsrc += 3;
175 18 returned -= 3;
176 18 ptrdst += 4;
177 18 converted += 4;
178 }
179
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (returned == 1)
180 {
181 1 gate_base64_enc1(ptrsrc, ptrdst);
182 1 converted += 4;
183 }
184
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (returned == 2)
185 {
186 1 gate_base64_enc2(ptrsrc, ptrdst);
187 1 converted += 4;
188 }
189
190 2 ret = gate_stream_write_block(dst, dstbuffer, converted, &written);
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
192 {
193 break;
194 }
195 }
196
197 2 return ret;
198 }
199
200 2 gate_result_t gate_base64_encode_buffer(char const* src, gate_size_t srclength, char* dst, gate_size_t* dstlength)
201 {
202 gate_result_t ret;
203 2 gate_size_t b64length = (srclength / 3) * 4;
204 2 char const* ptrsrc = src;
205 2 char* ptrdst = dst;
206
207 do
208 {
209
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((srclength == 0) || (dstlength == NULL))
210 {
211 ret = GATE_RESULT_INVALIDARG;
212 break;
213 }
214
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ((srclength % 3) != 0)
215 {
216 2 b64length += 4;
217 }
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (*dstlength < b64length)
219 {
220 ret = GATE_RESULT_BUFFERTOOSMALL;
221 *dstlength = b64length;
222 break;
223 }
224 2 *dstlength = b64length;
225
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((src == NULL) || (dst == NULL))
226 {
227 ret = GATE_RESULT_INVALIDARG;
228 break;
229 }
230
231
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 while (srclength >= 3)
232 {
233 18 gate_base64_enc3(ptrsrc, ptrdst);
234 18 ptrsrc += 3;
235 18 srclength -= 3;
236 18 ptrdst += 4;
237 }
238
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (srclength == 1)
239 {
240 1 gate_base64_enc1(ptrsrc, ptrdst);
241 }
242
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (srclength == 2)
243 {
244 1 gate_base64_enc2(ptrsrc, ptrdst);
245 }
246 2 ret = GATE_RESULT_OK;
247 } while (0);
248
249 2 return ret;
250 }
251
252
253 2 static gate_size_t gate_base64_decode_block(char const* src, gate_size_t srclength, char* dst, gate_size_t dstlength)
254 {
255 2 gate_size_t ret = 0;
256 gate_size_t tmp;
257
258
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
22 while ((srclength >= 4) && (dstlength >= 3))
259 {
260 20 tmp = gate_base64_dec(src, dst);
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (tmp == 0)
262 {
263 break;
264 }
265 20 ret += tmp;
266 20 src += 4;
267 20 srclength -= 4;
268 20 dst += tmp;
269 20 dstlength -= tmp;
270 }
271
272 2 return ret;
273 }
274
275 2 gate_result_t gate_base64_decode(gate_string_t const* src, gate_strbuilder_t* dst)
276 {
277 gate_result_t ret;
278 char const* ptrsrc;
279 gate_size_t length;
280
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_DEBUG_ASSERT(src != NULL);
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_DEBUG_ASSERT(dst != NULL);
283
284 2 ptrsrc = src->str;
285 2 length = src->length;
286
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ((length % 4) != 0)
288 {
289 ret = GATE_RESULT_INVALIDINPUT;
290 }
291 else
292 {
293 2 ret = GATE_RESULT_OK;
294
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 while (length != 0)
295 {
296 char buffer[3];
297 20 gate_size_t declength = gate_base64_dec(ptrsrc, buffer);
298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (declength == 0)
299 {
300 ret = GATE_RESULT_INVALIDINPUT;
301 2 break;
302 }
303 20 length -= 4;
304 20 ptrsrc += 4;
305
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if (declength != gate_strbuilder_append_text(dst, buffer, declength))
306 {
307 ret = GATE_RESULT_OUTOFMEMORY;
308 break;
309 }
310
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if (declength < 3)
311 {
312 2 break;
313 }
314 }
315 }
316
317 2 return ret;
318 }
319 2 gate_result_t gate_base64_decode_stream(gate_stream_t* src, gate_stream_t* dst)
320 {
321 2 gate_result_t ret = GATE_RESULT_OK;
322 char srcbuffer[GATE_MAX_COPYBUFFER_LENGTH];
323 char dstbuffer[GATE_MAX_COPYBUFFER_LENGTH * 3 / 4];
324 gate_size_t returned;
325 gate_size_t converted;
326 gate_size_t written;
327
328
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 while (GATE_SUCCEEDED(ret))
329 {
330 4 ret = gate_stream_read_block(src, srcbuffer, sizeof(srcbuffer), &returned);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(ret))
332 {
333 break;
334 }
335
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (returned == 0)
336 {
337 2 break;
338 }
339
340 2 converted = gate_base64_decode_block(srcbuffer, returned, dstbuffer, sizeof(dstbuffer));
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (converted == 0)
342 {
343 ret = GATE_RESULT_INVALIDINPUT;
344 break;
345 }
346
347 2 ret = gate_stream_write_block(dst, dstbuffer, converted, &written);
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
349 {
350 break;
351 }
352 }
353
354 2 return ret;
355 }
356
357 2 gate_result_t gate_base64_decode_buffer(char const* src, gate_size_t srclength, char* dst, gate_size_t* dstlength)
358 {
359 gate_result_t ret;
360 gate_size_t outlength;
361 gate_size_t lendecoded;
362 2 char const* ptrsrc = src;
363 2 char* ptrdst = dst;
364
365 do
366 {
367
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((srclength == 0) || (dstlength == NULL))
368 {
369 ret = GATE_RESULT_INVALIDARG;
370 break;
371 }
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ((srclength % 4) != 0)
373 {
374 srclength -= (srclength % 4);
375 }
376 2 outlength = (srclength / 4) * 3;
377
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (*dstlength < outlength)
379 {
380 ret = GATE_RESULT_BUFFERTOOSMALL;
381 *dstlength = outlength;
382 break;
383 }
384
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if ((src == NULL) || (dst == NULL))
385 {
386 ret = GATE_RESULT_INVALIDARG;
387 break;
388 }
389
390 2 ret = GATE_RESULT_OK;
391 2 outlength = 0;
392
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 while (srclength >= 4)
393 {
394 20 lendecoded = gate_base64_dec(ptrsrc, ptrdst);
395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (lendecoded == 0)
396 {
397 ret = GATE_RESULT_INVALIDINPUT;
398 break;
399 }
400 20 ptrsrc += 4;
401 20 srclength -= 4;
402 20 ptrdst += lendecoded;
403 20 outlength += lendecoded;
404 }
405 2 *dstlength = outlength;
406 } while (0);
407
408 2 return ret;
409 }
410