diff options
| author | ominitay <37453713+ominitay@users.noreply.github.com> | 2022-07-15 22:05:35 +0100 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-07-23 13:52:16 +0300 |
| commit | 889efddd1a2b12d3348f06900436b9ba8c823a01 (patch) | |
| tree | 16e0500940e8273e718ab704f07711bb4089f993 /lib/std/json.zig | |
| parent | a8bfddfaeae4f48c044fd134aac1e977e6a161f8 (diff) | |
| download | zig-889efddd1a2b12d3348f06900436b9ba8c823a01.tar.gz zig-889efddd1a2b12d3348f06900436b9ba8c823a01.zip | |
std.json: Fix parsing of large numbers
Numbers greater than about 2^53 are encoded as strings in JSON.
std.json.parseInternal previously errored out in this condition.
Diffstat (limited to 'lib/std/json.zig')
| -rw-r--r-- | lib/std/json.zig | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/lib/std/json.zig b/lib/std/json.zig index 9f678fb4aa..baf93af47c 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1422,23 +1422,37 @@ fn parseInternal( }; }, .Float, .ComptimeFloat => { - const numberToken = switch (token) { - .Number => |n| n, + switch (token) { + .Number => |numberToken| return try std.fmt.parseFloat(T, numberToken.slice(tokens.slice, tokens.i - 1)), + .String => |stringToken| return try std.fmt.parseFloat(T, stringToken.slice(tokens.slice, tokens.i - 1)), else => return error.UnexpectedToken, - }; - return try std.fmt.parseFloat(T, numberToken.slice(tokens.slice, tokens.i - 1)); + } }, .Int, .ComptimeInt => { - const numberToken = switch (token) { - .Number => |n| n, + switch (token) { + .Number => |numberToken| { + if (numberToken.is_integer) + return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10); + const float = try std.fmt.parseFloat(f128, numberToken.slice(tokens.slice, tokens.i - 1)); + if (@round(float) != float) return error.InvalidNumber; + if (float > std.math.maxInt(T) or float < std.math.minInt(T)) return error.Overflow; + return @floatToInt(T, float); + }, + .String => |stringToken| { + return std.fmt.parseInt(T, stringToken.slice(tokens.slice, tokens.i - 1), 10) catch |err| { + switch (err) { + error.Overflow => return err, + error.InvalidCharacter => { + const float = try std.fmt.parseFloat(f128, stringToken.slice(tokens.slice, tokens.i - 1)); + if (@round(float) != float) return error.InvalidNumber; + if (float > std.math.maxInt(T) or float < std.math.minInt(T)) return error.Overflow; + return @floatToInt(T, float); + }, + } + }; + }, else => return error.UnexpectedToken, - }; - if (numberToken.is_integer) - return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10); - const float = try std.fmt.parseFloat(f128, numberToken.slice(tokens.slice, tokens.i - 1)); - if (@round(float) != float) return error.InvalidNumber; - if (float > std.math.maxInt(T) or float < std.math.minInt(T)) return error.Overflow; - return @floatToInt(T, float); + } }, .Optional => |optionalInfo| { if (token == .Null) { |
