Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
2dcc5a70
Commit
2dcc5a70
authored
Oct 14, 2022
by
Gabriel Ivăncescu
Committed by
Alexandre Julliard
Oct 17, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
jscript: Implement `reviver` argument for JSON.parse.
Signed-off-by:
Gabriel Ivăncescu
<
gabrielopcode@gmail.com
>
parent
a4697901
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
173 additions
and
7 deletions
+173
-7
array.c
dlls/jscript/array.c
+1
-1
jscript.h
dlls/jscript/jscript.h
+1
-0
json.c
dlls/jscript/json.c
+115
-5
api.js
dlls/jscript/tests/api.js
+56
-1
No files found.
dlls/jscript/array.c
View file @
2dcc5a70
...
...
@@ -93,7 +93,7 @@ static HRESULT set_length(jsdisp_t *obj, DWORD length)
return
jsdisp_propput_name
(
obj
,
L"length"
,
jsval_number
(
length
));
}
static
WCHAR
*
idx_to_str
(
DWORD
idx
,
WCHAR
*
ptr
)
WCHAR
*
idx_to_str
(
DWORD
idx
,
WCHAR
*
ptr
)
{
if
(
!
idx
)
{
*
ptr
=
'0'
;
...
...
dlls/jscript/jscript.h
View file @
2dcc5a70
...
...
@@ -318,6 +318,7 @@ HRESULT variant_date_to_string(script_ctx_t*,double,jsstr_t**) DECLSPEC_HIDDEN;
HRESULT
decode_source
(
WCHAR
*
)
DECLSPEC_HIDDEN
;
HRESULT
double_to_string
(
double
,
jsstr_t
**
)
DECLSPEC_HIDDEN
;
WCHAR
*
idx_to_str
(
DWORD
,
WCHAR
*
)
DECLSPEC_HIDDEN
;
static
inline
BOOL
is_digit
(
WCHAR
c
)
{
...
...
dlls/jscript/json.c
View file @
2dcc5a70
...
...
@@ -267,20 +267,104 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r)
return
E_FAIL
;
}
struct
transform_json_object_ctx
{
script_ctx_t
*
ctx
;
IDispatch
*
reviver
;
HRESULT
hres
;
};
static
jsval_t
transform_json_object
(
struct
transform_json_object_ctx
*
proc_ctx
,
jsdisp_t
*
holder
,
jsstr_t
*
name
)
{
jsval_t
res
,
args
[
2
];
const
WCHAR
*
str
;
if
(
!
(
str
=
jsstr_flatten
(
name
)))
proc_ctx
->
hres
=
E_OUTOFMEMORY
;
else
proc_ctx
->
hres
=
jsdisp_propget_name
(
holder
,
str
,
&
args
[
1
]);
if
(
FAILED
(
proc_ctx
->
hres
))
return
jsval_undefined
();
if
(
is_object_instance
(
args
[
1
]))
{
jsdisp_t
*
obj
=
to_jsdisp
(
get_object
(
args
[
1
]));
jsstr_t
*
jsstr
;
DISPID
id
;
BOOL
b
;
if
(
!
obj
)
{
FIXME
(
"non-JS obj in JSON object: %p
\n
"
,
get_object
(
args
[
1
]));
proc_ctx
->
hres
=
E_NOTIMPL
;
return
jsval_undefined
();
}
else
if
(
is_class
(
obj
,
JSCLASS_ARRAY
))
{
unsigned
i
,
length
=
array_get_length
(
obj
);
WCHAR
buf
[
14
],
*
buf_end
;
buf_end
=
buf
+
ARRAY_SIZE
(
buf
)
-
1
;
*
buf_end
--
=
0
;
for
(
i
=
0
;
i
<
length
;
i
++
)
{
str
=
idx_to_str
(
i
,
buf_end
);
if
(
!
(
jsstr
=
jsstr_alloc
(
str
)))
{
proc_ctx
->
hres
=
E_OUTOFMEMORY
;
return
jsval_undefined
();
}
res
=
transform_json_object
(
proc_ctx
,
obj
,
jsstr
);
jsstr_release
(
jsstr
);
if
(
is_undefined
(
res
))
{
if
(
FAILED
(
proc_ctx
->
hres
))
return
jsval_undefined
();
if
(
FAILED
(
jsdisp_get_id
(
obj
,
str
,
0
,
&
id
)))
continue
;
proc_ctx
->
hres
=
disp_delete
((
IDispatch
*
)
&
obj
->
IDispatchEx_iface
,
id
,
&
b
);
}
else
{
proc_ctx
->
hres
=
jsdisp_define_data_property
(
obj
,
str
,
PROPF_WRITABLE
|
PROPF_ENUMERABLE
|
PROPF_CONFIGURABLE
,
res
);
jsval_release
(
res
);
}
if
(
FAILED
(
proc_ctx
->
hres
))
return
jsval_undefined
();
}
}
else
{
id
=
DISPID_STARTENUM
;
for
(;;)
{
proc_ctx
->
hres
=
jsdisp_next_prop
(
obj
,
id
,
JSDISP_ENUM_OWN_ENUMERABLE
,
&
id
);
if
(
proc_ctx
->
hres
==
S_FALSE
)
break
;
if
(
FAILED
(
proc_ctx
->
hres
)
||
FAILED
(
proc_ctx
->
hres
=
jsdisp_get_prop_name
(
obj
,
id
,
&
jsstr
)))
return
jsval_undefined
();
res
=
transform_json_object
(
proc_ctx
,
obj
,
jsstr
);
if
(
is_undefined
(
res
))
{
if
(
SUCCEEDED
(
proc_ctx
->
hres
))
proc_ctx
->
hres
=
disp_delete
((
IDispatch
*
)
&
obj
->
IDispatchEx_iface
,
id
,
&
b
);
}
else
{
if
(
!
(
str
=
jsstr_flatten
(
jsstr
)))
proc_ctx
->
hres
=
E_OUTOFMEMORY
;
else
proc_ctx
->
hres
=
jsdisp_define_data_property
(
obj
,
str
,
PROPF_WRITABLE
|
PROPF_ENUMERABLE
|
PROPF_CONFIGURABLE
,
res
);
jsval_release
(
res
);
}
jsstr_release
(
jsstr
);
if
(
FAILED
(
proc_ctx
->
hres
))
return
jsval_undefined
();
}
}
}
args
[
0
]
=
jsval_string
(
name
);
proc_ctx
->
hres
=
disp_call_value
(
proc_ctx
->
ctx
,
proc_ctx
->
reviver
,
(
IDispatch
*
)
&
holder
->
IDispatchEx_iface
,
DISPATCH_METHOD
,
ARRAY_SIZE
(
args
),
args
,
&
res
);
return
FAILED
(
proc_ctx
->
hres
)
?
jsval_undefined
()
:
res
;
}
/* ECMA-262 5.1 Edition 15.12.2 */
static
HRESULT
JSON_parse
(
script_ctx_t
*
ctx
,
jsval_t
vthis
,
WORD
flags
,
unsigned
argc
,
jsval_t
*
argv
,
jsval_t
*
r
)
{
json_parse_ctx_t
parse_ctx
;
const
WCHAR
*
buf
;
jsdisp_t
*
root
;
jsstr_t
*
str
;
jsval_t
ret
;
HRESULT
hres
;
if
(
argc
!=
1
)
{
FIXME
(
"Unsupported args
\n
"
);
return
E_INVALIDARG
;
}
hres
=
to_flat_string
(
ctx
,
argv
[
0
],
&
str
,
&
buf
);
if
(
FAILED
(
hres
))
return
hres
;
...
...
@@ -293,12 +377,38 @@ static HRESULT JSON_parse(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned
hres
=
parse_json_value
(
&
parse_ctx
,
&
ret
);
if
(
SUCCEEDED
(
hres
)
&&
skip_spaces
(
&
parse_ctx
))
{
FIXME
(
"syntax error
\n
"
);
jsval_release
(
ret
);
hres
=
E_FAIL
;
}
jsstr_release
(
str
);
if
(
FAILED
(
hres
))
return
hres
;
/* FIXME: check IsCallable */
if
(
argc
>
1
&&
is_object_instance
(
argv
[
1
]))
{
hres
=
create_object
(
ctx
,
NULL
,
&
root
);
if
(
FAILED
(
hres
))
{
jsval_release
(
ret
);
return
hres
;
}
hres
=
jsdisp_define_data_property
(
root
,
L""
,
PROPF_WRITABLE
|
PROPF_ENUMERABLE
|
PROPF_CONFIGURABLE
,
ret
);
jsval_release
(
ret
);
if
(
SUCCEEDED
(
hres
))
{
struct
transform_json_object_ctx
proc_ctx
=
{
ctx
,
get_object
(
argv
[
1
]),
S_OK
};
if
(
!
(
str
=
jsstr_alloc
(
L""
)))
hres
=
E_OUTOFMEMORY
;
else
{
ret
=
transform_json_object
(
&
proc_ctx
,
root
,
str
);
jsstr_release
(
str
);
hres
=
proc_ctx
.
hres
;
}
}
jsdisp_release
(
root
);
if
(
FAILED
(
hres
))
return
hres
;
}
if
(
r
)
*
r
=
ret
;
else
...
...
dlls/jscript/tests/api.js
View file @
2dcc5a70
...
...
@@ -1960,7 +1960,7 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN");
[[[,
2
,
undefined
,
3
,{
prop
:
0
},],
undefined
,
" "
],
"[
\
n null,
\
n 2,
\
n null,
\
n 3,
\
n {
\
n
\"
prop
\"
: 0
\
n },
\
n null
\
n]"
]
];
var
i
,
s
,
v
;
var
i
,
s
,
v
,
t
;
for
(
i
=
0
;
i
<
stringify_tests
.
length
;
i
++
)
{
s
=
JSON
.
stringify
.
apply
(
null
,
stringify_tests
[
i
][
0
]);
...
...
@@ -2043,6 +2043,61 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN");
v
=
JSON
.
parse
(
parse_tests
[
i
][
0
]);
ok
(
json_cmp
(
v
,
parse_tests
[
i
][
1
]),
"parse["
+
i
+
"] returned "
+
v
+
", expected "
+
parse_tests
[
i
][
1
]);
}
v
=
[
[
-
1
,
"b"
],
{
"length"
:
-
2
,
"0"
:
-
4
,
"1"
:
-
5
},
[{}],
[{
"x"
:
[
null
]}]
];
s
=
'{'
+
'"foo": true,'
+
'"bar": [],'
+
'"baz": "remove_me",'
+
'"obj": {'
+
' "arr": [ [1, "b"], {"length": 2, "0": 4, "1": 5}, [{}], [{"x": [null]}] ],'
+
' "": "empty"'
+
'},'
+
'"last": false'
+
'}'
;
o
=
JSON
.
parse
(
s
),
t
=
JSON
.
parse
(
s
),
i
=
new
Object
();
i
[
""
]
=
t
;
delete
t
.
baz
;
/* baz gets removed */
t
.
obj
.
arr
=
v
;
/* has negative values */
var
walk_expect
=
[
[
o
,
"foo"
,
true
],
[
o
,
"bar"
,
[]
],
[
o
,
"baz"
,
"remove_me"
],
[
[
1
,
"b"
],
"0"
,
1
],
[
[
-
1
,
"b"
],
"1"
,
"b"
],
[
[
[
-
1
,
"b"
],
{
"length"
:
2
,
"0"
:
4
,
"1"
:
5
},
[{}],
[{
"x"
:
[
null
]}]
],
"0"
,
[
-
1
,
"b"
]
],
[
{
"length"
:
2
,
"0"
:
4
,
"1"
:
5
},
"length"
,
2
],
[
{
"length"
:
-
2
,
"0"
:
4
,
"1"
:
5
},
"0"
,
4
],
[
{
"length"
:
-
2
,
"0"
:
-
4
,
"1"
:
5
},
"1"
,
5
],
[
v
,
"1"
,
{
"length"
:
-
2
,
"0"
:
-
4
,
"1"
:
-
5
}
],
[
[{}],
"0"
,
{}
],
[
v
,
"2"
,
[{}]
],
[
[
null
],
"0"
,
null
],
[
{
"x"
:
[
null
]},
"x"
,
[
null
]
],
[
[{
"x"
:
[
null
]}],
"0"
,
{
"x"
:
[
null
]}
],
[
v
,
"3"
,
[{
"x"
:
[
null
]}]
],
[
{
"arr"
:
v
,
""
:
"empty"
},
"arr"
,
v
],
[
{
"arr"
:
v
,
""
:
"empty"
},
""
,
"empty"
],
[
t
,
"obj"
,
{
"arr"
:
v
,
""
:
"empty"
}
],
[
t
,
"last"
,
false
],
[
i
,
""
,
t
]
];
i
=
0
;
v
=
JSON
.
parse
(
s
,
function
(
prop
,
value
)
{
var
a
=
[
this
,
prop
,
value
];
ok
(
json_cmp
(
a
,
walk_expect
[
i
]),
"[walk step "
+
i
+
"] got ["
+
a
+
"], expected ["
+
walk_expect
[
i
]
+
"]"
);
i
++
;
return
(
typeof
value
===
'number'
)
?
-
value
:
(
value
===
"remove_me"
?
undefined
:
value
);
});
ok
(
i
===
walk_expect
.
length
,
"parse with reviver walked "
+
i
+
" steps, expected "
+
walk_expect
.
length
);
ok
(
json_cmp
(
v
,
t
),
"parse with reviver returned wrong object"
);
v
=
JSON
.
parse
(
'true'
,
function
(
prop
,
value
)
{
return
prop
===
""
?
undefined
:
value
;
});
ok
(
v
===
undefined
,
"parse with reviver removing last prop returned "
+
v
);
v
=
JSON
.
parse
(
'true'
,
function
(
prop
,
value
)
{
return
prop
===
""
?
false
:
value
;
});
ok
(
v
===
false
,
"parse with reviver setting last prop to false returned "
+
v
);
})();
var
func
=
function
(
a
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment