Add std/cbor
diff --git a/doc/changelog.md b/doc/changelog.md
index b320e7f..8f04555 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -13,6 +13,7 @@
- Added `example/imageviewer`.
- Added `example/jsonptr`.
- Added `std/bmp`.
+- Added `std/cbor`.
- Added `std/gif.config_decoder`.
- Added `std/json`.
- Added `std/wbmp`.
diff --git a/example/jsonptr/jsonptr.cc b/example/jsonptr/jsonptr.cc
index b476875..b5f86b6 100644
--- a/example/jsonptr/jsonptr.cc
+++ b/example/jsonptr/jsonptr.cc
@@ -121,6 +121,7 @@
// code simply isn't compiled.
#define WUFFS_CONFIG__MODULES
#define WUFFS_CONFIG__MODULE__BASE
+#define WUFFS_CONFIG__MODULE__CBOR
#define WUFFS_CONFIG__MODULE__JSON
// If building this program in an environment that doesn't easily accommodate
@@ -152,6 +153,7 @@
"Flags:\n"
" -c -compact-output\n"
" -d=NUM -max-output-depth=NUM\n"
+ " -i=FMT -input-format={json,cbor}\n"
" -o=FMT -output-format={json,cbor}\n"
" -q=STR -query=STR\n"
" -s=NUM -spaces=NUM\n"
@@ -316,7 +318,9 @@
uint32_t g_suppress_write_dst;
bool g_wrote_to_dst;
-wuffs_json__decoder g_dec;
+wuffs_cbor__decoder g_cbor_decoder;
+wuffs_json__decoder g_json_decoder;
+wuffs_base__token_decoder* g_dec;
// cbor_output_string_array is a 4 KiB buffer. For -output-format=cbor, strings
// whose length are 4096 or less are written as a single definite-length
@@ -597,6 +601,7 @@
bool compact_output;
bool fail_if_unsandboxed;
+ file_format input_format;
bool input_json_extra_comma;
uint32_t max_output_depth;
file_format output_format;
@@ -656,6 +661,14 @@
g_flags.fail_if_unsandboxed = true;
continue;
}
+ if (!strcmp(arg, "i=cbor") || !strcmp(arg, "input-format=cbor")) {
+ g_flags.input_format = file_format::cbor;
+ continue;
+ }
+ if (!strcmp(arg, "i=json") || !strcmp(arg, "input-format=json")) {
+ g_flags.input_format = file_format::json;
+ continue;
+ }
if (!strcmp(arg, "input-json-extra-comma")) {
g_flags.input_json_extra_comma = true;
continue;
@@ -747,18 +760,27 @@
g_suppress_write_dst = g_query.next_fragment() ? 1 : 0;
g_wrote_to_dst = false;
- TRY(g_dec.initialize(sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0)
- .message());
+ if (g_flags.input_format == file_format::json) {
+ TRY(g_json_decoder
+ .initialize(sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0)
+ .message());
+ g_dec = g_json_decoder.upcast_as__wuffs_base__token_decoder();
+ } else {
+ TRY(g_cbor_decoder
+ .initialize(sizeof__wuffs_cbor__decoder(), WUFFS_VERSION, 0)
+ .message());
+ g_dec = g_cbor_decoder.upcast_as__wuffs_base__token_decoder();
+ }
if (g_flags.input_json_extra_comma) {
- g_dec.set_quirk_enabled(WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA, true);
+ g_dec->set_quirk_enabled(WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA, true);
}
// Consume an optional whitespace trailer. This isn't part of the JSON spec,
// but it works better with line oriented Unix tools (such as "echo 123 |
// jsonptr" where it's "echo", not "echo -n") or hand-edited JSON files which
// can accidentally contain trailing whitespace.
- g_dec.set_quirk_enabled(WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE, true);
+ g_dec->set_quirk_enabled(WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE, true);
return nullptr;
}
@@ -937,11 +959,48 @@
const char* //
write_number(uint64_t vbd, uint8_t* ptr, size_t len) {
- if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT) {
- if (g_flags.output_format == file_format::json) {
+ if (g_flags.output_format == file_format::json) {
+ if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT) {
return write_dst(ptr, len);
+ } else if ((vbd &
+ WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED) &&
+ (vbd &
+ WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN)) {
+ if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_IGNORE_FIRST_BYTE) {
+ if (len == 0) {
+ goto fail;
+ }
+ ptr++;
+ len--;
+ }
+ uint64_t u;
+ switch (len) {
+ case 1:
+ u = wuffs_base__load_u8__no_bounds_check(ptr);
+ break;
+ case 2:
+ u = wuffs_base__load_u16be__no_bounds_check(ptr);
+ break;
+ case 4:
+ u = wuffs_base__load_u32be__no_bounds_check(ptr);
+ break;
+ case 8:
+ u = wuffs_base__load_u64be__no_bounds_check(ptr);
+ break;
+ default:
+ goto fail;
+ }
+ uint8_t buf[WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL];
+ size_t n = wuffs_base__render_number_u64(
+ wuffs_base__make_slice_u8(&buf[0], sizeof buf), u,
+ WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS);
+ return write_dst(&buf[0], n);
}
+ // From here on, (g_flags.output_format == file_format::cbor).
+ } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN) {
+ return write_dst(ptr, len);
+ } else if (vbd & WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT) {
// First try to parse (ptr, len) as an integer. Something like
// "1180591620717411303424" is a valid number (in the JSON sense) but will
// overflow int64_t or uint64_t, so fall back to parsing it as a float64.
@@ -973,9 +1032,23 @@
}
}
+fail:
return "main: internal error: unexpected write_number argument";
}
+const char* //
+write_inline_integer(uint64_t vbd, uint8_t* ptr, size_t len) {
+ if (g_flags.output_format == file_format::cbor) {
+ return write_dst(ptr, len);
+ }
+
+ uint8_t buf[WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL];
+ size_t n = wuffs_base__render_number_i64(
+ wuffs_base__make_slice_u8(&buf[0], sizeof buf), (int16_t)vbd,
+ WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS);
+ return write_dst(&buf[0], n);
+}
+
// ----
uint8_t //
@@ -1332,6 +1405,11 @@
TRY(write_number(vbd, g_src.data.ptr + g_curr_token_end_src_index - len,
len));
goto after_value;
+
+ case WUFFS_BASE__TOKEN__VBC__INLINE_INTEGER:
+ TRY(write_inline_integer(
+ vbd, g_src.data.ptr + g_curr_token_end_src_index - len, len));
+ goto after_value;
}
// Return an error if we didn't match the (vbc, vbd) pair.
@@ -1370,7 +1448,7 @@
bool start_of_token_chain = true;
while (true) {
- wuffs_base__status status = g_dec.decode_tokens(
+ wuffs_base__status status = g_dec->decode_tokens(
&g_tok, &g_src,
wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
diff --git a/internal/cgen/base/token-public.h b/internal/cgen/base/token-public.h
index 8dba529..362cc0e 100644
--- a/internal/cgen/base/token-public.h
+++ b/internal/cgen/base/token-public.h
@@ -63,6 +63,7 @@
#define WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT 3
#define WUFFS_BASE__TOKEN__VBC__LITERAL 4
#define WUFFS_BASE__TOKEN__VBC__NUMBER 5
+#define WUFFS_BASE__TOKEN__VBC__INLINE_INTEGER 6
// --------
@@ -137,7 +138,7 @@
// --------
// For a source string of "123" or "0x9A", it is valid for a tokenizer to
-// return any one of:
+// return any combination of:
// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.
// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.
// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.
@@ -156,11 +157,14 @@
// The number 300 might be represented as "\x01\x2C", "\x2C\x01\x00\x00" or
// "300", which are big-endian, little-endian or text. For binary formats, the
-// token length discriminates e.g. u16 little-endian vs u32 little-endian.
+// token length (after adjusting for FORMAT_IGNORE_ETC) discriminates
+// e.g. u16 little-endian vs u32 little-endian.
#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100
#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN 0x00200
#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_IGNORE_FIRST_BYTE 0x01000
+
// --------
// wuffs_base__token__value returns the token's high 46 bits, sign-extended. A
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 1530fca..f4629f0 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -569,7 +569,7 @@
"" +
"// --------\n\n#define WUFFS_BASE__TOKEN__LENGTH__MAX_INCL 0xFFFF\n\n#define WUFFS_BASE__TOKEN__VALUE__SHIFT 17\n#define WUFFS_BASE__TOKEN__VALUE_EXTENSION__SHIFT 17\n#define WUFFS_BASE__TOKEN__VALUE_MAJOR__SHIFT 42\n#define WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT 17\n#define WUFFS_BASE__TOKEN__VALUE_BASE_CATEGORY__SHIFT 38\n#define WUFFS_BASE__TOKEN__VALUE_BASE_DETAIL__SHIFT 17\n#define WUFFS_BASE__TOKEN__CONTINUED__SHIFT 16\n#define WUFFS_BASE__TOKEN__LENGTH__SHIFT 0\n\n" +
"" +
- "// --------\n\n#define WUFFS_BASE__TOKEN__VBC__FILLER 0\n#define WUFFS_BASE__TOKEN__VBC__STRUCTURE 1\n#define WUFFS_BASE__TOKEN__VBC__STRING 2\n#define WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT 3\n#define WUFFS_BASE__TOKEN__VBC__LITERAL 4\n#define WUFFS_BASE__TOKEN__VBC__NUMBER 5\n\n" +
+ "// --------\n\n#define WUFFS_BASE__TOKEN__VBC__FILLER 0\n#define WUFFS_BASE__TOKEN__VBC__STRUCTURE 1\n#define WUFFS_BASE__TOKEN__VBC__STRING 2\n#define WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT 3\n#define WUFFS_BASE__TOKEN__VBC__LITERAL 4\n#define WUFFS_BASE__TOKEN__VBC__NUMBER 5\n#define WUFFS_BASE__TOKEN__VBC__INLINE_INTEGER 6\n\n" +
"" +
"// --------\n\n#define WUFFS_BASE__TOKEN__VBD__FILLER__COMMENT_LINE 0x00001\n#define WUFFS_BASE__TOKEN__VBD__FILLER__COMMENT_BLOCK 0x00002\n\n" +
"" +
@@ -581,8 +581,8 @@
"" +
"// --------\n\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__UNDEFINED 0x00001\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__NULL 0x00002\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__FALSE 0x00004\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__TRUE 0x00008\n\n" +
"" +
- "// --------\n\n// For a source string of \"123\" or \"0x9A\", it is valid for a tokenizer to\n// return any one of:\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.\n//\n// For a source string of \"+123\" or \"-0x9A\", only the first two are valid.\n//\n// For a source string of \"123.\", only the first one is valid.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT 0x00001\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004\n\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080\n\n// The number 300 might be represented as \"\\x01\\x2C\", \"\\x2C\\x01\\x00\\x00\" or\n// \"300\", which are big-endian, li" +
- "ttle-endian or text. For binary formats, the\n// token length discriminates e.g. u16 little-endian vs u32 little-endian.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN 0x00200\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400\n\n" +
+ "// --------\n\n// For a source string of \"123\" or \"0x9A\", it is valid for a tokenizer to\n// return any combination of:\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.\n//\n// For a source string of \"+123\" or \"-0x9A\", only the first two are valid.\n//\n// For a source string of \"123.\", only the first one is valid.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT 0x00001\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004\n\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080\n\n// The number 300 might be represented as \"\\x01\\x2C\", \"\\x2C\\x01\\x00\\x00\" or\n// \"300\", which are big-en" +
+ "dian, little-endian or text. For binary formats, the\n// token length (after adjusting for FORMAT_IGNORE_ETC) discriminates\n// e.g. u16 little-endian vs u32 little-endian.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN 0x00200\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400\n\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_IGNORE_FIRST_BYTE 0x01000\n\n" +
"" +
"// --------\n\n// wuffs_base__token__value returns the token's high 46 bits, sign-extended. A\n// negative value means an extended token, non-negative means a simple token.\nstatic inline int64_t //\nwuffs_base__token__value(const wuffs_base__token* t) {\n return ((int64_t)(t->repr)) >> WUFFS_BASE__TOKEN__VALUE__SHIFT;\n}\n\n// wuffs_base__token__value_extension returns a negative value if the token was\n// not an extended token.\nstatic inline int64_t //\nwuffs_base__token__value_extension(const wuffs_base__token* t) {\n return (~(int64_t)(t->repr)) >> WUFFS_BASE__TOKEN__VALUE_EXTENSION__SHIFT;\n}\n\n// wuffs_base__token__value_major returns a negative value if the token was not\n// a simple token.\nstatic inline int64_t //\nwuffs_base__token__value_major(const wuffs_base__token* t) {\n return ((int64_t)(t->repr)) >> WUFFS_BASE__TOKEN__VALUE_MAJOR__SHIFT;\n}\n\n// wuffs_base__token__value_base_category returns a negative value if the token\n// was not a simple token.\nstatic inline int64_t //\nwuffs_base__token__value_base_cat" +
"egory(const wuffs_base__token* t) {\n return ((int64_t)(t->repr)) >> WUFFS_BASE__TOKEN__VALUE_BASE_CATEGORY__SHIFT;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_minor(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) & 0x1FFFFFF;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_base_detail(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_BASE_DETAIL__SHIFT) & 0x1FFFFF;\n}\n\nstatic inline bool //\nwuffs_base__token__continued(const wuffs_base__token* t) {\n return t->repr & 0x10000;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__length(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__LENGTH__SHIFT) & 0xFFFF;\n}\n\n#ifdef __cplusplus\n\ninline int64_t //\nwuffs_base__token::value() const {\n return wuffs_base__token__value(this);\n}\n\ninline int64_t //\nwuffs_base__token::value_extension() const {\n return wuffs_base__token__value_extension(this);\n}\n\ninline int64_t //\nwuffs_base__token::value_major() const {\n retu" +
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index 764096a..e70125c 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -81,6 +81,7 @@
{t.IDU32, "3", "TOKEN__VBC__UNICODE_CODE_POINT"},
{t.IDU32, "4", "TOKEN__VBC__LITERAL"},
{t.IDU32, "5", "TOKEN__VBC__NUMBER"},
+ {t.IDU32, "6", "TOKEN__VBC__INLINE_INTEGER"},
// ----
@@ -139,6 +140,8 @@
{t.IDU32, "0x00200", "TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN"},
{t.IDU32, "0x00400", "TOKEN__VBD__NUMBER__FORMAT_TEXT"},
+ {t.IDU32, "0x01000", "TOKEN__VBD__NUMBER__FORMAT_IGNORE_FIRST_BYTE"},
+
// ----
{t.IDU32, "0xFFFD", "UNICODE__REPLACEMENT_CHARACTER"},
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 261e08c..26e6e0b 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -2133,6 +2133,7 @@
#define WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT 3
#define WUFFS_BASE__TOKEN__VBC__LITERAL 4
#define WUFFS_BASE__TOKEN__VBC__NUMBER 5
+#define WUFFS_BASE__TOKEN__VBC__INLINE_INTEGER 6
// --------
@@ -2207,7 +2208,7 @@
// --------
// For a source string of "123" or "0x9A", it is valid for a tokenizer to
-// return any one of:
+// return any combination of:
// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.
// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.
// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.
@@ -2226,11 +2227,14 @@
// The number 300 might be represented as "\x01\x2C", "\x2C\x01\x00\x00" or
// "300", which are big-endian, little-endian or text. For binary formats, the
-// token length discriminates e.g. u16 little-endian vs u32 little-endian.
+// token length (after adjusting for FORMAT_IGNORE_ETC) discriminates
+// e.g. u16 little-endian vs u32 little-endian.
#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100
#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN 0x00200
#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_IGNORE_FIRST_BYTE 0x01000
+
// --------
// wuffs_base__token__value returns the token's high 46 bits, sign-extended. A
@@ -5512,6 +5516,207 @@
// ---------------- Status Codes
+extern const char wuffs_cbor__error__bad_input[];
+
+// ---------------- Public Consts
+
+// ---------------- Struct Declarations
+
+typedef struct wuffs_cbor__decoder__struct wuffs_cbor__decoder;
+
+// ---------------- Public Initializer Prototypes
+
+// For any given "wuffs_foo__bar* self", "wuffs_foo__bar__initialize(self,
+// etc)" should be called before any other "wuffs_foo__bar__xxx(self, etc)".
+//
+// Pass sizeof(*self) and WUFFS_VERSION for sizeof_star_self and wuffs_version.
+// Pass 0 (or some combination of WUFFS_INITIALIZE__XXX) for options.
+
+wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT
+wuffs_cbor__decoder__initialize(
+ wuffs_cbor__decoder* self,
+ size_t sizeof_star_self,
+ uint64_t wuffs_version,
+ uint32_t options);
+
+size_t
+sizeof__wuffs_cbor__decoder();
+
+// ---------------- Allocs
+
+// These functions allocate and initialize Wuffs structs. They return NULL if
+// memory allocation fails. If they return non-NULL, there is no need to call
+// wuffs_foo__bar__initialize, but the caller is responsible for eventually
+// calling free on the returned pointer. That pointer is effectively a C++
+// std::unique_ptr<T, decltype(&free)>.
+
+wuffs_cbor__decoder*
+wuffs_cbor__decoder__alloc();
+
+static inline wuffs_base__token_decoder*
+wuffs_cbor__decoder__alloc_as__wuffs_base__token_decoder() {
+ return (wuffs_base__token_decoder*)(wuffs_cbor__decoder__alloc());
+}
+
+// ---------------- Upcasts
+
+static inline wuffs_base__token_decoder*
+wuffs_cbor__decoder__upcast_as__wuffs_base__token_decoder(
+ wuffs_cbor__decoder* p) {
+ return (wuffs_base__token_decoder*)p;
+}
+
+// ---------------- Public Function Prototypes
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_cbor__decoder__set_quirk_enabled(
+ wuffs_cbor__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64
+wuffs_cbor__decoder__workbuf_len(
+ const wuffs_cbor__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_cbor__decoder__decode_tokens(
+ wuffs_cbor__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf);
+
+// ---------------- Struct Definitions
+
+// These structs' fields, and the sizeof them, are private implementation
+// details that aren't guaranteed to be stable across Wuffs versions.
+//
+// See https://en.wikipedia.org/wiki/Opaque_pointer#C
+
+#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
+
+struct wuffs_cbor__decoder__struct {
+ // Do not access the private_impl's or private_data's fields directly. There
+ // is no API/ABI compatibility or safety guarantee if you do so. Instead, use
+ // the wuffs_foo__bar__baz functions.
+ //
+ // It is a struct, not a struct*, so that the outermost wuffs_foo__bar struct
+ // can be stack allocated when WUFFS_IMPLEMENTATION is defined.
+
+ struct {
+ uint32_t magic;
+ uint32_t active_coroutine;
+ wuffs_base__vtable vtable_for__wuffs_base__token_decoder;
+ wuffs_base__vtable null_vtable;
+
+ bool f_end_of_data;
+
+ uint32_t p_decode_tokens[1];
+ } private_impl;
+
+ struct {
+ struct {
+ uint32_t v_depth;
+ uint32_t v_token_length;
+ uint8_t v_c;
+ uint64_t scratch;
+ } s_decode_tokens[1];
+ } private_data;
+
+#ifdef __cplusplus
+#if (__cplusplus >= 201103L)
+ using unique_ptr = std::unique_ptr<wuffs_cbor__decoder, decltype(&free)>;
+
+ // On failure, the alloc_etc functions return nullptr. They don't throw.
+
+ static inline unique_ptr
+ alloc() {
+ return unique_ptr(wuffs_cbor__decoder__alloc(), &free);
+ }
+
+ static inline wuffs_base__token_decoder::unique_ptr
+ alloc_as__wuffs_base__token_decoder() {
+ return wuffs_base__token_decoder::unique_ptr(
+ wuffs_cbor__decoder__alloc_as__wuffs_base__token_decoder(), &free);
+ }
+#endif // (__cplusplus >= 201103L)
+
+#if (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)
+ // Disallow constructing or copying an object via standard C++ mechanisms,
+ // e.g. the "new" operator, as this struct is intentionally opaque. Its total
+ // size and field layout is not part of the public, stable, memory-safe API.
+ // Use malloc or memcpy and the sizeof__wuffs_foo__bar function instead, and
+ // call wuffs_foo__bar__baz methods (which all take a "this"-like pointer as
+ // their first argument) rather than tweaking bar.private_impl.qux fields.
+ //
+ // In C, we can just leave wuffs_foo__bar as an incomplete type (unless
+ // WUFFS_IMPLEMENTATION is #define'd). In C++, we define a complete type in
+ // order to provide convenience methods. These forward on "this", so that you
+ // can write "bar->baz(etc)" instead of "wuffs_foo__bar__baz(bar, etc)".
+ wuffs_cbor__decoder__struct() = delete;
+ wuffs_cbor__decoder__struct(const wuffs_cbor__decoder__struct&) = delete;
+ wuffs_cbor__decoder__struct& operator=(
+ const wuffs_cbor__decoder__struct&) = delete;
+
+ // As above, the size of the struct is not part of the public API, and unless
+ // WUFFS_IMPLEMENTATION is #define'd, this struct type T should be heap
+ // allocated, not stack allocated. Its size is not intended to be known at
+ // compile time, but it is unfortunately divulged as a side effect of
+ // defining C++ convenience methods. Use "sizeof__T()", calling the function,
+ // instead of "sizeof T", invoking the operator. To make the two values
+ // different, so that passing the latter will be rejected by the initialize
+ // function, we add an arbitrary amount of dead weight.
+ uint8_t dead_weight[123000000]; // 123 MB.
+#endif // (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)
+
+ inline wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT
+ initialize(
+ size_t sizeof_star_self,
+ uint64_t wuffs_version,
+ uint32_t options) {
+ return wuffs_cbor__decoder__initialize(
+ this, sizeof_star_self, wuffs_version, options);
+ }
+
+ inline wuffs_base__token_decoder*
+ upcast_as__wuffs_base__token_decoder() {
+ return (wuffs_base__token_decoder*)this;
+ }
+
+ inline wuffs_base__empty_struct
+ set_quirk_enabled(
+ uint32_t a_quirk,
+ bool a_enabled) {
+ return wuffs_cbor__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+ }
+
+ inline wuffs_base__range_ii_u64
+ workbuf_len() const {
+ return wuffs_cbor__decoder__workbuf_len(this);
+ }
+
+ inline wuffs_base__status
+ decode_tokens(
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf) {
+ return wuffs_cbor__decoder__decode_tokens(this, a_dst, a_src, a_workbuf);
+ }
+
+#endif // __cplusplus
+}; // struct wuffs_cbor__decoder__struct
+
+#endif // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------- Status Codes
+
// ---------------- Public Consts
// ---------------- Struct Declarations
@@ -16008,6 +16213,302 @@
#endif // !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__BMP)
+#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__CBOR)
+
+// ---------------- Status Codes Implementations
+
+const char wuffs_cbor__error__bad_input[] = "#cbor: bad input";
+const char wuffs_cbor__error__internal_error_inconsistent_i_o[] = "#cbor: internal error: inconsistent I/O";
+
+// ---------------- Private Consts
+
+// ---------------- Private Initializer Prototypes
+
+// ---------------- Private Function Prototypes
+
+// ---------------- VTables
+
+const wuffs_base__token_decoder__func_ptrs
+wuffs_cbor__decoder__func_ptrs_for__wuffs_base__token_decoder = {
+ (wuffs_base__status(*)(void*,
+ wuffs_base__token_buffer*,
+ wuffs_base__io_buffer*,
+ wuffs_base__slice_u8))(&wuffs_cbor__decoder__decode_tokens),
+ (wuffs_base__empty_struct(*)(void*,
+ uint32_t,
+ bool))(&wuffs_cbor__decoder__set_quirk_enabled),
+ (wuffs_base__range_ii_u64(*)(const void*))(&wuffs_cbor__decoder__workbuf_len),
+};
+
+// ---------------- Initializer Implementations
+
+wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT
+wuffs_cbor__decoder__initialize(
+ wuffs_cbor__decoder* self,
+ size_t sizeof_star_self,
+ uint64_t wuffs_version,
+ uint32_t options){
+ if (!self) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ }
+ if (sizeof(*self) != sizeof_star_self) {
+ return wuffs_base__make_status(wuffs_base__error__bad_sizeof_receiver);
+ }
+ if (((wuffs_version >> 32) != WUFFS_VERSION_MAJOR) ||
+ (((wuffs_version >> 16) & 0xFFFF) > WUFFS_VERSION_MINOR)) {
+ return wuffs_base__make_status(wuffs_base__error__bad_wuffs_version);
+ }
+
+ if ((options & WUFFS_INITIALIZE__ALREADY_ZEROED) != 0) {
+ // The whole point of this if-check is to detect an uninitialized *self.
+ // We disable the warning on GCC. Clang-5.0 does not have this warning.
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+ if (self->private_impl.magic != 0) {
+ return wuffs_base__make_status(wuffs_base__error__initialize_falsely_claimed_already_zeroed);
+ }
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+ } else {
+ if ((options & WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED) == 0) {
+ memset(self, 0, sizeof(*self));
+ options |= WUFFS_INITIALIZE__ALREADY_ZEROED;
+ } else {
+ memset(&(self->private_impl), 0, sizeof(self->private_impl));
+ }
+ }
+
+ self->private_impl.magic = WUFFS_BASE__MAGIC;
+ self->private_impl.vtable_for__wuffs_base__token_decoder.vtable_name =
+ wuffs_base__token_decoder__vtable_name;
+ self->private_impl.vtable_for__wuffs_base__token_decoder.function_pointers =
+ (const void*)(&wuffs_cbor__decoder__func_ptrs_for__wuffs_base__token_decoder);
+ return wuffs_base__make_status(NULL);
+}
+
+wuffs_cbor__decoder*
+wuffs_cbor__decoder__alloc() {
+ wuffs_cbor__decoder* x =
+ (wuffs_cbor__decoder*)(calloc(sizeof(wuffs_cbor__decoder), 1));
+ if (!x) {
+ return NULL;
+ }
+ if (wuffs_cbor__decoder__initialize(
+ x, sizeof(wuffs_cbor__decoder), WUFFS_VERSION, WUFFS_INITIALIZE__ALREADY_ZEROED).repr) {
+ free(x);
+ return NULL;
+ }
+ return x;
+}
+
+size_t
+sizeof__wuffs_cbor__decoder() {
+ return sizeof(wuffs_cbor__decoder);
+}
+
+// ---------------- Function Implementations
+
+// -------- func cbor.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_cbor__decoder__set_quirk_enabled(
+ wuffs_cbor__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled) {
+ return wuffs_base__make_empty_struct();
+}
+
+// -------- func cbor.decoder.workbuf_len
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64
+wuffs_cbor__decoder__workbuf_len(
+ const wuffs_cbor__decoder* self) {
+ if (!self) {
+ return wuffs_base__utility__empty_range_ii_u64();
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return wuffs_base__utility__empty_range_ii_u64();
+ }
+
+ return wuffs_base__utility__empty_range_ii_u64();
+}
+
+// -------- func cbor.decoder.decode_tokens
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_cbor__decoder__decode_tokens(
+ wuffs_cbor__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf) {
+ if (!self) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_status(
+ (self->private_impl.magic == WUFFS_BASE__DISABLED)
+ ? wuffs_base__error__disabled_by_previous_error
+ : wuffs_base__error__initialize_not_called);
+ }
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ if ((self->private_impl.active_coroutine != 0) &&
+ (self->private_impl.active_coroutine != 1)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__make_status(wuffs_base__error__interleaved_coroutine_calls);
+ }
+ self->private_impl.active_coroutine = 0;
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint32_t v_depth = 0;
+ uint32_t v_token_length = 0;
+ uint8_t v_c = 0;
+
+ wuffs_base__token* iop_a_dst = NULL;
+ wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
+ }
+ }
+ const uint8_t* iop_a_src = NULL;
+ const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_tokens[0];
+ if (coro_susp_point) {
+ v_depth = self->private_data.s_decode_tokens[0].v_depth;
+ v_token_length = self->private_data.s_decode_tokens[0].v_token_length;
+ v_c = self->private_data.s_decode_tokens[0].v_c;
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_end_of_data) {
+ status = wuffs_base__make_status(wuffs_base__note__end_of_data);
+ goto ok;
+ }
+ label__outer__continue:;
+ while (true) {
+ while (true) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ goto label__outer__continue;
+ }
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_cbor__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ goto label__outer__continue;
+ }
+ v_c = wuffs_base__load_u8be__no_bounds_check(iop_a_src);
+ if ((24 <= (v_c & 31)) && ((v_c & 31) <= 27)) {
+ v_token_length = (1 + (((uint32_t)(1)) << (v_c & 3)));
+ if (((uint64_t)(io2_a_src - iop_a_src)) < ((uint64_t)(v_token_length))) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_cbor__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+ goto label__outer__continue;
+ }
+ self->private_data.s_decode_tokens[0].scratch = v_token_length;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ if (self->private_data.s_decode_tokens[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_tokens[0].scratch -= ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_decode_tokens[0].scratch;
+ } else {
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ }
+ if (v_c < 32) {
+ v_c &= 31;
+ if (v_c < 24) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((12582912 | ((uint32_t)(v_c))))) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__goto_parsed_a_leaf_value__break;
+ } else if (v_c < 28) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10490116)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)((1 + (((uint32_t)(1)) << (v_c - 24))))) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__goto_parsed_a_leaf_value__break;
+ }
+ }
+ if (iop_a_src > io1_a_src) {
+ (iop_a_src--, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(wuffs_cbor__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_cbor__error__internal_error_inconsistent_i_o);
+ goto exit;
+ }
+ label__goto_parsed_a_leaf_value__break:;
+ if (v_depth == 0) {
+ goto label__outer__break;
+ }
+ }
+ label__outer__break:;
+ self->private_impl.f_end_of_data = true;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_tokens[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_tokens[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 1 : 0;
+ self->private_data.s_decode_tokens[0].v_depth = v_depth;
+ self->private_data.s_decode_tokens[0].v_token_length = v_token_length;
+ self->private_data.s_decode_tokens[0].v_c = v_c;
+
+ goto exit;
+ exit:
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ if (wuffs_base__status__is_error(&status)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ }
+ return status;
+}
+
+#endif // !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__CBOR)
+
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__CRC32)
// ---------------- Status Codes Implementations
diff --git a/script/print-json-token-debug-format.c b/script/print-json-token-debug-format.c
index a2a5277..7c306e8 100644
--- a/script/print-json-token-debug-format.c
+++ b/script/print-json-token-debug-format.c
@@ -82,6 +82,7 @@
// code simply isn't compiled.
#define WUFFS_CONFIG__MODULES
#define WUFFS_CONFIG__MODULE__BASE
+#define WUFFS_CONFIG__MODULE__CBOR
#define WUFFS_CONFIG__MODULE__JSON
// If building this program in an environment that doesn't easily accommodate
@@ -91,8 +92,14 @@
// Wuffs allows either statically or dynamically allocated work buffers. This
// program exercises static allocation.
+#if WUFFS_CBOR__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE > \
+ WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+#define WORK_BUFFER_ARRAY_SIZE \
+ WUFFS_CBOR__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+#else
#define WORK_BUFFER_ARRAY_SIZE \
WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+#endif
#if WORK_BUFFER_ARRAY_SIZE > 0
uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
#else
@@ -113,7 +120,9 @@
wuffs_base__io_buffer g_src;
wuffs_base__token_buffer g_tok;
-wuffs_json__decoder g_dec;
+wuffs_cbor__decoder g_cbor_decoder;
+wuffs_json__decoder g_json_decoder;
+wuffs_base__token_decoder* g_dec;
wuffs_base__status g_dec_status;
#define TRY(error_msg) \
@@ -149,12 +158,18 @@
// ----
+typedef enum file_format_enum {
+ FILE_FORMAT_JSON,
+ FILE_FORMAT_CBOR,
+} file_format;
+
struct {
int remaining_argc;
char** remaining_argv;
bool all_tokens;
bool human_readable;
+ file_format input_format;
bool quirks;
} g_flags = {0};
@@ -188,6 +203,14 @@
g_flags.human_readable = true;
continue;
}
+ if (!strcmp(arg, "i=cbor") || !strcmp(arg, "input-format=cbor")) {
+ g_flags.input_format = FILE_FORMAT_CBOR;
+ continue;
+ }
+ if (!strcmp(arg, "i=json") || !strcmp(arg, "input-format=json")) {
+ g_flags.input_format = FILE_FORMAT_JSON;
+ continue;
+ }
if (!strcmp(arg, "q") || !strcmp(arg, "quirks")) {
g_flags.quirks = true;
continue;
@@ -208,7 +231,7 @@
"3:UnicodeCodePoint", //
"4:Literal.........", //
"5:Number..........", //
- "6:Reserved........", //
+ "6:Inline_Integer..", //
"7:Reserved........", //
"8:Reserved........", //
"9:Reserved........", //
@@ -241,10 +264,22 @@
wuffs_base__make_slice_token(g_tok_buffer_array, TOKEN_BUFFER_ARRAY_SIZE),
wuffs_base__empty_token_buffer_meta());
- wuffs_base__status init_status = wuffs_json__decoder__initialize(
- &g_dec, sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0);
- if (!wuffs_base__status__is_ok(&init_status)) {
- return wuffs_base__status__message(&init_status);
+ if (g_flags.input_format == FILE_FORMAT_JSON) {
+ wuffs_base__status init_status = wuffs_json__decoder__initialize(
+ &g_json_decoder, sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0);
+ if (!wuffs_base__status__is_ok(&init_status)) {
+ return wuffs_base__status__message(&init_status);
+ }
+ g_dec = wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(
+ &g_json_decoder);
+ } else {
+ wuffs_base__status init_status = wuffs_cbor__decoder__initialize(
+ &g_cbor_decoder, sizeof__wuffs_cbor__decoder(), WUFFS_VERSION, 0);
+ if (!wuffs_base__status__is_ok(&init_status)) {
+ return wuffs_base__status__message(&init_status);
+ }
+ g_dec = wuffs_cbor__decoder__upcast_as__wuffs_base__token_decoder(
+ &g_cbor_decoder);
}
if (g_flags.quirks) {
@@ -269,14 +304,14 @@
};
uint32_t i;
for (i = 0; quirks[i]; i++) {
- wuffs_json__decoder__set_quirk_enabled(&g_dec, quirks[i], true);
+ wuffs_base__token_decoder__set_quirk_enabled(g_dec, quirks[i], true);
}
}
uint64_t pos = 0;
while (true) {
- wuffs_base__status status = wuffs_json__decoder__decode_tokens(
- &g_dec, &g_tok, &g_src,
+ wuffs_base__status status = wuffs_base__token_decoder__decode_tokens(
+ g_dec, &g_tok, &g_src,
wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
while (g_tok.meta.ri < g_tok.meta.wi) {
diff --git a/std/cbor/decode_cbor.wuffs b/std/cbor/decode_cbor.wuffs
new file mode 100644
index 0000000..7ec6084
--- /dev/null
+++ b/std/cbor/decode_cbor.wuffs
@@ -0,0 +1,108 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+pub status "#bad input"
+
+pri status "#internal error: inconsistent I/O"
+
+pub struct decoder? implements base.token_decoder(
+ end_of_data : base.bool,
+
+ util : base.utility,
+)(
+)
+
+pub func decoder.set_quirk_enabled!(quirk: base.u32, enabled: base.bool) {
+}
+
+pub func decoder.workbuf_len() base.range_ii_u64 {
+ return this.util.empty_range_ii_u64()
+}
+
+pub func decoder.decode_tokens?(dst: base.token_writer, src: base.io_reader, workbuf: slice base.u8) {
+ var depth : base.u32[..= 1024]
+ var token_length : base.u32[..= 9]
+ var c : base.u8
+
+ if this.end_of_data {
+ return base."@end of data"
+ }
+
+ while.outer true {
+ while.goto_parsed_a_leaf_value true {{
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ continue.outer
+ }
+ if args.src.available() <= 0 {
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ continue.outer
+ }
+ c = args.src.peek_u8()
+ if (0x18 <= (c & 0x1F)) and ((c & 0x1F) <= 0x1B) {
+ token_length = 1 + ((1 as base.u32) << (c & 0x03))
+ if args.src.available() < (token_length as base.u64) {
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ continue.outer
+ }
+ args.src.skip_u32?(n: token_length)
+ } else {
+ args.src.skip_u32_fast!(actual: 1, worst_case: 1)
+ }
+
+ if c < 0x20 {
+ c &= 0x1F
+ if c < 0x18 {
+ args.dst.write_simple_token_fast!(
+ value_major: 0,
+ value_minor: (base.TOKEN__VBC__INLINE_INTEGER << 21) |
+ (c as base.u32),
+ continued: 0,
+ length: 1)
+ break.goto_parsed_a_leaf_value
+ } else if c < 0x1C {
+ args.dst.write_simple_token_fast!(
+ value_major: 0,
+ value_minor: (base.TOKEN__VBC__NUMBER << 21) |
+ base.TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED |
+ base.TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN |
+ base.TOKEN__VBD__NUMBER__FORMAT_IGNORE_FIRST_BYTE,
+ continued: 0,
+ length: 1 + ((1 as base.u32) << (c - 0x18)))
+ break.goto_parsed_a_leaf_value
+ }
+ }
+
+ if args.src.can_undo_byte() {
+ args.src.undo_byte!()
+ return "#bad input"
+ }
+ return "#internal error: inconsistent I/O"
+ }} endwhile.goto_parsed_a_leaf_value
+
+ // We've just parsed a leaf (non-container) value: literal (null,
+ // false, true), number or string.
+ if depth == 0 {
+ break.outer
+ }
+ } endwhile.outer
+
+ this.end_of_data = true
+}
diff --git a/test/c/std/cbor.c b/test/c/std/cbor.c
new file mode 100644
index 0000000..e903a63
--- /dev/null
+++ b/test/c/std/cbor.c
@@ -0,0 +1,133 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ----------------
+
+/*
+This test program is typically run indirectly, by the "wuffs test" or "wuffs
+bench" commands. These commands take an optional "-mimic" flag to check that
+Wuffs' output mimics (i.e. exactly matches) other libraries' output, such as
+giflib for GIF, libpng for PNG, etc.
+
+To manually run this test:
+
+for CC in clang gcc; do
+ $CC -std=c99 -Wall -Werror cbor.c && ./a.out
+ rm -f a.out
+done
+
+Each edition should print "PASS", amongst other information, and exit(0).
+
+Add the "wuffs mimic cflags" (everything after the colon below) to the C
+compiler flags (after the .c file) to run the mimic tests.
+
+To manually run the benchmarks, replace "-Wall -Werror" with "-O3" and replace
+the first "./a.out" with "./a.out -bench". Combine these changes with the
+"wuffs mimic cflags" to run the mimic benchmarks.
+*/
+
+// !! wuffs mimic cflags: -DWUFFS_MIMIC
+
+// Wuffs ships as a "single file C library" or "header file library" as per
+// https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
+//
+// To use that single file as a "foo.c"-like implementation, instead of a
+// "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or
+// compiling it.
+#define WUFFS_IMPLEMENTATION
+
+// Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of
+// release/c/etc.c whitelist which parts of Wuffs to build. That file contains
+// the entire Wuffs standard library, implementing a variety of codecs and file
+// formats. Without this macro definition, an optimizing compiler or linker may
+// very well discard Wuffs code for unused codecs, but listing the Wuffs
+// modules we use makes that process explicit. Preprocessing means that such
+// code simply isn't compiled.
+#define WUFFS_CONFIG__MODULES
+#define WUFFS_CONFIG__MODULE__BASE
+#define WUFFS_CONFIG__MODULE__CBOR
+
+// If building this program in an environment that doesn't easily accommodate
+// relative includes, you can use the script/inline-c-relative-includes.go
+// program to generate a stand-alone C file.
+#include "../../../release/c/wuffs-unsupported-snapshot.c"
+#include "../testlib/testlib.c"
+#ifdef WUFFS_MIMIC
+// No mimic library.
+#endif
+
+// ---------------- CBOR Tests
+
+const char* //
+test_wuffs_cbor_decode_interface() {
+ CHECK_FOCUS(__func__);
+
+ // TODO.
+
+ return NULL;
+}
+
+// ---------------- Mimic Tests
+
+#ifdef WUFFS_MIMIC
+
+// No mimic tests.
+
+#endif // WUFFS_MIMIC
+
+// ---------------- CBOR Benches
+
+// No CBOR benches.
+
+// ---------------- Mimic Benches
+
+#ifdef WUFFS_MIMIC
+
+// No mimic benches.
+
+#endif // WUFFS_MIMIC
+
+// ---------------- Manifest
+
+proc g_tests[] = {
+
+ test_wuffs_cbor_decode_interface,
+
+#ifdef WUFFS_MIMIC
+
+// No mimic tests.
+
+#endif // WUFFS_MIMIC
+
+ NULL,
+};
+
+proc g_benches[] = {
+
+// No CBOR benches.
+
+#ifdef WUFFS_MIMIC
+
+// No mimic benches.
+
+#endif // WUFFS_MIMIC
+
+ NULL,
+};
+
+int //
+main(int argc, char** argv) {
+ g_proc_package_name = "std/cbor";
+ return test_main(argc, argv, g_tests, g_benches);
+}