| ... | @@ -111,21 +111,23 @@ pub fn view(self: Decoder, elem: Element) []const u8 { | ... | @@ -111,21 +111,23 @@ pub fn view(self: Decoder, elem: Element) []const u8 { |
| 111 | } | 111 | } |
| 112 | | 112 | |
| 113 | fn int(comptime T: type, value: []const u8) error{ NonCanonical, LargeValue }!T { | 113 | fn int(comptime T: type, value: []const u8) error{ NonCanonical, LargeValue }!T { |
| 114 | if (@typeInfo(T).int.bits % 8 != 0) @compileError("T must be byte aligned"); | 114 | const info = @typeInfo(T).int; |
| 115 | | 115 | if (info.bits % 8 != 0) @compileError("T must be byte aligned"); |
| 116 | var bytes = value; | 116 | |
| 117 | if (bytes.len >= 2) { | 117 | if (value.len == 0) return error.NonCanonical; |
| 118 | if (bytes[0] == 0) { | 118 | if (value.len >= 2) { |
| 119 | if (@clz(bytes[1]) > 0) return error.NonCanonical; | 119 | if (value[0] == 0x00 and value[1] & 0x80 == 0) return error.NonCanonical; |
| 120 | bytes.ptr += 1; | 120 | if (value[0] == 0xff and value[1] & 0x80 != 0) return error.NonCanonical; |
| 121 | } | | |
| 122 | if (bytes[0] == 0xff and @clz(bytes[1]) == 0) return error.NonCanonical; | | |
| 123 | } | 121 | } |
| 124 | | 122 | |
| | 123 | const had_sign_byte = value.len >= 2 and value[0] == 0x00; |
| | 124 | const bytes = if (had_sign_byte) value[1..] else value; |
| 125 | if (bytes.len > @sizeOf(T)) return error.LargeValue; | 125 | if (bytes.len > @sizeOf(T)) return error.LargeValue; |
| 126 | if (@sizeOf(T) == 1) return @bitCast(bytes[0]); | | |
| 127 | | 126 | |
| 128 | return std.mem.readVarInt(T, bytes, .big); | 127 | const sign_extend = info.signedness == .signed and !had_sign_byte and bytes[0] & 0x80 != 0; |
| | 128 | var buf: [@sizeOf(T)]u8 = @splat(if (sign_extend) 0xff else 0); |
| | 129 | @memcpy(buf[buf.len - bytes.len ..], bytes); |
| | 130 | return std.mem.readInt(T, &buf, .big); |
| 129 | } | 131 | } |
| 130 | | 132 | |
| 131 | test int { | 133 | test int { |
| ... | @@ -136,6 +138,16 @@ test int { | ... | @@ -136,6 +138,16 @@ test int { |
| 136 | const big = [_]u8{ 0xef, 0xff }; | 138 | const big = [_]u8{ 0xef, 0xff }; |
| 137 | try expectError(error.LargeValue, int(u8, &big)); | 139 | try expectError(error.LargeValue, int(u8, &big)); |
| 138 | try expectEqual(0xefff, int(u16, &big)); | 140 | try expectEqual(0xefff, int(u16, &big)); |
| | 141 | |
| | 142 | try expectEqual(@as(u16, 255), try int(u16, &.{ 0x00, 0xff })); |
| | 143 | try expectEqual(@as(u16, 0x8000), try int(u16, &.{ 0x00, 0x80, 0x00 })); |
| | 144 | |
| | 145 | try expectEqual(@as(i8, -1), try int(i8, &.{0xff})); |
| | 146 | try expectEqual(@as(i16, -1), try int(i16, &.{0xff})); |
| | 147 | try expectEqual(@as(i16, -128), try int(i16, &.{0x80})); |
| | 148 | try expectEqual(@as(i16, -129), try int(i16, &.{ 0xff, 0x7f })); |
| | 149 | try expectEqual(@as(i16, 255), try int(i16, &.{ 0x00, 0xff })); |
| | 150 | try expectEqual(@as(i32, 0x7fffffff), try int(i32, &.{ 0x7f, 0xff, 0xff, 0xff })); |
| 139 | } | 151 | } |
| 140 | | 152 | |
| 141 | test Decoder { | 153 | test Decoder { |