From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/json.c | 77 +++++++++++++++++++++++++++++++++++++-- dlls/jscript/lex.c | 2 +- dlls/jscript/parser.h | 1 + dlls/jscript/tests/api.js | 2 +- dlls/mshtml/tests/es5.js | 20 ++++++++++ 5 files changed, 97 insertions(+), 5 deletions(-)
diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index b56d75d3570..9018687aba2 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -57,6 +57,77 @@ static BOOL is_keyword(json_parse_ctx_t *ctx, const WCHAR *keyword) return TRUE; }
+static BOOL unescape_json_string(WCHAR *str, size_t *len) +{ + WCHAR *pd, *p, c, *end = str + *len; + int i; + + pd = p = str; + while(p < end) { + if(*p != '\') { + *pd++ = *p++; + continue; + } + + if(++p == end) + return FALSE; + + switch(*p) { + case '"': + case '\': + case '/': + c = *p; + break; + case 'b': + c = '\b'; + break; + case 't': + c = '\t'; + break; + case 'n': + c = '\n'; + break; + case 'f': + c = '\f'; + break; + case 'r': + c = '\r'; + break; + case 'u': + if(p + 4 >= end) + return FALSE; + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c = i << 12; + + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c += i << 8; + + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c += i << 4; + + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c += i; + break; + default: + return FALSE; + } + + *pd++ = c; + p++; + } + + *len = pd - str; + return TRUE; +} + /* ECMA-262 5.1 Edition 15.12.1.1 */ static HRESULT parse_json_string(json_parse_ctx_t *ctx, WCHAR **r) { @@ -80,10 +151,10 @@ static HRESULT parse_json_string(json_parse_ctx_t *ctx, WCHAR **r) if(len) memcpy(buf, ptr, len*sizeof(WCHAR));
- if(!unescape(buf, &len)) { - FIXME("unescape failed\n"); + if(!(ctx->ctx->html_mode ? unescape_json_string(buf, &len) : unescape(buf, &len))) { + WARN("unescape failed\n"); free(buf); - return E_FAIL; + return JS_E_INVALID_CHAR; }
buf[len] = 0; diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c index 3bb2040803d..ee29bff1e37 100644 --- a/dlls/jscript/lex.c +++ b/dlls/jscript/lex.c @@ -117,7 +117,7 @@ static BOOL is_endline(WCHAR c) return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029; }
-static int hex_to_int(WCHAR c) +int hex_to_int(WCHAR c) { if('0' <= c && c <= '9') return c-'0'; diff --git a/dlls/jscript/parser.h b/dlls/jscript/parser.h index 3b616b43b07..406bedc6607 100644 --- a/dlls/jscript/parser.h +++ b/dlls/jscript/parser.h @@ -65,6 +65,7 @@ static inline void *parser_alloc_tmp(parser_ctx_t *ctx, DWORD size) return heap_pool_alloc(&ctx->script->tmp_heap, size); }
+int hex_to_int(WCHAR); BOOL is_identifier_char(WCHAR); BOOL unescape(WCHAR*,size_t*); HRESULT parse_decimal(const WCHAR**,const WCHAR*,double*); diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index a82e4756c24..255418a6744 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2010,7 +2010,7 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN"); ["true", true], [" \nnull ", null], ["{}", {}], - [""\r\n test\u1111"", "\r\n test\u1111"], + [""\r\n test\u1111\/\x20\45\'"", "\r\n test\u1111/ %'"], ["{"x" :\n true}", {x:true}], ["{"x y": {}, "z": {"x":null}}", {"x y":{}, z:{x:null}}], ["[]", []], diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 630d9079703..7496ea4c395 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1676,6 +1676,26 @@ sync_test("isFrozen", function() { } });
+sync_test("JSON.parse escapes", function() { + var i, valid = [ "b", "t", "n", "f", "r", "u1111", '"', "/" ]; + + for(i = 0; i < valid.length; i++) { + var a = JSON.parse('"\' + valid[i] + '"'), b = eval('"\' + valid[i] + '"'); + ok(a === b, "JSON.parse with \" + valid[i] + " returned " + a); + } + + var invalid = [ "0", "00", "05", "x20", "i", "'" ]; + + for(i = 0; i < invalid.length; i++) { + try { + JSON.parse('"\' + invalid[i] + '"'); + ok(false, "expected exception calling JSON.parse with \" + invalid[i]); + } catch(e) { + ok(e.number === 0xa03f6 - 0x80000000, "calling JSON.parse with \" + invalid[i] + " threw " + e.number); + } + } +}); + sync_test("RegExp", function() { var r;