27static const char B64_TABLE[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36 while (i + 2 < src_len)
38 uint32_t v = ((uint32_t)src[i] << 16) | ((uint32_t)src[i + 1] << 8) | (uint32_t)src[i + 2];
39 dst[j++] = B64_TABLE[(v >> 18) & 0x3F];
40 dst[j++] = B64_TABLE[(v >> 12) & 0x3F];
41 dst[j++] = B64_TABLE[(v >> 6) & 0x3F];
42 dst[j++] = B64_TABLE[(v) & 0x3F];
49 uint32_t v = (uint32_t)src[i] << 16;
52 v |= (uint32_t)src[i + 1] << 8;
55 dst[j++] = B64_TABLE[(v >> 18) & 0x3F];
56 dst[j++] = B64_TABLE[(v >> 12) & 0x3F];
57 dst[j++] = (i + 1 < src_len) ? B64_TABLE[(v >> 6) & 0x3F] :
'=';
78static inline uint32_t ct_ge(uint32_t x, uint32_t lo)
80 return ((x - lo) >> 31) - 1u;
82static inline uint32_t ct_le(uint32_t x, uint32_t hi)
84 return ((hi - x) >> 31) - 1u;
86static inline uint32_t ct_eq(uint32_t x, uint32_t y)
88 return ct_ge(x, y) & ct_le(x, y);
90static inline uint32_t ct_is_zero(uint32_t x)
92 return 0u - ((x - 1u) >> 31);
99static inline uint32_t ct_b64_val_plus1(uint32_t c,
int urlsafe)
101 uint32_t plus = urlsafe ? (uint32_t)
'-' : (uint32_t)
'+';
102 uint32_t slash = urlsafe ? (uint32_t)
'_' : (uint32_t)
'/';
104 v |= ct_ge(c,
'A') & ct_le(c,
'Z') & (c -
'A' + 1u);
105 v |= ct_ge(c,
'a') & ct_le(c,
'z') & (c -
'a' + 27u);
106 v |= ct_ge(c,
'0') & ct_le(c,
'9') & (c -
'0' + 53u);
107 v |= ct_eq(c, plus) & 63u;
108 v |= ct_eq(c, slash) & 64u;
120#define B64_ONES 0x01010101u
121#define B64_HIGH 0x80808080u
123static inline uint32_t swar_ge(uint32_t a, uint32_t v)
125 return ((a | B64_HIGH) - v * B64_ONES) & B64_HIGH;
127static inline uint32_t swar_le(uint32_t a, uint32_t v)
129 return ((v * B64_ONES | B64_HIGH) - a) & B64_HIGH;
131static inline uint32_t swar_spread(uint32_t m)
133 return m + (m - (m >> 7));
135static inline uint32_t swar_sub7(uint32_t a, uint32_t lo)
137 return ((a | B64_HIGH) - lo * B64_ONES) & 0x7F7F7F7Fu;
141static inline uint32_t swar_quad(uint32_t a, uint32_t *ok)
143 uint32_t mAZ = swar_spread(swar_ge(a,
'A') & swar_le(a,
'Z'));
144 uint32_t maz = swar_spread(swar_ge(a,
'a') & swar_le(a,
'z'));
145 uint32_t m09 = swar_spread(swar_ge(a,
'0') & swar_le(a,
'9'));
146 uint32_t mpl = swar_spread(swar_ge(a,
'+') & swar_le(a,
'+'));
147 uint32_t msl = swar_spread(swar_ge(a,
'/') & swar_le(a,
'/'));
148 uint32_t val = (mAZ & (swar_sub7(a,
'A') + 0u * B64_ONES)) | (maz & (swar_sub7(a,
'a') + 26u * B64_ONES)) |
149 (m09 & (swar_sub7(a,
'0') + 52u * B64_ONES)) | (mpl & (62u * B64_ONES)) | (msl & (63u * B64_ONES));
150 *ok = mAZ | maz | m09 | mpl | msl;
156 size_t src_len = strnlen(src, ((dst_cap + 2) / 3) * 4 + 4);
157 if (src_len == 0 || (src_len & 3u) != 0)
163 size_t nquads = src_len / 4;
164 for (
size_t q = 0; q < nquads; q++)
167 uint32_t c0 = (uint8_t)src[i];
168 uint32_t c1 = (uint8_t)src[i + 1];
169 uint32_t c2 = (uint8_t)src[i + 2];
170 uint32_t c3 = (uint8_t)src[i + 3];
171 int is_last = (q + 1 == nquads);
172 int p2 = is_last && (c2 ==
'=');
173 int p3 = is_last && (c3 ==
'=');
180 uint32_t word = c0 | (c1 << 8) | ((p2 ? (uint32_t)
'A' : c2) << 16) | ((p3 ? (uint32_t)
'A' : c3) << 24);
182 uint32_t val = swar_quad(word, &ok);
184 uint32_t a = val & 0xFF;
185 uint32_t b = (val >> 8) & 0xFF;
186 uint32_t c = (val >> 16) & 0xFF;
187 uint32_t d = (val >> 24) & 0xFF;
192 dst[out++] = (uint8_t)((a << 2) | (b >> 4));
199 dst[out++] = (uint8_t)((b << 4) | (c >> 2));
207 dst[out++] = (uint8_t)((c << 6) | d);
221 size_t src_len = strnlen(src, ((dst_cap + 2) / 3) * 4 + 4);
222 if (src_len == 0 || (src_len & 3u) != 0)
230 for (
size_t i = 0; i < src_len; i += 4)
232 uint32_t c0 = (uint8_t)src[i + 0];
233 uint32_t c1 = (uint8_t)src[i + 1];
234 uint32_t c2 = (uint8_t)src[i + 2];
235 uint32_t c3 = (uint8_t)src[i + 3];
239 int is_last = (i + 4 == src_len);
240 int p2 = is_last && (c2 ==
'=');
241 int p3 = is_last && (c3 ==
'=');
247 uint32_t v0 = ct_b64_val_plus1(c0, 0);
248 uint32_t v1 = ct_b64_val_plus1(c1, 0);
249 uint32_t v2 = ct_b64_val_plus1(c2, 0);
250 uint32_t v3 = ct_b64_val_plus1(c3, 0);
253 bad |= ct_is_zero(v0);
254 bad |= ct_is_zero(v1);
255 bad |= p2 ? 0u : ct_is_zero(v2);
256 bad |= p3 ? 0u : ct_is_zero(v3);
258 uint32_t a = (v0 - 1u) & 0x3Fu;
259 uint32_t b = (v1 - 1u) & 0x3Fu;
260 uint32_t c = p2 ? 0u : ((v2 - 1u) & 0x3Fu);
261 uint32_t d = p3 ? 0u : ((v3 - 1u) & 0x3Fu);
268 dst[out++] = (uint8_t)((a << 2) | (b >> 4));
275 dst[out++] = (uint8_t)((b << 4) | (c >> 2));
283 dst[out++] = (uint8_t)((c << 6) | d);
308 for (
size_t i = 0; dst[i]; i++)
339 for (
size_t i = 0; i < src_len; i++)
341 uint32_t ch = (uint8_t)src[i];
346 uint32_t vp = ct_b64_val_plus1(ch, 1);
347 bad |= ct_is_zero(vp);
348 acc = (acc << 6) | ((vp - 1u) & 0x3Fu);
357 dst[o++] = (uint8_t)((acc >> bits) & 0xFF);
size_t pc_base64url_decode(const char *src, size_t src_len, uint8_t *dst, size_t dst_cap)
Decode src_len characters of base64url (RFC 4648 section 5, '-'/'_' alphabet; an '=' ends the input).
size_t pc_base64url_encode(const uint8_t *src, size_t src_len, char *dst)
Encode src_len bytes as base64url (RFC 4648 section 5): '-' / '_' in place of '+' / '/',...
size_t pc_base64_decode(const char *src, uint8_t *dst, size_t dst_cap)
Decode a null-terminated Base64 string.
void pc_base64_encode(const uint8_t *src, size_t src_len, char *dst)
Encode src_len bytes of src as Base64.
User-facing configuration for ProtoCore.