Add base_64 codec to wuffs_base
diff --git a/internal/cgen/base/fundamental-public.h b/internal/cgen/base/fundamental-public.h
index 55c0d40..a450b43 100644
--- a/internal/cgen/base/fundamental-public.h
+++ b/internal/cgen/base/fundamental-public.h
@@ -256,6 +256,16 @@
// --------
+// wuffs_base__transform__output is the result of transforming from a src slice
+// to a dst slice.
+typedef struct {
+ wuffs_base__status status;
+ size_t num_dst;
+ size_t num_src;
+} wuffs_base__transform__output;
+
+// --------
+
// FourCC constants.
// !! INSERT FourCCs.
diff --git a/internal/cgen/base/i64conv-submodule.c b/internal/cgen/base/i64conv-submodule.c
index eee18ee..f6fcb2e 100644
--- a/internal/cgen/base/i64conv-submodule.c
+++ b/internal/cgen/base/i64conv-submodule.c
@@ -435,3 +435,322 @@
return len;
}
+
+// ---------------- Base-64
+
+// The two base-64 alphabets, std and url, differ only in the last two codes.
+// - std: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+// - url: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+
+static const uint8_t wuffs_base__base_64__decode_std[256] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x00 ..= 0x07.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x08 ..= 0x0F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x10 ..= 0x17.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x18 ..= 0x1F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x20 ..= 0x27.
+ 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, // 0x28 ..= 0x2F.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 ..= 0x37.
+ 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x38 ..= 0x3F.
+
+ 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40 ..= 0x47.
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 ..= 0x4F.
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 ..= 0x57.
+ 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x58 ..= 0x5F.
+ 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 ..= 0x67.
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 ..= 0x6F.
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 ..= 0x77.
+ 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x78 ..= 0x7F.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x80 ..= 0x87.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x88 ..= 0x8F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x90 ..= 0x97.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x98 ..= 0x9F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA0 ..= 0xA7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA8 ..= 0xAF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB0 ..= 0xB7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB8 ..= 0xBF.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC0 ..= 0xC7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC8 ..= 0xCF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD0 ..= 0xD7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD8 ..= 0xDF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE0 ..= 0xE7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE8 ..= 0xEF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF0 ..= 0xF7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF8 ..= 0xFF.
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+};
+
+static const uint8_t wuffs_base__base_64__decode_url[256] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x00 ..= 0x07.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x08 ..= 0x0F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x10 ..= 0x17.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x18 ..= 0x1F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x20 ..= 0x27.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, // 0x28 ..= 0x2F.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 ..= 0x37.
+ 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x38 ..= 0x3F.
+
+ 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40 ..= 0x47.
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 ..= 0x4F.
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 ..= 0x57.
+ 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x3F, // 0x58 ..= 0x5F.
+ 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 ..= 0x67.
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 ..= 0x6F.
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 ..= 0x77.
+ 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x78 ..= 0x7F.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x80 ..= 0x87.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x88 ..= 0x8F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x90 ..= 0x97.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x98 ..= 0x9F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA0 ..= 0xA7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA8 ..= 0xAF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB0 ..= 0xB7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB8 ..= 0xBF.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC0 ..= 0xC7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC8 ..= 0xCF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD0 ..= 0xD7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD8 ..= 0xDF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE0 ..= 0xE7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE8 ..= 0xEF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF0 ..= 0xF7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF8 ..= 0xFF.
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+};
+
+static const uint8_t wuffs_base__base_64__encode_std[64] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // 0x00 ..= 0x07.
+ 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // 0x08 ..= 0x0F.
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // 0x10 ..= 0x17.
+ 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 0x18 ..= 0x1F.
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 0x20 ..= 0x27.
+ 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, // 0x28 ..= 0x2F.
+ 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, // 0x30 ..= 0x37.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, // 0x38 ..= 0x3F.
+};
+
+static const uint8_t wuffs_base__base_64__encode_url[64] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // 0x00 ..= 0x07.
+ 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // 0x08 ..= 0x0F.
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // 0x10 ..= 0x17.
+ 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 0x18 ..= 0x1F.
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 0x20 ..= 0x27.
+ 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, // 0x28 ..= 0x2F.
+ 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, // 0x30 ..= 0x37.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2D, 0x5F, // 0x38 ..= 0x3F.
+};
+
+// --------
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__decode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options) {
+ const uint8_t* alphabet = (options & WUFFS_BASE__BASE_64__URL_ALPHABET)
+ ? wuffs_base__base_64__decode_url
+ : wuffs_base__base_64__decode_std;
+ wuffs_base__transform__output o;
+ uint8_t* d_ptr = dst.ptr;
+ size_t d_len = dst.len;
+ const uint8_t* s_ptr = src.ptr;
+ size_t s_len = src.len;
+ bool pad = false;
+
+ while (s_len >= 4) {
+ uint32_t s = wuffs_base__load_u32le__no_bounds_check(s_ptr);
+ uint32_t s0 = alphabet[0xFF & (s >> 0)];
+ uint32_t s1 = alphabet[0xFF & (s >> 8)];
+ uint32_t s2 = alphabet[0xFF & (s >> 16)];
+ uint32_t s3 = alphabet[0xFF & (s >> 24)];
+
+ if (((s0 | s1 | s2 | s3) & 0xC0) != 0) {
+ if (s_len > 4) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ } else if (!src_closed) {
+ o.status.repr = wuffs_base__suspension__short_read;
+ goto done;
+ } else if ((options & WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING) &&
+ (s_ptr[3] == '=')) {
+ pad = true;
+ if (s_ptr[2] == '=') {
+ goto src2;
+ }
+ goto src3;
+ }
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ }
+
+ if (d_len < 3) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+
+ s_ptr += 4;
+ s_len -= 4;
+ s = (s0 << 18) | (s1 << 12) | (s2 << 6) | (s3 << 0);
+ *d_ptr++ = (uint8_t)(s >> 16);
+ *d_ptr++ = (uint8_t)(s >> 8);
+ *d_ptr++ = (uint8_t)(s >> 0);
+ d_len -= 3;
+ }
+
+ if (!src_closed) {
+ o.status.repr = wuffs_base__suspension__short_read;
+ goto done;
+ }
+
+ if (s_len == 0) {
+ o.status.repr = NULL;
+ goto done;
+ } else if (s_len == 1) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ } else if (s_len == 2) {
+ goto src2;
+ }
+
+src3:
+ do {
+ uint32_t s = wuffs_base__load_u24le__no_bounds_check(s_ptr);
+ uint32_t s0 = alphabet[0xFF & (s >> 0)];
+ uint32_t s1 = alphabet[0xFF & (s >> 8)];
+ uint32_t s2 = alphabet[0xFF & (s >> 16)];
+ if ((s0 & 0xC0) || (s1 & 0xC0) || (s2 & 0xC3)) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ }
+ if (d_len < 2) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ s_ptr += pad ? 4 : 3;
+ s = (s0 << 18) | (s1 << 12) | (s2 << 6);
+ *d_ptr++ = (uint8_t)(s >> 16);
+ *d_ptr++ = (uint8_t)(s >> 8);
+ o.status.repr = NULL;
+ goto done;
+ } while (0);
+
+src2:
+ do {
+ uint32_t s = wuffs_base__load_u16le__no_bounds_check(s_ptr);
+ uint32_t s0 = alphabet[0xFF & (s >> 0)];
+ uint32_t s1 = alphabet[0xFF & (s >> 8)];
+ if ((s0 & 0xC0) || (s1 & 0xCF)) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ }
+ if (d_len < 1) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ s_ptr += pad ? 4 : 2;
+ s = (s0 << 18) | (s1 << 12);
+ *d_ptr++ = (uint8_t)(s >> 16);
+ o.status.repr = NULL;
+ goto done;
+ } while (0);
+
+done:
+ o.num_dst = d_ptr - dst.ptr;
+ o.num_src = s_ptr - src.ptr;
+ return o;
+}
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__encode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options) {
+ const uint8_t* alphabet = (options & WUFFS_BASE__BASE_64__URL_ALPHABET)
+ ? wuffs_base__base_64__encode_url
+ : wuffs_base__base_64__encode_std;
+ wuffs_base__transform__output o;
+ uint8_t* d_ptr = dst.ptr;
+ size_t d_len = dst.len;
+ const uint8_t* s_ptr = src.ptr;
+ size_t s_len = src.len;
+
+ do {
+ while (s_len >= 3) {
+ if (d_len < 4) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ uint32_t s = wuffs_base__load_u24be__no_bounds_check(s_ptr);
+ s_ptr += 3;
+ s_len -= 3;
+ *d_ptr++ = alphabet[0x3F & (s >> 18)];
+ *d_ptr++ = alphabet[0x3F & (s >> 12)];
+ *d_ptr++ = alphabet[0x3F & (s >> 6)];
+ *d_ptr++ = alphabet[0x3F & (s >> 0)];
+ d_len -= 4;
+ }
+
+ if (!src_closed) {
+ o.status.repr = wuffs_base__suspension__short_read;
+ goto done;
+ }
+
+ if (s_len == 2) {
+ if (d_len <
+ ((options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) ? 4 : 3)) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ uint32_t s = ((uint32_t)(wuffs_base__load_u16be__no_bounds_check(s_ptr)))
+ << 8;
+ s_ptr += 2;
+ *d_ptr++ = alphabet[0x3F & (s >> 18)];
+ *d_ptr++ = alphabet[0x3F & (s >> 12)];
+ *d_ptr++ = alphabet[0x3F & (s >> 6)];
+ if (options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) {
+ *d_ptr++ = '=';
+ }
+ o.status.repr = NULL;
+ goto done;
+
+ } else if (s_len == 1) {
+ if (d_len <
+ ((options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) ? 4 : 2)) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ uint32_t s = ((uint32_t)(wuffs_base__load_u8__no_bounds_check(s_ptr)))
+ << 16;
+ s_ptr += 1;
+ *d_ptr++ = alphabet[0x3F & (s >> 18)];
+ *d_ptr++ = alphabet[0x3F & (s >> 12)];
+ if (options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) {
+ *d_ptr++ = '=';
+ *d_ptr++ = '=';
+ }
+ o.status.repr = NULL;
+ goto done;
+
+ } else {
+ o.status.repr = NULL;
+ goto done;
+ }
+ } while (0);
+
+done:
+ o.num_dst = d_ptr - dst.ptr;
+ o.num_src = s_ptr - src.ptr;
+ return o;
+}
diff --git a/internal/cgen/base/strconv-public.h b/internal/cgen/base/strconv-public.h
index 561b954..071476d 100644
--- a/internal/cgen/base/strconv-public.h
+++ b/internal/cgen/base/strconv-public.h
@@ -295,6 +295,57 @@
wuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 src);
+// ---------------- Base-64
+
+// Options (bitwise or'ed together) for wuffs_base__base_64__xxx functions.
+
+#define WUFFS_BASE__BASE_64__DEFAULT_OPTIONS ((uint32_t)0x00000000)
+
+// WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING means that, when decoding base-64,
+// the input may (but does not need to) be padded with '=' bytes so that the
+// overall encoded length in bytes is a multiple of 4. A successful decoding
+// will return a num_src that includes those padding bytes.
+//
+// Excess padding (e.g. three final '='s) will be rejected as bad data.
+#define WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING ((uint32_t)0x00000001)
+
+// WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING means that, when encoding base-64,
+// the output will be padded with '=' bytes so that the overall encoded length
+// in bytes is a multiple of 4.
+#define WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING ((uint32_t)0x00000002)
+
+// WUFFS_BASE__BASE_64__URL_ALPHABET means that, for base-64, the URL-friendly
+// and file-name-friendly alphabet be used, as per RFC 4648 section 5. When
+// this option bit is off, the standard alphabet from section 4 is used.
+#define WUFFS_BASE__BASE_64__URL_ALPHABET ((uint32_t)0x00000100)
+
+// wuffs_base__base_64__decode transforms base-64 encoded bytes from src to
+// arbitrary bytes in dst.
+//
+// It will not permit line breaks or other whitespace in src. Filtering those
+// out is the responsibility of the caller.
+//
+// For modular builds that divide the base module into sub-modules, using this
+// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not
+// just WUFFS_CONFIG__MODULE__BASE__CORE.
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__decode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options);
+
+// wuffs_base__base_64__encode transforms arbitrary bytes from src to base-64
+// encoded bytes in dst.
+//
+// For modular builds that divide the base module into sub-modules, using this
+// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not
+// just WUFFS_CONFIG__MODULE__BASE__CORE.
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__encode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options);
+
// ---------------- Unicode and UTF-8
#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 0571418..44b14b4 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -176,7 +176,22 @@
"er_u64(dst, u, options,\n neg);\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_u64(wuffs_base__slice_u8 dst,\n uint64_t x,\n uint32_t options) {\n return wuffs_base__private_implementation__render_number_u64(dst, x, options,\n false);\n}\n\n" +
"" +
"// ---------------- Hexadecimal\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t src_len2 = src.len / 2;\n size_t len = dst.len < src_len2 ? dst.len : src_len2;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n while (n--) {\n *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[0]] << 4) |\n (wuffs_base__parse_number__hexadecimal_digits[s[1]] & 0x0F));\n d += 1;\n s += 2;\n }\n\n return len;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t src_len4 = src.len / 4;\n size_t len = dst.len < src_len4 ? dst.len : src_len4;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n while (n--) {\n *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[2]] << 4) |\n (wuffs_base__parse_number__hexa" +
- "decimal_digits[s[3]] & 0x0F));\n d += 1;\n s += 4;\n }\n\n return len;\n}\n" +
+ "decimal_digits[s[3]] & 0x0F));\n d += 1;\n s += 4;\n }\n\n return len;\n}\n\n" +
+ "" +
+ "// ---------------- Base-64\n\n// The two base-64 alphabets, std and url, differ only in the last two codes.\n// - std: \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n// - url: \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\"\n\nstatic const uint8_t wuffs_base__base_64__decode_std[256] = {\n // 0 1 2 3 4 5 6 7\n // 8 9 A B C D E F\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x00 ..= 0x07.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x08 ..= 0x0F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x10 ..= 0x17.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x18 ..= 0x1F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x20 ..= 0x27.\n 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, // 0x28 ..= 0x2F.\n 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 ..= 0x37.\n 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x38 ..= 0x3F.\n\n 0x80, 0x00, 0x01, 0x02," +
+ " 0x03, 0x04, 0x05, 0x06, // 0x40 ..= 0x47.\n 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 ..= 0x4F.\n 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 ..= 0x57.\n 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x58 ..= 0x5F.\n 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 ..= 0x67.\n 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 ..= 0x6F.\n 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 ..= 0x77.\n 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x78 ..= 0x7F.\n\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x80 ..= 0x87.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x88 ..= 0x8F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x90 ..= 0x97.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x98 ..= 0x9F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA0 ..= 0xA7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA8 ..= 0xAF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // " +
+ "0xB0 ..= 0xB7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB8 ..= 0xBF.\n\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC0 ..= 0xC7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC8 ..= 0xCF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD0 ..= 0xD7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD8 ..= 0xDF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE0 ..= 0xE7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE8 ..= 0xEF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF0 ..= 0xF7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF8 ..= 0xFF.\n // 0 1 2 3 4 5 6 7\n // 8 9 A B C D E F\n};\n\nstatic const uint8_t wuffs_base__base_64__decode_url[256] = {\n // 0 1 2 3 4 5 6 7\n // 8 9 A B C D E F\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x00 ..= 0x07.\n 0x80, 0x80, 0x80, 0x80, " +
+ "0x80, 0x80, 0x80, 0x80, // 0x08 ..= 0x0F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x10 ..= 0x17.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x18 ..= 0x1F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x20 ..= 0x27.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, // 0x28 ..= 0x2F.\n 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 ..= 0x37.\n 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x38 ..= 0x3F.\n\n 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40 ..= 0x47.\n 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 ..= 0x4F.\n 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 ..= 0x57.\n 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x3F, // 0x58 ..= 0x5F.\n 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 ..= 0x67.\n 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 ..= 0x6F.\n 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 ..= 0x77.\n 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 0" +
+ "x78 ..= 0x7F.\n\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x80 ..= 0x87.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x88 ..= 0x8F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x90 ..= 0x97.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x98 ..= 0x9F.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA0 ..= 0xA7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA8 ..= 0xAF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB0 ..= 0xB7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB8 ..= 0xBF.\n\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC0 ..= 0xC7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC8 ..= 0xCF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD0 ..= 0xD7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD8 ..= 0xDF.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE0 ..= 0xE7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE8 ..= 0xEF.\n 0x80, 0x80" +
+ ", 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF0 ..= 0xF7.\n 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF8 ..= 0xFF.\n // 0 1 2 3 4 5 6 7\n // 8 9 A B C D E F\n};\n\nstatic const uint8_t wuffs_base__base_64__encode_std[64] = {\n // 0 1 2 3 4 5 6 7\n // 8 9 A B C D E F\n 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // 0x00 ..= 0x07.\n 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // 0x08 ..= 0x0F.\n 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // 0x10 ..= 0x17.\n 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 0x18 ..= 0x1F.\n 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 0x20 ..= 0x27.\n 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, // 0x28 ..= 0x2F.\n 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, // 0x30 ..= 0x37.\n 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, // 0x38 ..= 0x3F.\n};\n\nstatic const uint8_t wuffs_base__base_64__encode_url[64" +
+ "] = {\n // 0 1 2 3 4 5 6 7\n // 8 9 A B C D E F\n 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // 0x00 ..= 0x07.\n 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // 0x08 ..= 0x0F.\n 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // 0x10 ..= 0x17.\n 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 0x18 ..= 0x1F.\n 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 0x20 ..= 0x27.\n 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, // 0x28 ..= 0x2F.\n 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, // 0x30 ..= 0x37.\n 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2D, 0x5F, // 0x38 ..= 0x3F.\n};\n\n" +
+ "" +
+ "// --------\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //\nwuffs_base__base_64__decode(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src,\n bool src_closed,\n uint32_t options) {\n const uint8_t* alphabet = (options & WUFFS_BASE__BASE_64__URL_ALPHABET)\n ? wuffs_base__base_64__decode_url\n : wuffs_base__base_64__decode_std;\n wuffs_base__transform__output o;\n uint8_t* d_ptr = dst.ptr;\n size_t d_len = dst.len;\n const uint8_t* s_ptr = src.ptr;\n size_t s_len = src.len;\n bool pad = false;\n\n while (s_len >= 4) {\n uint32_t s = wuffs_base__load_u32le__no_bounds_check(s_ptr);\n uint32_t s0 = alphabet[0xFF & (s >> 0)];\n uint32_t s1 = alphabet[0xFF & (s >> 8)];\n uint32_t s2 = alphabet[0xFF & (s >> 16)];\n uint32_t s3 = alphabet[0xFF & (s >> 24)];\n\n if (((s0 | s1 | s2 | s3) & 0xC0) != 0) {\n if (s_len > 4) {\n o.status.repr = wuffs_base_" +
+ "_error__bad_data;\n goto done;\n } else if (!src_closed) {\n o.status.repr = wuffs_base__suspension__short_read;\n goto done;\n } else if ((options & WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING) &&\n (s_ptr[3] == '=')) {\n pad = true;\n if (s_ptr[2] == '=') {\n goto src2;\n }\n goto src3;\n }\n o.status.repr = wuffs_base__error__bad_data;\n goto done;\n }\n\n if (d_len < 3) {\n o.status.repr = wuffs_base__suspension__short_write;\n goto done;\n }\n\n s_ptr += 4;\n s_len -= 4;\n s = (s0 << 18) | (s1 << 12) | (s2 << 6) | (s3 << 0);\n *d_ptr++ = (uint8_t)(s >> 16);\n *d_ptr++ = (uint8_t)(s >> 8);\n *d_ptr++ = (uint8_t)(s >> 0);\n d_len -= 3;\n }\n\n if (!src_closed) {\n o.status.repr = wuffs_base__suspension__short_read;\n goto done;\n }\n\n if (s_len == 0) {\n o.status.repr = NULL;\n goto done;\n } else if (s_len == 1) {\n o.status.repr = wuffs_base__error__bad_data;\n goto done;\n } else if (s" +
+ "_len == 2) {\n goto src2;\n }\n\nsrc3:\n do {\n uint32_t s = wuffs_base__load_u24le__no_bounds_check(s_ptr);\n uint32_t s0 = alphabet[0xFF & (s >> 0)];\n uint32_t s1 = alphabet[0xFF & (s >> 8)];\n uint32_t s2 = alphabet[0xFF & (s >> 16)];\n if ((s0 & 0xC0) || (s1 & 0xC0) || (s2 & 0xC3)) {\n o.status.repr = wuffs_base__error__bad_data;\n goto done;\n }\n if (d_len < 2) {\n o.status.repr = wuffs_base__suspension__short_write;\n goto done;\n }\n s_ptr += pad ? 4 : 3;\n s = (s0 << 18) | (s1 << 12) | (s2 << 6);\n *d_ptr++ = (uint8_t)(s >> 16);\n *d_ptr++ = (uint8_t)(s >> 8);\n o.status.repr = NULL;\n goto done;\n } while (0);\n\nsrc2:\n do {\n uint32_t s = wuffs_base__load_u16le__no_bounds_check(s_ptr);\n uint32_t s0 = alphabet[0xFF & (s >> 0)];\n uint32_t s1 = alphabet[0xFF & (s >> 8)];\n if ((s0 & 0xC0) || (s1 & 0xCF)) {\n o.status.repr = wuffs_base__error__bad_data;\n goto done;\n }\n if (d_len < 1) {\n o.status.repr = wuffs_base__suspension__sho" +
+ "rt_write;\n goto done;\n }\n s_ptr += pad ? 4 : 2;\n s = (s0 << 18) | (s1 << 12);\n *d_ptr++ = (uint8_t)(s >> 16);\n o.status.repr = NULL;\n goto done;\n } while (0);\n\ndone:\n o.num_dst = d_ptr - dst.ptr;\n o.num_src = s_ptr - src.ptr;\n return o;\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //\nwuffs_base__base_64__encode(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src,\n bool src_closed,\n uint32_t options) {\n const uint8_t* alphabet = (options & WUFFS_BASE__BASE_64__URL_ALPHABET)\n ? wuffs_base__base_64__encode_url\n : wuffs_base__base_64__encode_std;\n wuffs_base__transform__output o;\n uint8_t* d_ptr = dst.ptr;\n size_t d_len = dst.len;\n const uint8_t* s_ptr = src.ptr;\n size_t s_len = src.len;\n\n do {\n while (s_len >= 3) {\n if (d_len < 4) {\n o.status.repr = wuffs_base__suspension__short_write;\n goto done;\n " +
+ " }\n uint32_t s = wuffs_base__load_u24be__no_bounds_check(s_ptr);\n s_ptr += 3;\n s_len -= 3;\n *d_ptr++ = alphabet[0x3F & (s >> 18)];\n *d_ptr++ = alphabet[0x3F & (s >> 12)];\n *d_ptr++ = alphabet[0x3F & (s >> 6)];\n *d_ptr++ = alphabet[0x3F & (s >> 0)];\n d_len -= 4;\n }\n\n if (!src_closed) {\n o.status.repr = wuffs_base__suspension__short_read;\n goto done;\n }\n\n if (s_len == 2) {\n if (d_len <\n ((options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) ? 4 : 3)) {\n o.status.repr = wuffs_base__suspension__short_write;\n goto done;\n }\n uint32_t s = ((uint32_t)(wuffs_base__load_u16be__no_bounds_check(s_ptr)))\n << 8;\n s_ptr += 2;\n *d_ptr++ = alphabet[0x3F & (s >> 18)];\n *d_ptr++ = alphabet[0x3F & (s >> 12)];\n *d_ptr++ = alphabet[0x3F & (s >> 6)];\n if (options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) {\n *d_ptr++ = '=';\n }\n o.status.repr = NULL;\n goto done;\n\n } e" +
+ "lse if (s_len == 1) {\n if (d_len <\n ((options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) ? 4 : 2)) {\n o.status.repr = wuffs_base__suspension__short_write;\n goto done;\n }\n uint32_t s = ((uint32_t)(wuffs_base__load_u8__no_bounds_check(s_ptr)))\n << 16;\n s_ptr += 1;\n *d_ptr++ = alphabet[0x3F & (s >> 18)];\n *d_ptr++ = alphabet[0x3F & (s >> 12)];\n if (options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) {\n *d_ptr++ = '=';\n *d_ptr++ = '=';\n }\n o.status.repr = NULL;\n goto done;\n\n } else {\n o.status.repr = NULL;\n goto done;\n }\n } while (0);\n\ndone:\n o.num_dst = d_ptr - dst.ptr;\n o.num_src = s_ptr - src.ptr;\n return o;\n}\n" +
""
const BasePixConvSubmoduleC = "" +
@@ -297,6 +312,8 @@
"" +
"// --------\n\n// WUFFS_BASE__RESULT is a result type: either a status (an error) or a value.\n//\n// A result with all fields NULL or zero is as valid as a zero-valued T.\n#define WUFFS_BASE__RESULT(T) \\\n struct { \\\n wuffs_base__status status; \\\n T value; \\\n }\n\ntypedef WUFFS_BASE__RESULT(double) wuffs_base__result_f64;\ntypedef WUFFS_BASE__RESULT(int64_t) wuffs_base__result_i64;\ntypedef WUFFS_BASE__RESULT(uint64_t) wuffs_base__result_u64;\n\n" +
"" +
+ "// --------\n\n// wuffs_base__transform__output is the result of transforming from a src slice\n// to a dst slice.\ntypedef struct {\n wuffs_base__status status;\n size_t num_dst;\n size_t num_src;\n} wuffs_base__transform__output;\n\n" +
+ "" +
"// --------\n\n// FourCC constants.\n\n// !! INSERT FourCCs.\n\n" +
"" +
"// --------\n\n// Flicks are a unit of time. One flick (frame-tick) is 1 / 705_600_000 of a\n// second. See https://github.com/OculusVR/Flicks\ntypedef int64_t wuffs_base__flicks;\n\n#define WUFFS_BASE__FLICKS_PER_SECOND ((uint64_t)705600000)\n#define WUFFS_BASE__FLICKS_PER_MILLISECOND ((uint64_t)705600)\n\n" +
@@ -512,6 +529,10 @@
"// ---------------- Hexadecimal\n\n// wuffs_base__hexadecimal__decode2 converts \"6A6b\" to \"jk\", where e.g. 'j' is\n// U+006A. There are 2 source bytes for every destination byte.\n//\n// It returns the number of dst bytes written: the minimum of dst.len and\n// (src.len / 2). Excess source bytes are ignored.\n//\n// It assumes that the src bytes are two hexadecimal digits (0-9, A-F, a-f),\n// repeated. It may write nonsense bytes if not, although it will not read or\n// write out of bounds.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not\n// just WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src);\n\n// wuffs_base__hexadecimal__decode4 converts \"\\\\x6A\\\\x6b\" to \"jk\", where e.g.\n// 'j' is U+006A. There are 4 source bytes for every destination byte.\n//\n// It returns the number of d" +
"st bytes written: the minimum of dst.len and\n// (src.len / 4). Excess source bytes are ignored.\n//\n// It assumes that the src bytes are two ignored bytes and then two hexadecimal\n// digits (0-9, A-F, a-f), repeated. It may write nonsense bytes if not,\n// although it will not read or write out of bounds.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not\n// just WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src);\n\n" +
"" +
+ "// ---------------- Base-64\n\n// Options (bitwise or'ed together) for wuffs_base__base_64__xxx functions.\n\n#define WUFFS_BASE__BASE_64__DEFAULT_OPTIONS ((uint32_t)0x00000000)\n\n// WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING means that, when decoding base-64,\n// the input may (but does not need to) be padded with '=' bytes so that the\n// overall encoded length in bytes is a multiple of 4. A successful decoding\n// will return a num_src that includes those padding bytes.\n//\n// Excess padding (e.g. three final '='s) will be rejected as bad data.\n#define WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING ((uint32_t)0x00000001)\n\n// WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING means that, when encoding base-64,\n// the output will be padded with '=' bytes so that the overall encoded length\n// in bytes is a multiple of 4.\n#define WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING ((uint32_t)0x00000002)\n\n// WUFFS_BASE__BASE_64__URL_ALPHABET means that, for base-64, the URL-friendly\n// and file-name-friendly alphabet be used, as per RFC 4648 sect" +
+ "ion 5. When\n// this option bit is off, the standard alphabet from section 4 is used.\n#define WUFFS_BASE__BASE_64__URL_ALPHABET ((uint32_t)0x00000100)\n\n// wuffs_base__base_64__decode transforms base-64 encoded bytes from src to\n// arbitrary bytes in dst.\n//\n// It will not permit line breaks or other whitespace in src. Filtering those\n// out is the responsibility of the caller.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not\n// just WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //\nwuffs_base__base_64__decode(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src,\n bool src_closed,\n uint32_t options);\n\n// wuffs_base__base_64__encode transforms arbitrary bytes from src to base-64\n// encoded bytes in dst.\n//\n// For modular builds that divide the base module into sub-modules, using this" +
+ "\n// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not\n// just WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //\nwuffs_base__base_64__encode(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src,\n bool src_closed,\n uint32_t options);\n\n" +
+ "" +
"// ---------------- Unicode and UTF-8\n\n#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000\n#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF\n\n#define WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER 0x0000FFFD\n\n#define WUFFS_BASE__UNICODE_SURROGATE__MIN_INCL 0x0000D800\n#define WUFFS_BASE__UNICODE_SURROGATE__MAX_INCL 0x0000DFFF\n\n#define WUFFS_BASE__ASCII__MIN_INCL 0x00\n#define WUFFS_BASE__ASCII__MAX_INCL 0x7F\n\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH__MIN_INCL 1\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL 4\n\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_1__CODE_POINT__MIN_INCL 0x00000000\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_1__CODE_POINT__MAX_INCL 0x0000007F\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_2__CODE_POINT__MIN_INCL 0x00000080\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_2__CODE_POINT__MAX_INCL 0x000007FF\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_3__CODE_POINT__MIN_INCL 0x00000800\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_3__CODE_POINT__MAX_INCL 0x0000FFFF\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_4__CODE_POINT_" +
"_MIN_INCL 0x00010000\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_4__CODE_POINT__MAX_INCL 0x0010FFFF\n\n" +
"" +
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index 6944190..44775f9 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -160,6 +160,7 @@
`"#bad argument (length too short)"`,
`"#bad argument"`,
`"#bad call sequence"`,
+ `"#bad data"`,
`"#bad receiver"`,
`"#bad restart"`,
`"#bad sizeof receiver"`,
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index b24ecaf..9f188e1 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -206,6 +206,7 @@
extern const char wuffs_base__error__bad_argument_length_too_short[];
extern const char wuffs_base__error__bad_argument[];
extern const char wuffs_base__error__bad_call_sequence[];
+extern const char wuffs_base__error__bad_data[];
extern const char wuffs_base__error__bad_receiver[];
extern const char wuffs_base__error__bad_restart[];
extern const char wuffs_base__error__bad_sizeof_receiver[];
@@ -319,6 +320,16 @@
// --------
+// wuffs_base__transform__output is the result of transforming from a src slice
+// to a dst slice.
+typedef struct {
+ wuffs_base__status status;
+ size_t num_dst;
+ size_t num_src;
+} wuffs_base__transform__output;
+
+// --------
+
// FourCC constants.
// International Color Consortium Profile.
@@ -4201,6 +4212,57 @@
wuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 src);
+// ---------------- Base-64
+
+// Options (bitwise or'ed together) for wuffs_base__base_64__xxx functions.
+
+#define WUFFS_BASE__BASE_64__DEFAULT_OPTIONS ((uint32_t)0x00000000)
+
+// WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING means that, when decoding base-64,
+// the input may (but does not need to) be padded with '=' bytes so that the
+// overall encoded length in bytes is a multiple of 4. A successful decoding
+// will return a num_src that includes those padding bytes.
+//
+// Excess padding (e.g. three final '='s) will be rejected as bad data.
+#define WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING ((uint32_t)0x00000001)
+
+// WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING means that, when encoding base-64,
+// the output will be padded with '=' bytes so that the overall encoded length
+// in bytes is a multiple of 4.
+#define WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING ((uint32_t)0x00000002)
+
+// WUFFS_BASE__BASE_64__URL_ALPHABET means that, for base-64, the URL-friendly
+// and file-name-friendly alphabet be used, as per RFC 4648 section 5. When
+// this option bit is off, the standard alphabet from section 4 is used.
+#define WUFFS_BASE__BASE_64__URL_ALPHABET ((uint32_t)0x00000100)
+
+// wuffs_base__base_64__decode transforms base-64 encoded bytes from src to
+// arbitrary bytes in dst.
+//
+// It will not permit line breaks or other whitespace in src. Filtering those
+// out is the responsibility of the caller.
+//
+// For modular builds that divide the base module into sub-modules, using this
+// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not
+// just WUFFS_CONFIG__MODULE__BASE__CORE.
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__decode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options);
+
+// wuffs_base__base_64__encode transforms arbitrary bytes from src to base-64
+// encoded bytes in dst.
+//
+// For modular builds that divide the base module into sub-modules, using this
+// function requires the WUFFS_CONFIG__MODULE__BASE__I64CONV sub-module, not
+// just WUFFS_CONFIG__MODULE__BASE__CORE.
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__encode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options);
+
// ---------------- Unicode and UTF-8
#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000
@@ -8391,6 +8453,7 @@
const char wuffs_base__error__bad_argument_length_too_short[] = "#base: bad argument (length too short)";
const char wuffs_base__error__bad_argument[] = "#base: bad argument";
const char wuffs_base__error__bad_call_sequence[] = "#base: bad call sequence";
+const char wuffs_base__error__bad_data[] = "#base: bad data";
const char wuffs_base__error__bad_receiver[] = "#base: bad receiver";
const char wuffs_base__error__bad_restart[] = "#base: bad restart";
const char wuffs_base__error__bad_sizeof_receiver[] = "#base: bad sizeof receiver";
@@ -11940,6 +12003,325 @@
return len;
}
+// ---------------- Base-64
+
+// The two base-64 alphabets, std and url, differ only in the last two codes.
+// - std: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+// - url: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+
+static const uint8_t wuffs_base__base_64__decode_std[256] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x00 ..= 0x07.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x08 ..= 0x0F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x10 ..= 0x17.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x18 ..= 0x1F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x20 ..= 0x27.
+ 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, // 0x28 ..= 0x2F.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 ..= 0x37.
+ 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x38 ..= 0x3F.
+
+ 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40 ..= 0x47.
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 ..= 0x4F.
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 ..= 0x57.
+ 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x58 ..= 0x5F.
+ 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 ..= 0x67.
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 ..= 0x6F.
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 ..= 0x77.
+ 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x78 ..= 0x7F.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x80 ..= 0x87.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x88 ..= 0x8F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x90 ..= 0x97.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x98 ..= 0x9F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA0 ..= 0xA7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA8 ..= 0xAF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB0 ..= 0xB7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB8 ..= 0xBF.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC0 ..= 0xC7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC8 ..= 0xCF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD0 ..= 0xD7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD8 ..= 0xDF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE0 ..= 0xE7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE8 ..= 0xEF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF0 ..= 0xF7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF8 ..= 0xFF.
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+};
+
+static const uint8_t wuffs_base__base_64__decode_url[256] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x00 ..= 0x07.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x08 ..= 0x0F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x10 ..= 0x17.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x18 ..= 0x1F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x20 ..= 0x27.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, // 0x28 ..= 0x2F.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 ..= 0x37.
+ 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x38 ..= 0x3F.
+
+ 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40 ..= 0x47.
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 ..= 0x4F.
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 ..= 0x57.
+ 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x3F, // 0x58 ..= 0x5F.
+ 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 ..= 0x67.
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 ..= 0x6F.
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 ..= 0x77.
+ 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x78 ..= 0x7F.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x80 ..= 0x87.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x88 ..= 0x8F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x90 ..= 0x97.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0x98 ..= 0x9F.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA0 ..= 0xA7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xA8 ..= 0xAF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB0 ..= 0xB7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xB8 ..= 0xBF.
+
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC0 ..= 0xC7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xC8 ..= 0xCF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD0 ..= 0xD7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xD8 ..= 0xDF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE0 ..= 0xE7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xE8 ..= 0xEF.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF0 ..= 0xF7.
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 0xF8 ..= 0xFF.
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+};
+
+static const uint8_t wuffs_base__base_64__encode_std[64] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // 0x00 ..= 0x07.
+ 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // 0x08 ..= 0x0F.
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // 0x10 ..= 0x17.
+ 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 0x18 ..= 0x1F.
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 0x20 ..= 0x27.
+ 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, // 0x28 ..= 0x2F.
+ 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, // 0x30 ..= 0x37.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, // 0x38 ..= 0x3F.
+};
+
+static const uint8_t wuffs_base__base_64__encode_url[64] = {
+ // 0 1 2 3 4 5 6 7
+ // 8 9 A B C D E F
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // 0x00 ..= 0x07.
+ 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // 0x08 ..= 0x0F.
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // 0x10 ..= 0x17.
+ 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 0x18 ..= 0x1F.
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 0x20 ..= 0x27.
+ 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, // 0x28 ..= 0x2F.
+ 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, // 0x30 ..= 0x37.
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2D, 0x5F, // 0x38 ..= 0x3F.
+};
+
+// --------
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__decode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options) {
+ const uint8_t* alphabet = (options & WUFFS_BASE__BASE_64__URL_ALPHABET)
+ ? wuffs_base__base_64__decode_url
+ : wuffs_base__base_64__decode_std;
+ wuffs_base__transform__output o;
+ uint8_t* d_ptr = dst.ptr;
+ size_t d_len = dst.len;
+ const uint8_t* s_ptr = src.ptr;
+ size_t s_len = src.len;
+ bool pad = false;
+
+ while (s_len >= 4) {
+ uint32_t s = wuffs_base__load_u32le__no_bounds_check(s_ptr);
+ uint32_t s0 = alphabet[0xFF & (s >> 0)];
+ uint32_t s1 = alphabet[0xFF & (s >> 8)];
+ uint32_t s2 = alphabet[0xFF & (s >> 16)];
+ uint32_t s3 = alphabet[0xFF & (s >> 24)];
+
+ if (((s0 | s1 | s2 | s3) & 0xC0) != 0) {
+ if (s_len > 4) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ } else if (!src_closed) {
+ o.status.repr = wuffs_base__suspension__short_read;
+ goto done;
+ } else if ((options & WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING) &&
+ (s_ptr[3] == '=')) {
+ pad = true;
+ if (s_ptr[2] == '=') {
+ goto src2;
+ }
+ goto src3;
+ }
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ }
+
+ if (d_len < 3) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+
+ s_ptr += 4;
+ s_len -= 4;
+ s = (s0 << 18) | (s1 << 12) | (s2 << 6) | (s3 << 0);
+ *d_ptr++ = (uint8_t)(s >> 16);
+ *d_ptr++ = (uint8_t)(s >> 8);
+ *d_ptr++ = (uint8_t)(s >> 0);
+ d_len -= 3;
+ }
+
+ if (!src_closed) {
+ o.status.repr = wuffs_base__suspension__short_read;
+ goto done;
+ }
+
+ if (s_len == 0) {
+ o.status.repr = NULL;
+ goto done;
+ } else if (s_len == 1) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ } else if (s_len == 2) {
+ goto src2;
+ }
+
+src3:
+ do {
+ uint32_t s = wuffs_base__load_u24le__no_bounds_check(s_ptr);
+ uint32_t s0 = alphabet[0xFF & (s >> 0)];
+ uint32_t s1 = alphabet[0xFF & (s >> 8)];
+ uint32_t s2 = alphabet[0xFF & (s >> 16)];
+ if ((s0 & 0xC0) || (s1 & 0xC0) || (s2 & 0xC3)) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ }
+ if (d_len < 2) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ s_ptr += pad ? 4 : 3;
+ s = (s0 << 18) | (s1 << 12) | (s2 << 6);
+ *d_ptr++ = (uint8_t)(s >> 16);
+ *d_ptr++ = (uint8_t)(s >> 8);
+ o.status.repr = NULL;
+ goto done;
+ } while (0);
+
+src2:
+ do {
+ uint32_t s = wuffs_base__load_u16le__no_bounds_check(s_ptr);
+ uint32_t s0 = alphabet[0xFF & (s >> 0)];
+ uint32_t s1 = alphabet[0xFF & (s >> 8)];
+ if ((s0 & 0xC0) || (s1 & 0xCF)) {
+ o.status.repr = wuffs_base__error__bad_data;
+ goto done;
+ }
+ if (d_len < 1) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ s_ptr += pad ? 4 : 2;
+ s = (s0 << 18) | (s1 << 12);
+ *d_ptr++ = (uint8_t)(s >> 16);
+ o.status.repr = NULL;
+ goto done;
+ } while (0);
+
+done:
+ o.num_dst = d_ptr - dst.ptr;
+ o.num_src = s_ptr - src.ptr;
+ return o;
+}
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__transform__output //
+wuffs_base__base_64__encode(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src,
+ bool src_closed,
+ uint32_t options) {
+ const uint8_t* alphabet = (options & WUFFS_BASE__BASE_64__URL_ALPHABET)
+ ? wuffs_base__base_64__encode_url
+ : wuffs_base__base_64__encode_std;
+ wuffs_base__transform__output o;
+ uint8_t* d_ptr = dst.ptr;
+ size_t d_len = dst.len;
+ const uint8_t* s_ptr = src.ptr;
+ size_t s_len = src.len;
+
+ do {
+ while (s_len >= 3) {
+ if (d_len < 4) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ uint32_t s = wuffs_base__load_u24be__no_bounds_check(s_ptr);
+ s_ptr += 3;
+ s_len -= 3;
+ *d_ptr++ = alphabet[0x3F & (s >> 18)];
+ *d_ptr++ = alphabet[0x3F & (s >> 12)];
+ *d_ptr++ = alphabet[0x3F & (s >> 6)];
+ *d_ptr++ = alphabet[0x3F & (s >> 0)];
+ d_len -= 4;
+ }
+
+ if (!src_closed) {
+ o.status.repr = wuffs_base__suspension__short_read;
+ goto done;
+ }
+
+ if (s_len == 2) {
+ if (d_len <
+ ((options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) ? 4 : 3)) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ uint32_t s = ((uint32_t)(wuffs_base__load_u16be__no_bounds_check(s_ptr)))
+ << 8;
+ s_ptr += 2;
+ *d_ptr++ = alphabet[0x3F & (s >> 18)];
+ *d_ptr++ = alphabet[0x3F & (s >> 12)];
+ *d_ptr++ = alphabet[0x3F & (s >> 6)];
+ if (options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) {
+ *d_ptr++ = '=';
+ }
+ o.status.repr = NULL;
+ goto done;
+
+ } else if (s_len == 1) {
+ if (d_len <
+ ((options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) ? 4 : 2)) {
+ o.status.repr = wuffs_base__suspension__short_write;
+ goto done;
+ }
+ uint32_t s = ((uint32_t)(wuffs_base__load_u8__no_bounds_check(s_ptr)))
+ << 16;
+ s_ptr += 1;
+ *d_ptr++ = alphabet[0x3F & (s >> 18)];
+ *d_ptr++ = alphabet[0x3F & (s >> 12)];
+ if (options & WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING) {
+ *d_ptr++ = '=';
+ *d_ptr++ = '=';
+ }
+ o.status.repr = NULL;
+ goto done;
+
+ } else {
+ o.status.repr = NULL;
+ goto done;
+ }
+ } while (0);
+
+done:
+ o.num_dst = d_ptr - dst.ptr;
+ o.num_src = s_ptr - src.ptr;
+ return o;
+}
+
#endif // !defined(WUFFS_CONFIG__MODULES) ||
// defined(WUFFS_CONFIG__MODULE__BASE) ||
// defined(WUFFS_CONFIG__MODULE__BASE__I64CONV)
diff --git a/test/c/std/json.c b/test/c/std/json.c
index 5884997..7c8f527 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -471,6 +471,94 @@
}
const char* //
+test_wuffs_strconv_base_64() {
+ CHECK_FOCUS(__func__);
+
+ char* foobar = "foobar";
+ const char* wants[] = {
+ "", //
+ "Zg==", //
+ "Zm8=", //
+ "Zm9v", //
+ "Zm9vYg==", //
+ "Zm9vYmE=", //
+ "Zm9vYmFy", //
+ };
+
+ size_t tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(wants); tc++) {
+ const bool src_closed = true;
+
+ wuffs_base__transform__output e = wuffs_base__base_64__encode(
+ g_have_slice_u8, wuffs_base__make_slice_u8(((uint8_t*)foobar), tc),
+ src_closed, WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING);
+ if (e.status.repr) {
+ RETURN_FAIL("tc=%zu: encode: \"%s\"", tc, e.status.repr);
+ }
+ if (e.num_src != tc) {
+ RETURN_FAIL("tc=%zu: encode: num_src: have %zu, want %zu", tc, e.num_src,
+ tc);
+ }
+ if (e.num_dst != (((tc + 2) / 3) * 4)) {
+ RETURN_FAIL("tc=%zu: encode: num_dst: have %zu, want %zu", tc, e.num_dst,
+ (((tc + 2) / 3) * 4));
+ }
+ if ((e.num_dst + 1) > g_have_slice_u8.len) {
+ RETURN_FAIL("tc=%zu: encode: num_dst is too large", tc);
+ }
+ g_have_slice_u8.ptr[e.num_dst] = '\x00';
+ if (strncmp((const char*)(g_have_slice_u8.ptr), wants[tc], e.num_dst) !=
+ 0) {
+ RETURN_FAIL("tc=%zu: encode:\nhave \"%s\"\nwant \"%s\"", tc,
+ g_have_slice_u8.ptr, wants[tc]);
+ }
+
+ int trim;
+ for (trim = 0; trim < 2; trim++) {
+ size_t n = e.num_dst;
+ if (trim) {
+ while ((n > 0) && (g_have_slice_u8.ptr[n - 1] == '=')) {
+ n--;
+ }
+ }
+
+ wuffs_base__transform__output d = wuffs_base__base_64__decode(
+ g_work_slice_u8, wuffs_base__make_slice_u8(g_have_slice_u8.ptr, n),
+ src_closed, WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING);
+ if (d.status.repr) {
+ RETURN_FAIL("tc=%zu: trim=%d: decode: \"%s\"", tc, trim, d.status.repr);
+ }
+ if (d.num_src != n) {
+ RETURN_FAIL("tc=%zu: trim=%d: decode: num_src: have %zu, want %zu", tc,
+ trim, d.num_src, n);
+ }
+ if (d.num_dst != tc) {
+ RETURN_FAIL("tc=%zu: trim=%d: decode: num_dst: have %zu, want %zu", tc,
+ trim, d.num_dst, tc);
+ }
+ if ((d.num_dst + 1) > g_work_slice_u8.len) {
+ RETURN_FAIL("tc=%zu: trim=%d: decode: num_dst is too large", tc, trim);
+ }
+ g_work_slice_u8.ptr[d.num_dst] = '\x00';
+ if ((tc + 1) > g_want_slice_u8.len) {
+ RETURN_FAIL("tc=%zu: trim=%d: decode: tc is too large", tc, trim);
+ }
+ memcpy(g_want_slice_u8.ptr, foobar, tc);
+ g_want_slice_u8.ptr[tc] = '\x00';
+ if (strcmp(((const char*)(g_work_slice_u8.ptr)),
+ ((const char*)(g_want_slice_u8.ptr))) != 0) {
+ RETURN_FAIL("tc=%zu: trim=%d: decode:\nhave \"%s\"\nwant \"%s\"", tc,
+ trim, g_work_slice_u8.ptr, g_want_slice_u8.ptr);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// ----------------
+
+const char* //
test_wuffs_strconv_parse_number_f64() {
CHECK_FOCUS(__func__);
@@ -751,6 +839,8 @@
return NULL;
}
+// ----------------
+
const char* //
test_wuffs_strconv_render_number_f64() {
CHECK_FOCUS(__func__);
@@ -1636,6 +1726,8 @@
return NULL;
}
+// ----------------
+
const char* //
test_wuffs_strconv_utf_8_next() {
CHECK_FOCUS(__func__);
@@ -3346,6 +3438,7 @@
test_wuffs_core_count_leading_zeroes_u64,
test_wuffs_core_multiply_u64,
test_wuffs_strconv_hexadecimal,
+ test_wuffs_strconv_base_64,
test_wuffs_strconv_hpd_rounded_integer,
test_wuffs_strconv_hpd_shift,
test_wuffs_strconv_parse_number_f64,