authorgravatar for 14938807+xackus@users.noreply.github.comxackus <14938807+xackus@users.noreply.github.com> 2019-11-10 22:05:03+01:00
committergravatar for 14938807+xackus@users.noreply.github.comxackus <14938807+xackus@users.noreply.github.com> 2019-11-10 22:05:03+01:00
log6d0cdf7cd79f3a06fc920c4da545d84a11ac0a6c
tree8d4e9095b2f21456fe88c66763bd654efe78ea59
parentd44a69689eb2579ceb290cd19b91f824b30e6acc

Unescape JSON strings


1 files changed, 71 insertions(+), 1 deletions(-)

lib/std/json.zig+71-1
...@@ -1259,7 +1259,7 @@ pub const Parser = struct {...@@ -1259,7 +1259,7 @@ pub const Parser = struct {
1259 // TODO: We don't strictly have to copy values which do not contain any escape1259 // TODO: We don't strictly have to copy values which do not contain any escape
1260 // characters if flagged with the option.1260 // characters if flagged with the option.
1261 const slice = token.slice(input, i);1261 const slice = token.slice(input, i);
1262 return Value{ .String = try mem.dupe(allocator, u8, slice) };1262 return Value{ .String = try unescapeStringAlloc(allocator, slice) };
1263 }1263 }
12641264
1265 fn parseNumber(p: *Parser, token: Token, input: []const u8, i: usize) !Value {1265 fn parseNumber(p: *Parser, token: Token, input: []const u8, i: usize) !Value {
...@@ -1270,6 +1270,45 @@ pub const Parser = struct {...@@ -1270,6 +1270,45 @@ pub const Parser = struct {
1270 }1270 }
1271};1271};
12721272
1273pub fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 {
1274 var output = try alloc.alloc(u8, input.len);
1275 errdefer alloc.free(output);
1276
1277 var inIndex: usize = 0;
1278 var outIndex: usize = 0;
1279 while(inIndex < input.len) {
1280 if(input[inIndex] == '\\'){
1281 if(input[inIndex + 1] == 'u'){
1282 const codepoint = std.fmt.parseInt(u32, input[inIndex+2 .. inIndex+6], 16) catch return error.InvalidUnicodeHexSymbol;
1283 outIndex += std.unicode.utf8Encode(codepoint, output[outIndex..]) catch return error.InvalidUnicodeHexSymbol;
1284 inIndex += 6;
1285 } else {
1286 output[outIndex] = @as(u8,
1287 switch(input[inIndex + 1]){
1288 '\\' => '\\',
1289 '/' => '/',
1290 'n' => '\n',
1291 'r' => '\r',
1292 't' => '\t',
1293 'f' => 12,
1294 'b' => 8,
1295 '"' => '"',
1296 else => return error.InvalidEscapeCharacter;
1297 }
1298 );
1299 inIndex += 2;
1300 outIndex += 1;
1301 }
1302 } else {
1303 output[outIndex] = input[inIndex];
1304 inIndex += 1;
1305 outIndex += 1;
1306 }
1307 }
1308
1309 return try alloc.realloc(unescaped, outIndex);
1310}
1311
1273test "json.parser.dynamic" {1312test "json.parser.dynamic" {
1274 var p = Parser.init(debug.global_allocator, false);1313 var p = Parser.init(debug.global_allocator, false);
1275 defer p.deinit();1314 defer p.deinit();
...@@ -1379,3 +1418,34 @@ test "parsing empty string gives appropriate error" {...@@ -1379,3 +1418,34 @@ test "parsing empty string gives appropriate error" {
1379 defer p.deinit();1418 defer p.deinit();
1380 testing.expectError(error.UnexpectedEndOfJson, p.parse(""));1419 testing.expectError(error.UnexpectedEndOfJson, p.parse(""));
1381}1420}
1421
1422test "escaped characters" {
1423 const input =
1424 \\{
1425 \\ "backslash": "\\",
1426 \\ "forwardslash": "\/",
1427 \\ "newline": "\n",
1428 \\ "carriagereturn": "\r",
1429 \\ "tab": "\t",
1430 \\ "formfeed": "\f",
1431 \\ "backspace": "\b",
1432 \\ "doublequote": "\"",
1433 \\ "unicode": "\u0105"
1434 \\}
1435 ;
1436
1437 var p = Parser.init(debug.global_allocator, false);
1438 const tree = try p.parse(input);
1439
1440 const obj = tree.root.Object;
1441
1442 testing.expect(mem.eql(u8, obj.get("backslash").?.value.String, "\\"));
1443 testing.expect(mem.eql(u8, obj.get("forwardslash").?.value.String, "/"));
1444 testing.expect(mem.eql(u8, obj.get("newline").?.value.String, "\n"));
1445 testing.expect(mem.eql(u8, obj.get("carriagereturn").?.value.String, "\r"));
1446 testing.expect(mem.eql(u8, obj.get("tab").?.value.String, "\t"));
1447 testing.expect(mem.eql(u8, obj.get("formfeed").?.value.String, "\x0C"));
1448 testing.expect(mem.eql(u8, obj.get("backspace").?.value.String, "\x08"));
1449 testing.expect(mem.eql(u8, obj.get("doublequote").?.value.String, "\""));
1450 testing.expect(mem.eql(u8, obj.get("unicode").?.value.String, "ą"));
1451}