Jacek Caban : jscript: Support replacer argument in JSON.stringify.

Alexandre Julliard julliard at winehq.org
Tue Apr 20 16:27:47 CDT 2021


Module: wine
Branch: master
Commit: 34a9c343805f0cd526e1b1665d4f59005b421523
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=34a9c343805f0cd526e1b1665d4f59005b421523

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Apr 20 19:12:25 2021 +0200

jscript: Support replacer argument in JSON.stringify.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/jscript/json.c       | 38 +++++++++++++++++++++++++++++++-------
 dlls/jscript/tests/api.js | 21 ++++++++++++++++++++-
 2 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c
index f3b523d63d8..a8014f95b4f 100644
--- a/dlls/jscript/json.c
+++ b/dlls/jscript/json.c
@@ -320,6 +320,8 @@ typedef struct {
     size_t stack_size;
 
     WCHAR gap[11]; /* according to the spec, it's no longer than 10 chars */
+
+    jsdisp_t *replacer;
 } stringify_ctx_t;
 
 static BOOL stringify_push_obj(stringify_ctx_t *ctx, jsdisp_t *obj)
@@ -656,7 +658,22 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *na
             FIXME("Use toJSON.\n");
     }
 
-    /* FIXME: Support replacer replacer. */
+    if(ctx->replacer) {
+        jsstr_t *name_str;
+        jsval_t args[2];
+        if(!(name_str = jsstr_alloc(name))) {
+            jsval_release(value);
+            return E_OUTOFMEMORY;
+        }
+        args[0] = jsval_string(name_str);
+        args[1] = value;
+        hres = jsdisp_call_value(ctx->replacer, to_disp(object), DISPATCH_METHOD, ARRAY_SIZE(args), args, &v);
+        jsstr_release(name_str);
+        jsval_release(value);
+        if(FAILED(hres))
+            return hres;
+        value = v;
+    }
 
     v = value;
     hres = maybe_to_primitive(ctx->ctx, v, &value);
@@ -736,8 +753,8 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *na
 /* ECMA-262 5.1 Edition    15.12.3 */
 static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
-    stringify_ctx_t stringify_ctx = {ctx, NULL,0,0, NULL,0,0, {0}};
-    jsdisp_t *obj;
+    stringify_ctx_t stringify_ctx = { ctx };
+    jsdisp_t *obj = NULL, *replacer;
     HRESULT hres;
 
     TRACE("\n");
@@ -748,9 +765,14 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
         return S_OK;
     }
 
-    if(argc >= 2 && is_object_instance(argv[1])) {
-        FIXME("Replacer %s not yet supported\n", debugstr_jsval(argv[1]));
-        return E_NOTIMPL;
+    if(argc >= 2 && is_object_instance(argv[1]) && get_object(argv[1]) &&
+       (replacer = to_jsdisp(get_object(argv[1])))) {
+        if(is_callable(replacer)) {
+            stringify_ctx.replacer = jsdisp_addref(replacer);
+        }else if(is_class(replacer, JSCLASS_ARRAY)) {
+            FIXME("Array replacer not yet supported\n");
+            return E_NOTIMPL;
+        }
     }
 
     if(argc >= 3) {
@@ -758,7 +780,7 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
 
         hres = maybe_to_primitive(ctx, argv[2], &space_val);
         if(FAILED(hres))
-            return hres;
+            goto fail;
 
         if(is_number(space_val)) {
             double n = get_number(space_val);
@@ -805,6 +827,8 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
 fail:
     if(obj)
         jsdisp_release(obj);
+    if(stringify_ctx.replacer)
+        jsdisp_release(stringify_ctx.replacer);
     heap_free(stringify_ctx.buf);
     heap_free(stringify_ctx.stack);
     return hres;
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index 564dfc16f30..d5d8e7d34b9 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -1923,7 +1923,7 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN");
         [[NaN], "null"],
         [[Infinity], "null"],
         [[-Infinity], "null"],
-        [[{prop1: true, prop2: "string"}], "{\"prop1\":true,\"prop2\":\"string\"}"],
+        [[{prop1: true, prop2: "string", func1: function() {}}], "{\"prop1\":true,\"prop2\":\"string\"}"],
         [[{prop1: true, prop2: testObj, prop3: undefined}], "{\"prop1\":true}"],
         [[{prop1: true, prop2: {prop: "string"}},undefined,"  "],
                 "{\n  \"prop1\": true,\n  \"prop2\": {\n    \"prop\": \"string\"\n  }\n}"],
@@ -1951,6 +1951,25 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN");
     ok(s === undefined || s === "undefined" /* broken on some old versions */,
        "stringify(undefined) returned " + s + " expected undefined");
 
+    s = JSON.stringify(1, function(name, value) {
+        ok(name === "", "name = " + name);
+        ok(value === 1, "value = " + value);
+        ok(this[name] === value, "this[" + name + "] = " + this[name] + " expected " + value);
+        return 2;
+    });
+    ok(s == "2", "s = " + s);
+
+    var o = { prop: 1 };
+        s = JSON.stringify(1, function(name, value) {
+        ok(name === "" || name === "prop", "name = " + name);
+        ok(value === 1 || value === true, "value = " + value);
+        ok(this[name] === value, "this[" + name + "] = " + this[name] + " expected " + value);
+        if(name === "") return o;
+        ok(this === o, "this != o");
+        return value;
+    });
+    ok(s == "{\"prop\":1}", "s = " + s);
+
     var parse_tests = [
         ["true", true],
         ["   \nnull  ", null],




More information about the wine-cvs mailing list