1 | static inline int |
2 | dec_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 | |
32 | static inline void |
33 | dec_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 | |