1static inline int
2dec_loop_generic_32_inner (const uint8_t **s, uint8_t **o, size_t *rounds)
3{
4 const uint32_t str
5 = base64_table_dec_d0[(*s)[0]]
6 | base64_table_dec_d1[(*s)[1]]
7 | base64_table_dec_d2[(*s)[2]]
8 | base64_table_dec_d3[(*s)[3]];
9
10#if BASE64_LITTLE_ENDIAN
11
12 // LUTs for little-endian set MSB in case of invalid character:
13 if (str & UINT32_C(0x80000000)) {
14 return 0;
15 }
16#else
17 // LUTs for big-endian set LSB in case of invalid character:
18 if (str & UINT32_C(1)) {
19 return 0;
20 }
21#endif
22 // Store the output:
23 memcpy(*o, &str, sizeof (str));
24
25 *s += 4;
26 *o += 3;
27 *rounds -= 1;
28
29 return 1;
30}
31
32static inline void
33dec_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
34{
35 if (*slen < 8) {
36 return;
37 }
38
39 // Process blocks of 4 bytes per round. Because one extra zero byte is
40 // written after the output, ensure that there will be at least 4 bytes
41 // of input data left to cover the gap. (Two data bytes and up to two
42 // end-of-string markers.)
43 size_t rounds = (*slen - 4) / 4;
44
45 *slen -= rounds * 4; // 4 bytes consumed per round
46 *olen += rounds * 3; // 3 bytes produced per round
47
48 do {
49 if (rounds >= 8) {
50 if (dec_loop_generic_32_inner(s, o, &rounds) &&
51 dec_loop_generic_32_inner(s, o, &rounds) &&
52 dec_loop_generic_32_inner(s, o, &rounds) &&
53 dec_loop_generic_32_inner(s, o, &rounds) &&
54 dec_loop_generic_32_inner(s, o, &rounds) &&
55 dec_loop_generic_32_inner(s, o, &rounds) &&
56 dec_loop_generic_32_inner(s, o, &rounds) &&
57 dec_loop_generic_32_inner(s, o, &rounds)) {
58 continue;
59 }
60 break;
61 }
62 if (rounds >= 4) {
63 if (dec_loop_generic_32_inner(s, o, &rounds) &&
64 dec_loop_generic_32_inner(s, o, &rounds) &&
65 dec_loop_generic_32_inner(s, o, &rounds) &&
66 dec_loop_generic_32_inner(s, o, &rounds)) {
67 continue;
68 }
69 break;
70 }
71 if (rounds >= 2) {
72 if (dec_loop_generic_32_inner(s, o, &rounds) &&
73 dec_loop_generic_32_inner(s, o, &rounds)) {
74 continue;
75 }
76 break;
77 }
78 dec_loop_generic_32_inner(s, o, &rounds);
79 break;
80
81 } while (rounds > 0);
82
83 // Adjust for any rounds that were skipped:
84 *slen += rounds * 4;
85 *olen -= rounds * 3;
86}
87