summaryrefslogtreecommitdiffstats
path: root/src/third-party/base64/lib/arch/generic
diff options
context:
space:
mode:
Diffstat (limited to 'src/third-party/base64/lib/arch/generic')
-rw-r--r--src/third-party/base64/lib/arch/generic/32/dec_loop.c86
-rw-r--r--src/third-party/base64/lib/arch/generic/32/enc_loop.c73
-rw-r--r--src/third-party/base64/lib/arch/generic/64/enc_loop.c77
-rw-r--r--src/third-party/base64/lib/arch/generic/codec.c39
-rw-r--r--src/third-party/base64/lib/arch/generic/dec_head.c37
-rw-r--r--src/third-party/base64/lib/arch/generic/dec_tail.c91
-rw-r--r--src/third-party/base64/lib/arch/generic/enc_head.c24
-rw-r--r--src/third-party/base64/lib/arch/generic/enc_tail.c34
8 files changed, 461 insertions, 0 deletions
diff --git a/src/third-party/base64/lib/arch/generic/32/dec_loop.c b/src/third-party/base64/lib/arch/generic/32/dec_loop.c
new file mode 100644
index 0000000..8a8260f
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/32/dec_loop.c
@@ -0,0 +1,86 @@
+static inline int
+dec_loop_generic_32_inner (const uint8_t **s, uint8_t **o, size_t *rounds)
+{
+ const uint32_t str
+ = base64_table_dec_32bit_d0[(*s)[0]]
+ | base64_table_dec_32bit_d1[(*s)[1]]
+ | base64_table_dec_32bit_d2[(*s)[2]]
+ | base64_table_dec_32bit_d3[(*s)[3]];
+
+#if BASE64_LITTLE_ENDIAN
+
+ // LUTs for little-endian set MSB in case of invalid character:
+ if (str & UINT32_C(0x80000000)) {
+ return 0;
+ }
+#else
+ // LUTs for big-endian set LSB in case of invalid character:
+ if (str & UINT32_C(1)) {
+ return 0;
+ }
+#endif
+ // Store the output:
+ memcpy(*o, &str, sizeof (str));
+
+ *s += 4;
+ *o += 3;
+ *rounds -= 1;
+
+ return 1;
+}
+
+static inline void
+dec_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
+{
+ if (*slen < 8) {
+ return;
+ }
+
+ // Process blocks of 4 bytes per round. Because one extra zero byte is
+ // written after the output, ensure that there will be at least 4 bytes
+ // of input data left to cover the gap. (Two data bytes and up to two
+ // end-of-string markers.)
+ size_t rounds = (*slen - 4) / 4;
+
+ *slen -= rounds * 4; // 4 bytes consumed per round
+ *olen += rounds * 3; // 3 bytes produced per round
+
+ do {
+ if (rounds >= 8) {
+ if (dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds)) {
+ continue;
+ }
+ break;
+ }
+ if (rounds >= 4) {
+ if (dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds)) {
+ continue;
+ }
+ break;
+ }
+ if (rounds >= 2) {
+ if (dec_loop_generic_32_inner(s, o, &rounds) &&
+ dec_loop_generic_32_inner(s, o, &rounds)) {
+ continue;
+ }
+ break;
+ }
+ dec_loop_generic_32_inner(s, o, &rounds);
+ break;
+
+ } while (rounds > 0);
+
+ // Adjust for any rounds that were skipped:
+ *slen += rounds * 4;
+ *olen -= rounds * 3;
+}
diff --git a/src/third-party/base64/lib/arch/generic/32/enc_loop.c b/src/third-party/base64/lib/arch/generic/32/enc_loop.c
new file mode 100644
index 0000000..f4870a7
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/32/enc_loop.c
@@ -0,0 +1,73 @@
+static inline void
+enc_loop_generic_32_inner (const uint8_t **s, uint8_t **o)
+{
+ uint32_t src;
+
+ // Load input:
+ memcpy(&src, *s, sizeof (src));
+
+ // Reorder to 32-bit big-endian, if not already in that format. The
+ // workset must be in big-endian, otherwise the shifted bits do not
+ // carry over properly among adjacent bytes:
+ src = BASE64_HTOBE32(src);
+
+ // Two indices for the 12-bit lookup table:
+ const size_t index0 = (src >> 20) & 0xFFFU;
+ const size_t index1 = (src >> 8) & 0xFFFU;
+
+ // Table lookup and store:
+ memcpy(*o + 0, base64_table_enc_12bit + index0, 2);
+ memcpy(*o + 2, base64_table_enc_12bit + index1, 2);
+
+ *s += 3;
+ *o += 4;
+}
+
+static inline void
+enc_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
+{
+ if (*slen < 4) {
+ return;
+ }
+
+ // Process blocks of 3 bytes at a time. Because blocks are loaded 4
+ // bytes at a time, ensure that there will be at least one remaining
+ // byte after the last round, so that the final read will not pass
+ // beyond the bounds of the input buffer:
+ size_t rounds = (*slen - 1) / 3;
+
+ *slen -= rounds * 3; // 3 bytes consumed per round
+ *olen += rounds * 4; // 4 bytes produced per round
+
+ do {
+ if (rounds >= 8) {
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ rounds -= 8;
+ continue;
+ }
+ if (rounds >= 4) {
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ rounds -= 4;
+ continue;
+ }
+ if (rounds >= 2) {
+ enc_loop_generic_32_inner(s, o);
+ enc_loop_generic_32_inner(s, o);
+ rounds -= 2;
+ continue;
+ }
+ enc_loop_generic_32_inner(s, o);
+ break;
+
+ } while (rounds > 0);
+}
diff --git a/src/third-party/base64/lib/arch/generic/64/enc_loop.c b/src/third-party/base64/lib/arch/generic/64/enc_loop.c
new file mode 100644
index 0000000..0840bc7
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/64/enc_loop.c
@@ -0,0 +1,77 @@
+static inline void
+enc_loop_generic_64_inner (const uint8_t **s, uint8_t **o)
+{
+ uint64_t src;
+
+ // Load input:
+ memcpy(&src, *s, sizeof (src));
+
+ // Reorder to 64-bit big-endian, if not already in that format. The
+ // workset must be in big-endian, otherwise the shifted bits do not
+ // carry over properly among adjacent bytes:
+ src = BASE64_HTOBE64(src);
+
+ // Four indices for the 12-bit lookup table:
+ const size_t index0 = (src >> 52) & 0xFFFU;
+ const size_t index1 = (src >> 40) & 0xFFFU;
+ const size_t index2 = (src >> 28) & 0xFFFU;
+ const size_t index3 = (src >> 16) & 0xFFFU;
+
+ // Table lookup and store:
+ memcpy(*o + 0, base64_table_enc_12bit + index0, 2);
+ memcpy(*o + 2, base64_table_enc_12bit + index1, 2);
+ memcpy(*o + 4, base64_table_enc_12bit + index2, 2);
+ memcpy(*o + 6, base64_table_enc_12bit + index3, 2);
+
+ *s += 6;
+ *o += 8;
+}
+
+static inline void
+enc_loop_generic_64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen)
+{
+ if (*slen < 8) {
+ return;
+ }
+
+ // Process blocks of 6 bytes at a time. Because blocks are loaded 8
+ // bytes at a time, ensure that there will be at least 2 remaining
+ // bytes after the last round, so that the final read will not pass
+ // beyond the bounds of the input buffer:
+ size_t rounds = (*slen - 2) / 6;
+
+ *slen -= rounds * 6; // 6 bytes consumed per round
+ *olen += rounds * 8; // 8 bytes produced per round
+
+ do {
+ if (rounds >= 8) {
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ rounds -= 8;
+ continue;
+ }
+ if (rounds >= 4) {
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ rounds -= 4;
+ continue;
+ }
+ if (rounds >= 2) {
+ enc_loop_generic_64_inner(s, o);
+ enc_loop_generic_64_inner(s, o);
+ rounds -= 2;
+ continue;
+ }
+ enc_loop_generic_64_inner(s, o);
+ break;
+
+ } while (rounds > 0);
+}
diff --git a/src/third-party/base64/lib/arch/generic/codec.c b/src/third-party/base64/lib/arch/generic/codec.c
new file mode 100644
index 0000000..8dd5af2
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/codec.c
@@ -0,0 +1,39 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "../../../include/libbase64.h"
+#include "../../tables/tables.h"
+#include "../../codecs.h"
+#include "config.h"
+#include "../../env.h"
+
+#if BASE64_WORDSIZE == 32
+# include "32/enc_loop.c"
+#elif BASE64_WORDSIZE == 64
+# include "64/enc_loop.c"
+#endif
+
+#if BASE64_WORDSIZE >= 32
+# include "32/dec_loop.c"
+#endif
+
+BASE64_ENC_FUNCTION(plain)
+{
+ #include "enc_head.c"
+#if BASE64_WORDSIZE == 32
+ enc_loop_generic_32(&s, &slen, &o, &olen);
+#elif BASE64_WORDSIZE == 64
+ enc_loop_generic_64(&s, &slen, &o, &olen);
+#endif
+ #include "enc_tail.c"
+}
+
+BASE64_DEC_FUNCTION(plain)
+{
+ #include "dec_head.c"
+#if BASE64_WORDSIZE >= 32
+ dec_loop_generic_32(&s, &slen, &o, &olen);
+#endif
+ #include "dec_tail.c"
+}
diff --git a/src/third-party/base64/lib/arch/generic/dec_head.c b/src/third-party/base64/lib/arch/generic/dec_head.c
new file mode 100644
index 0000000..179a31b
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/dec_head.c
@@ -0,0 +1,37 @@
+int ret = 0;
+const uint8_t *s = (const uint8_t *) src;
+uint8_t *o = (uint8_t *) out;
+uint8_t q;
+
+// Use local temporaries to avoid cache thrashing:
+size_t olen = 0;
+size_t slen = srclen;
+struct base64_state st;
+st.eof = state->eof;
+st.bytes = state->bytes;
+st.carry = state->carry;
+
+// If we previously saw an EOF or an invalid character, bail out:
+if (st.eof) {
+ *outlen = 0;
+ ret = 0;
+ // If there was a trailing '=' to check, check it:
+ if (slen && (st.eof == BASE64_AEOF)) {
+ state->bytes = 0;
+ state->eof = BASE64_EOF;
+ ret = ((base64_table_dec_8bit[*s++] == 254) && (slen == 1)) ? 1 : 0;
+ }
+ return ret;
+}
+
+// Turn four 6-bit numbers into three bytes:
+// out[0] = 11111122
+// out[1] = 22223333
+// out[2] = 33444444
+
+// Duff's device again:
+switch (st.bytes)
+{
+ for (;;)
+ {
+ case 0:
diff --git a/src/third-party/base64/lib/arch/generic/dec_tail.c b/src/third-party/base64/lib/arch/generic/dec_tail.c
new file mode 100644
index 0000000..e64f724
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/dec_tail.c
@@ -0,0 +1,91 @@
+ if (slen-- == 0) {
+ ret = 1;
+ break;
+ }
+ if ((q = base64_table_dec_8bit[*s++]) >= 254) {
+ st.eof = BASE64_EOF;
+ // Treat character '=' as invalid for byte 0:
+ break;
+ }
+ st.carry = q << 2;
+ st.bytes++;
+
+ // Deliberate fallthrough:
+ BASE64_FALLTHROUGH
+
+ case 1: if (slen-- == 0) {
+ ret = 1;
+ break;
+ }
+ if ((q = base64_table_dec_8bit[*s++]) >= 254) {
+ st.eof = BASE64_EOF;
+ // Treat character '=' as invalid for byte 1:
+ break;
+ }
+ *o++ = st.carry | (q >> 4);
+ st.carry = q << 4;
+ st.bytes++;
+ olen++;
+
+ // Deliberate fallthrough:
+ BASE64_FALLTHROUGH
+
+ case 2: if (slen-- == 0) {
+ ret = 1;
+ break;
+ }
+ if ((q = base64_table_dec_8bit[*s++]) >= 254) {
+ st.bytes++;
+ // When q == 254, the input char is '='.
+ // Check if next byte is also '=':
+ if (q == 254) {
+ if (slen-- != 0) {
+ st.bytes = 0;
+ // EOF:
+ st.eof = BASE64_EOF;
+ q = base64_table_dec_8bit[*s++];
+ ret = ((q == 254) && (slen == 0)) ? 1 : 0;
+ break;
+ }
+ else {
+ // Almost EOF
+ st.eof = BASE64_AEOF;
+ ret = 1;
+ break;
+ }
+ }
+ // If we get here, there was an error:
+ break;
+ }
+ *o++ = st.carry | (q >> 2);
+ st.carry = q << 6;
+ st.bytes++;
+ olen++;
+
+ // Deliberate fallthrough:
+ BASE64_FALLTHROUGH
+
+ case 3: if (slen-- == 0) {
+ ret = 1;
+ break;
+ }
+ if ((q = base64_table_dec_8bit[*s++]) >= 254) {
+ st.bytes = 0;
+ st.eof = BASE64_EOF;
+ // When q == 254, the input char is '='. Return 1 and EOF.
+ // When q == 255, the input char is invalid. Return 0 and EOF.
+ ret = ((q == 254) && (slen == 0)) ? 1 : 0;
+ break;
+ }
+ *o++ = st.carry | q;
+ st.carry = 0;
+ st.bytes = 0;
+ olen++;
+ }
+}
+
+state->eof = st.eof;
+state->bytes = st.bytes;
+state->carry = st.carry;
+*outlen = olen;
+return ret;
diff --git a/src/third-party/base64/lib/arch/generic/enc_head.c b/src/third-party/base64/lib/arch/generic/enc_head.c
new file mode 100644
index 0000000..38d60b2
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/enc_head.c
@@ -0,0 +1,24 @@
+// Assume that *out is large enough to contain the output.
+// Theoretically it should be 4/3 the length of src.
+const uint8_t *s = (const uint8_t *) src;
+uint8_t *o = (uint8_t *) out;
+
+// Use local temporaries to avoid cache thrashing:
+size_t olen = 0;
+size_t slen = srclen;
+struct base64_state st;
+st.bytes = state->bytes;
+st.carry = state->carry;
+
+// Turn three bytes into four 6-bit numbers:
+// in[0] = 00111111
+// in[1] = 00112222
+// in[2] = 00222233
+// in[3] = 00333333
+
+// Duff's device, a for() loop inside a switch() statement. Legal!
+switch (st.bytes)
+{
+ for (;;)
+ {
+ case 0:
diff --git a/src/third-party/base64/lib/arch/generic/enc_tail.c b/src/third-party/base64/lib/arch/generic/enc_tail.c
new file mode 100644
index 0000000..cbd5733
--- /dev/null
+++ b/src/third-party/base64/lib/arch/generic/enc_tail.c
@@ -0,0 +1,34 @@
+ if (slen-- == 0) {
+ break;
+ }
+ *o++ = base64_table_enc_6bit[*s >> 2];
+ st.carry = (*s++ << 4) & 0x30;
+ st.bytes++;
+ olen += 1;
+
+ // Deliberate fallthrough:
+ BASE64_FALLTHROUGH
+
+ case 1: if (slen-- == 0) {
+ break;
+ }
+ *o++ = base64_table_enc_6bit[st.carry | (*s >> 4)];
+ st.carry = (*s++ << 2) & 0x3C;
+ st.bytes++;
+ olen += 1;
+
+ // Deliberate fallthrough:
+ BASE64_FALLTHROUGH
+
+ case 2: if (slen-- == 0) {
+ break;
+ }
+ *o++ = base64_table_enc_6bit[st.carry | (*s >> 6)];
+ *o++ = base64_table_enc_6bit[*s++ & 0x3F];
+ st.bytes = 0;
+ olen += 2;
+ }
+}
+state->bytes = st.bytes;
+state->carry = st.carry;
+*outlen = olen;