| // 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" |
| |
| // TOKEN_VALUE_MAJOR is the base-38 encoding of "cbor". |
| pub const TOKEN_VALUE_MAJOR : base.u32 = 0x0C_061D |
| |
| // TOKEN_VALUE_MINOR__TAG means that the remaining 24 bits of the token's |
| // value_minor is a CBOR tag. That token may be continued, in which case the |
| // following token is an extended token (46 bits) and the overall 64-bit CBOR |
| // tag is ((first << 46) | ext). |
| pub const TOKEN_VALUE_MINOR__TAG : base.u32 = 0x01 |
| |
| // TOKEN_VALUE_MINOR__MINUS_1_MINUS_X means that the token's final |
| // (token.length - 1) bytes (which must be one of 1, 2, 4 or 8 bytes) contains |
| // a big-endian unsigned integer x. The token's overall value is the negative |
| // number (-1 - x). Note that this value can underflow an int64_t, and its |
| // absolute value (+1 + x) can overflow a uint64_t. |
| pub const TOKEN_VALUE_MINOR__MINUS_1_MINUS_X : base.u32 = 0x02 |
| |
| 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) { |
| args.src.skip_u32_fast!(actual: token_length, worst_case: token_length) |
| } else if args.src.is_closed() { |
| return "#bad input" |
| } else { |
| yield? base."$short read" |
| c = 0 |
| continue.outer |
| } |
| } else { |
| args.src.skip_u32_fast!(actual: 1, worst_case: 1) |
| } |
| |
| if c < 0x20 { // Major type 0: an unsigned integer. |
| 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 |
| } |
| |
| } else if c < 0x40 { // Major type 1: a negative integer. |
| c &= 0x1F |
| if c < 0x18 { |
| args.dst.write_simple_token_fast!( |
| value_major: 0, |
| value_minor: (base.TOKEN__VBC__INLINE_INTEGER << 21) | |
| (0x1F_FFFF - (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: TOKEN_VALUE_MAJOR, |
| value_minor: TOKEN_VALUE_MINOR__MINUS_1_MINUS_X, |
| 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 |
| } |