Have std/cbor parse arrays
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4cc25ce..abb6422 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -5542,6 +5542,7 @@
// ---------------- Status Codes
extern const char wuffs_cbor__error__bad_input[];
+extern const char wuffs_cbor__error__unsupported_recursion_depth[];
// ---------------- Public Consts
@@ -5642,11 +5643,15 @@
wuffs_base__vtable null_vtable;
bool f_end_of_data;
+ uint8_t f_container_close_token_length;
uint32_t p_decode_tokens[1];
} private_impl;
struct {
+ uint32_t f_stack[64];
+ uint64_t f_container_num_remaining[1024];
+
struct {
uint64_t v_string_length;
uint32_t v_depth;
@@ -16254,6 +16259,7 @@
// ---------------- Status Codes Implementations
const char wuffs_cbor__error__bad_input[] = "#cbor: bad input";
+const char wuffs_cbor__error__unsupported_recursion_depth[] = "#cbor: unsupported recursion depth";
const char wuffs_cbor__error__internal_error_inconsistent_i_o[] = "#cbor: internal error: inconsistent I/O";
const char wuffs_cbor__error__internal_error_inconsistent_token_length[] = "#cbor: internal error: inconsistent token length";
@@ -16264,7 +16270,7 @@
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 2, 3, 5, 9, 1, 1, 1, 1,
+ 2, 3, 5, 9, 0, 0, 0, 1,
};
// ---------------- Private Initializer Prototypes
@@ -16414,8 +16420,11 @@
uint64_t v_string_length = 0;
uint64_t v_n64 = 0;
uint32_t v_depth = 0;
+ uint32_t v_stack_byte = 0;
+ uint32_t v_stack_bit = 0;
uint32_t v_token_length = 0;
- uint32_t v_value_minor = 0;
+ uint32_t v_vminor = 0;
+ uint32_t v_vminor_alt = 0;
uint32_t v_continued = 0;
uint8_t v_c = 0;
uint8_t v_c_major = 0;
@@ -16484,14 +16493,14 @@
status = wuffs_base__make_status(wuffs_cbor__error__bad_input);
goto exit;
}
- v_value_minor = 4194560;
+ v_vminor = 4194560;
if (v_indefinite_string_major_type == 3) {
- v_value_minor |= 19;
+ v_vminor |= 19;
}
v_indefinite_string_major_type = 0;
(iop_a_src += 1, wuffs_base__make_empty_struct());
*iop_a_dst++ = wuffs_base__make_token(
- (((uint64_t)(v_value_minor)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(v_vminor)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
goto label__goto_parsed_a_leaf_value__break;
}
@@ -16716,6 +16725,53 @@
}
goto label__goto_parsed_a_leaf_value__break;
}
+ } else if (v_c_major == 4) {
+ if (WUFFS_CBOR__TOKEN_LENGTHS[v_c_minor] == 0) {
+ goto label__goto_fail__break;
+ } else if (v_depth >= 1024) {
+ status = wuffs_base__make_status(wuffs_cbor__error__unsupported_recursion_depth);
+ goto exit;
+ }
+ v_vminor = 2105361;
+ v_vminor_alt = 2101282;
+ if (v_depth > 0) {
+ v_stack_byte = ((v_depth - 1) / 16);
+ v_stack_bit = (((v_depth - 1) & 15) * 2);
+ if (0 == (self->private_data.f_stack[v_stack_byte] & (((uint32_t)(1)) << v_stack_bit))) {
+ v_vminor = 2105377;
+ v_vminor_alt = 2105378;
+ } else {
+ v_vminor = 2105409;
+ v_vminor_alt = 2113570;
+ }
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(v_vminor)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(((uint32_t)(WUFFS_CBOR__TOKEN_LENGTHS[v_c_minor])))) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ if (v_c_minor == 0) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(v_vminor_alt)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(0)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__goto_parsed_a_leaf_value__break;
+ }
+ v_stack_byte = (v_depth / 16);
+ v_stack_bit = ((v_depth & 15) * 2);
+ self->private_data.f_stack[v_stack_byte] &= (4294967295 ^ (((uint32_t)(3)) << v_stack_bit));
+ self->private_data.f_container_num_remaining[v_depth] = v_string_length;
+ v_depth += 1;
+ goto label__outer__continue;
+ } else if (v_c_major == 7) {
+ if (v_c_minor == 31) {
+ if (v_depth <= 0) {
+ goto label__goto_fail__break;
+ }
+ if (self->private_data.f_container_num_remaining[(v_depth - 1)] != 0) {
+ goto label__goto_fail__break;
+ }
+ self->private_data.f_container_num_remaining[(v_depth - 1)] = 1;
+ self->private_impl.f_container_close_token_length = 1;
+ goto label__goto_parsed_a_leaf_value__break;
+ }
}
goto label__goto_fail__break;
}
@@ -16729,9 +16785,46 @@
goto exit;
}
label__goto_parsed_a_leaf_value__break:;
- if (v_depth == 0) {
- goto label__outer__break;
+ while (v_depth > 0) {
+ if (self->private_data.f_container_num_remaining[(v_depth - 1)] <= 0) {
+ goto label__outer__continue;
+ }
+ self->private_data.f_container_num_remaining[(v_depth - 1)] -= 1;
+ if (self->private_data.f_container_num_remaining[(v_depth - 1)] > 0) {
+ goto label__outer__continue;
+ }
+ label__2__continue:;
+ while (((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(8);
+ goto label__2__continue;
+ }
+ v_vminor_alt = 2097154;
+ v_stack_byte = ((v_depth - 1) / 16);
+ v_stack_bit = (((v_depth - 1) & 15) * 2);
+ if (0 == (self->private_data.f_stack[v_stack_byte] & (((uint32_t)(1)) << v_stack_bit))) {
+ v_vminor_alt |= 32;
+ } else {
+ v_vminor_alt |= 64;
+ }
+ v_depth -= 1;
+ if (v_depth > 0) {
+ v_stack_byte = ((v_depth - 1) / 16);
+ v_stack_bit = (((v_depth - 1) & 15) * 2);
+ if (0 == (self->private_data.f_stack[v_stack_byte] & (((uint32_t)(1)) << v_stack_bit))) {
+ v_vminor_alt |= 8192;
+ } else {
+ v_vminor_alt |= 16384;
+ }
+ } else {
+ v_vminor_alt |= 4096;
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(v_vminor_alt)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(((uint32_t)(self->private_impl.f_container_close_token_length)))) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ self->private_impl.f_container_close_token_length = 0;
}
+ goto label__outer__break;
}
label__outer__break:;
self->private_impl.f_end_of_data = true;
diff --git a/std/cbor/decode_cbor.wuffs b/std/cbor/decode_cbor.wuffs
index a839644..d503f96 100644
--- a/std/cbor/decode_cbor.wuffs
+++ b/std/cbor/decode_cbor.wuffs
@@ -13,6 +13,7 @@
// limitations under the License.
pub status "#bad input"
+pub status "#unsupported recursion depth"
pri status "#internal error: inconsistent I/O"
pri status "#internal error: inconsistent token length"
@@ -46,14 +47,32 @@
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 2, 3, 5, 9, 1, 1, 1, 1,
+ 2, 3, 5, 9, 0, 0, 0, 1,
]
pub struct decoder? implements base.token_decoder(
end_of_data : base.bool,
+ container_close_token_length : base.u8[..= 1],
+
util : base.utility,
)(
+ // stack is conceptually an array of 2-bit integers, implemented as an
+ // array of u32. The N'th 2-bit pair is whether we're in an array or
+ // object, where N is the recursion depth:
+ // - 0b00 In an array.
+ // - 0b01 In an object, expecting a value.
+ // - 0b10 In an array.
+ // - 0b11 In an object, expecting a key.
+ //
+ // The maximum recursion depth, 1024, is the same as for std/json.
+ stack : array[1024 / 16] base.u32,
+
+ // container_num_remaining[i] is the number of elements remaining in the
+ // open containers, for i ranging in 0 .. depth. If (i < depth) and
+ // (container_num_remaining[i] == 0) then the i'th open container has
+ // indefinite length.
+ container_num_remaining : array[1024] base.u64,
)
pub func decoder.set_quirk_enabled!(quirk: base.u32, enabled: base.bool) {
@@ -68,8 +87,11 @@
var n64 : base.u64
var depth : base.u32[..= 1024]
+ var stack_byte : base.u32[..= (1024 / 16) - 1]
+ var stack_bit : base.u32[..= 30]
var token_length : base.u32[..= 0xFFFF]
- var value_minor : base.u32[..= 0x1FF_FFFF]
+ var vminor : base.u32[..= 0x1FF_FFFF]
+ var vminor_alt : base.u32[..= 0x1FF_FFFF]
var continued : base.u32[..= 1]
var c : base.u8
var c_major : base.u8[..= 0x07]
@@ -103,10 +125,10 @@
if c <> 0xFF {
return "#bad input"
}
- value_minor = (base.TOKEN__VBC__STRING << 21) |
+ vminor = (base.TOKEN__VBC__STRING << 21) |
base.TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP
if indefinite_string_major_type == 3 {
- value_minor |= base.TOKEN__VBD__STRING__DEFINITELY_UTF_8 |
+ vminor |= base.TOKEN__VBD__STRING__DEFINITELY_UTF_8 |
base.TOKEN__VBD__STRING__CHAIN_MUST_BE_UTF_8 |
base.TOKEN__VBD__STRING__DEFINITELY_ASCII
}
@@ -114,7 +136,7 @@
args.src.skip_u32_fast!(actual: 1, worst_case: 1)
args.dst.write_simple_token_fast!(
value_major: 0,
- value_minor: value_minor,
+ value_minor: vminor,
continued: 0,
length: 1)
break.goto_parsed_a_leaf_value
@@ -387,6 +409,88 @@
break.goto_parsed_a_leaf_value
} endwhile
// -------- END Major type 3: a text string.
+
+ } else if c_major == 4 {
+ // -------- BEGIN Major type 4: an array of data items.
+ if TOKEN_LENGTHS[c_minor] == 0 {
+ break.goto_fail
+ } else if depth >= 1024 {
+ return "#unsupported recursion depth"
+ }
+
+ vminor = (base.TOKEN__VBC__STRUCTURE << 21) |
+ base.TOKEN__VBD__STRUCTURE__PUSH |
+ base.TOKEN__VBD__STRUCTURE__FROM_NONE |
+ base.TOKEN__VBD__STRUCTURE__TO_LIST
+ vminor_alt = (base.TOKEN__VBC__STRUCTURE << 21) |
+ base.TOKEN__VBD__STRUCTURE__POP |
+ base.TOKEN__VBD__STRUCTURE__FROM_LIST |
+ base.TOKEN__VBD__STRUCTURE__TO_NONE
+ if depth > 0 {
+ stack_byte = (depth - 1) / 16
+ stack_bit = ((depth - 1) & 15) * 2
+ if 0 == (this.stack[stack_byte] & ((1 as base.u32) << stack_bit)) {
+ vminor = (base.TOKEN__VBC__STRUCTURE << 21) |
+ base.TOKEN__VBD__STRUCTURE__PUSH |
+ base.TOKEN__VBD__STRUCTURE__FROM_LIST |
+ base.TOKEN__VBD__STRUCTURE__TO_LIST
+ vminor_alt = (base.TOKEN__VBC__STRUCTURE << 21) |
+ base.TOKEN__VBD__STRUCTURE__POP |
+ base.TOKEN__VBD__STRUCTURE__FROM_LIST |
+ base.TOKEN__VBD__STRUCTURE__TO_LIST
+ } else {
+ vminor = (base.TOKEN__VBC__STRUCTURE << 21) |
+ base.TOKEN__VBD__STRUCTURE__PUSH |
+ base.TOKEN__VBD__STRUCTURE__FROM_DICT |
+ base.TOKEN__VBD__STRUCTURE__TO_LIST
+ vminor_alt = (base.TOKEN__VBC__STRUCTURE << 21) |
+ base.TOKEN__VBD__STRUCTURE__POP |
+ base.TOKEN__VBD__STRUCTURE__FROM_LIST |
+ base.TOKEN__VBD__STRUCTURE__TO_DICT
+ }
+ }
+ args.dst.write_simple_token_fast!(
+ value_major: 0,
+ value_minor: vminor,
+ continued: 0,
+ length: TOKEN_LENGTHS[c_minor] as base.u32)
+ if c_minor == 0x00 {
+ args.dst.write_simple_token_fast!(
+ value_major: 0,
+ value_minor: vminor_alt,
+ continued: 0,
+ length: 0)
+ break.goto_parsed_a_leaf_value
+ }
+
+ stack_byte = depth / 16
+ stack_bit = (depth & 15) * 2
+ this.stack[stack_byte] &= 0xFFFF_FFFF ^ ((3 as base.u32) << stack_bit)
+ this.container_num_remaining[depth] = string_length
+ depth += 1
+ continue.outer
+ // -------- END Major type 4: an array of data items.
+
+ } else if c_major == 7 {
+ // -------- BEGIN Major type 7: miscellaneous.
+ if c_minor == 0x1F {
+ // Indefinite-length strings were dealt with separately, above.
+ // Here, we expect to be in an indefinite-length container.
+ if depth <= 0 {
+ break.goto_fail
+ }
+ if this.container_num_remaining[depth - 1] <> 0 {
+ break.goto_fail
+ }
+ // Pretend that the indefinite-length container is effectively
+ // a definite-length container with one element remaining.
+ // Having parsed that final phantom element, we'll process the
+ // explicit CBOR stop code like an implicit end-of-container.
+ this.container_num_remaining[depth - 1] = 1
+ this.container_close_token_length = 1
+ break.goto_parsed_a_leaf_value
+ }
+ // -------- END Major type 7: miscellaneous.
}
break.goto_fail
}} endwhile.goto_fail
@@ -398,11 +502,60 @@
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
- }
+ // We've just parsed a leaf (non-container) value, or the (explicit or
+ // implicit) close of a container (array or object).
+ while depth > 0 {
+ if this.container_num_remaining[depth - 1] <= 0 {
+ // We're in an indefinite-length container.
+ continue.outer
+ }
+ this.container_num_remaining[depth - 1] -= 1
+ if this.container_num_remaining[depth - 1] > 0 {
+ // We're in a definite-length, non-empty container and have not
+ // seen its final value.
+ continue.outer
+ }
+
+ while args.dst.available() <= 0,
+ inv depth > 0,
+ post args.dst.available() > 0,
+ {
+ yield? base."$short write"
+ continue
+ } endwhile
+
+ vminor_alt = (base.TOKEN__VBC__STRUCTURE << 21) | base.TOKEN__VBD__STRUCTURE__POP
+
+ stack_byte = (depth - 1) / 16
+ stack_bit = ((depth - 1) & 15) * 2
+ if 0 == (this.stack[stack_byte] & ((1 as base.u32) << stack_bit)) {
+ vminor_alt |= base.TOKEN__VBD__STRUCTURE__FROM_LIST
+ } else {
+ vminor_alt |= base.TOKEN__VBD__STRUCTURE__FROM_DICT
+ }
+
+ depth -= 1
+ if depth > 0 {
+ stack_byte = (depth - 1) / 16
+ stack_bit = ((depth - 1) & 15) * 2
+ if 0 == (this.stack[stack_byte] & ((1 as base.u32) << stack_bit)) {
+ vminor_alt |= base.TOKEN__VBD__STRUCTURE__TO_LIST
+ } else {
+ vminor_alt |= base.TOKEN__VBD__STRUCTURE__TO_DICT
+ }
+ } else {
+ vminor_alt |= base.TOKEN__VBD__STRUCTURE__TO_NONE
+ }
+ args.dst.write_simple_token_fast!(
+ value_major: 0,
+ value_minor: vminor_alt,
+ continued: 0,
+ length: this.container_close_token_length as base.u32)
+ this.container_close_token_length = 0
+ } endwhile
+
+ // We've parsed the top-level value and we're therefore done overall.
+ break.outer
} endwhile.outer
this.end_of_data = true