1 static inline void
enc_loop_generic_64_inner(const uint8_t ** s,uint8_t ** o)2 enc_loop_generic_64_inner (const uint8_t **s, uint8_t **o)
3 {
4 uint64_t src;
5
6 // Load input:
7 memcpy(&src, *s, sizeof (src));
8
9 // Reorder to 64-bit big-endian, if not already in that format. The
10 // workset must be in big-endian, otherwise the shifted bits do not
11 // carry over properly among adjacent bytes:
12 src = BASE64_HTOBE64(src);
13
14 // Four indices for the 12-bit lookup table:
15 const size_t index0 = (src >> 52) & 0xFFFU;
16 const size_t index1 = (src >> 40) & 0xFFFU;
17 const size_t index2 = (src >> 28) & 0xFFFU;
18 const size_t index3 = (src >> 16) & 0xFFFU;
19
20 // Table lookup and store:
21 memcpy(*o + 0, base64_table_enc_12bit + index0, 2);
22 memcpy(*o + 2, base64_table_enc_12bit + index1, 2);
23 memcpy(*o + 4, base64_table_enc_12bit + index2, 2);
24 memcpy(*o + 6, base64_table_enc_12bit + index3, 2);
25
26 *s += 6;
27 *o += 8;
28 }
29
30 static inline void
enc_loop_generic_64(const uint8_t ** s,size_t * slen,uint8_t ** o,size_t * olen)31 enc_loop_generic_64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
32 {
33 if (*slen < 8) {
34 return;
35 }
36
37 // Process blocks of 6 bytes at a time. Because blocks are loaded 8
38 // bytes at a time, ensure that there will be at least 2 remaining
39 // bytes after the last round, so that the final read will not pass
40 // beyond the bounds of the input buffer:
41 size_t rounds = (*slen - 2) / 6;
42
43 *slen -= rounds * 6; // 6 bytes consumed per round
44 *olen += rounds * 8; // 8 bytes produced per round
45
46 do {
47 if (rounds >= 8) {
48 enc_loop_generic_64_inner(s, o);
49 enc_loop_generic_64_inner(s, o);
50 enc_loop_generic_64_inner(s, o);
51 enc_loop_generic_64_inner(s, o);
52 enc_loop_generic_64_inner(s, o);
53 enc_loop_generic_64_inner(s, o);
54 enc_loop_generic_64_inner(s, o);
55 enc_loop_generic_64_inner(s, o);
56 rounds -= 8;
57 continue;
58 }
59 if (rounds >= 4) {
60 enc_loop_generic_64_inner(s, o);
61 enc_loop_generic_64_inner(s, o);
62 enc_loop_generic_64_inner(s, o);
63 enc_loop_generic_64_inner(s, o);
64 rounds -= 4;
65 continue;
66 }
67 if (rounds >= 2) {
68 enc_loop_generic_64_inner(s, o);
69 enc_loop_generic_64_inner(s, o);
70 rounds -= 2;
71 continue;
72 }
73 enc_loop_generic_64_inner(s, o);
74 break;
75
76 } while (rounds > 0);
77 }
78