diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2022-04-16 18:14:01 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2022-04-16 18:14:01 +0200 |
| commit | 6d0ba8d1898adabceafc6a181395f5d158176a04 (patch) | |
| tree | 0b6e7db592e98f46d87b421974eface1f1e195a9 | |
| parent | b6f3fa6ee1a57058ea189be155839d7c6ab4fd23 (diff) | |
[LEB128] Add byte-at-a-time ILEB decoder.
| -rw-r--r-- | core/encoding/varint/leb128.odin | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin index 4cad1da76..f8fcc7de5 100644 --- a/core/encoding/varint/leb128.odin +++ b/core/encoding/varint/leb128.odin @@ -66,32 +66,46 @@ decode_uleb128 :: proc {decode_uleb128_buffer, decode_uleb128_byte} // Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used. // Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. -decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { - shift: uint - +decode_ileb128_buffer :: proc(buf: []u8) -> (val: i128, size: int, err: Error) { if len(buf) == 0 { return 0, 0, .Buffer_Too_Small } for v in buf { - size += 1 - - // 18 * 7 bits = 126, which including sign means we can have a 19th byte. - if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0x7f { - return 0, 0, .Value_Too_Large + val, size, err = decode_ileb128_byte(v, size, val) + if err != .Buffer_Too_Small { + return } + } + + if err == .Buffer_Too_Small { + val, size = 0, 0 + } + return +} - val |= i128(v & 0x7f) << shift - shift += 7 +// Decode a a signed LEB128 integer into value and number of bytes used, one byte at a time. +// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes. +decode_ileb128_byte :: proc(input: u8, offset: int, accumulator: i128) -> (val: i128, size: int, err: Error) { + size = offset + 1 + shift := uint(offset * 7) - if v < 128 { break } + // 18 * 7 bits = 126, which including sign means we can have a 19th byte. + if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && input > 0x7f { + return 0, 0, .Value_Too_Large } - if buf[size - 1] & 0x40 == 0x40 { - val |= max(i128) << shift + val = accumulator | i128(input & 0x7f) << shift + + if input < 128 { + if input & 0x40 == 0x40 { + val |= max(i128) << (shift + 7) + } + return val, size, .None } - return + return val, size, .Buffer_Too_Small } +decode_ileb128 :: proc{decode_ileb128_buffer, decode_ileb128_byte} // Encode `val` into `buf` as an unsigned LEB128 encoded series of bytes. // `buf` must be appropriately sized. |