Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
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-winehq
Commits
95bdd084
Commit
95bdd084
authored
Jan 27, 2016
by
Jacek Caban
Committed by
Alexandre Julliard
Jan 28, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
jscript: Added JSON.stringify implementation.
Signed-off-by:
Jacek Caban
<
jacek@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
f0be56e1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
511 additions
and
2 deletions
+511
-2
array.c
dlls/jscript/array.c
+7
-0
bool.c
dlls/jscript/bool.c
+8
-0
jscript.h
dlls/jscript/jscript.h
+3
-0
json.c
dlls/jscript/json.c
+493
-2
No files found.
dlls/jscript/array.c
View file @
95bdd084
...
...
@@ -20,6 +20,7 @@
#include "wine/port.h"
#include <math.h>
#include <assert.h>
#include "jscript.h"
...
...
@@ -64,6 +65,12 @@ static inline ArrayInstance *array_this(vdisp_t *jsthis)
return
is_vclass
(
jsthis
,
JSCLASS_ARRAY
)
?
array_from_vdisp
(
jsthis
)
:
NULL
;
}
unsigned
array_get_length
(
jsdisp_t
*
array
)
{
assert
(
is_class
(
array
,
JSCLASS_ARRAY
));
return
array_from_jsdisp
(
array
)
->
length
;
}
static
HRESULT
get_length
(
script_ctx_t
*
ctx
,
vdisp_t
*
vdisp
,
jsdisp_t
**
jsthis
,
DWORD
*
ret
)
{
ArrayInstance
*
array
;
...
...
dlls/jscript/bool.c
View file @
95bdd084
...
...
@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include "jscript.h"
#include "wine/debug.h"
...
...
@@ -37,6 +39,12 @@ static inline BoolInstance *bool_this(vdisp_t *jsthis)
return
is_vclass
(
jsthis
,
JSCLASS_BOOLEAN
)
?
(
BoolInstance
*
)
jsthis
->
u
.
jsdisp
:
NULL
;
}
BOOL
bool_obj_value
(
jsdisp_t
*
obj
)
{
assert
(
is_class
(
obj
,
JSCLASS_BOOLEAN
));
return
((
BoolInstance
*
)
obj
)
->
val
;
}
/* ECMA-262 3rd Edition 15.6.4.2 */
static
HRESULT
Bool_toString
(
script_ctx_t
*
ctx
,
vdisp_t
*
jsthis
,
WORD
flags
,
unsigned
argc
,
jsval_t
*
argv
,
jsval_t
*
r
)
{
...
...
dlls/jscript/jscript.h
View file @
95bdd084
...
...
@@ -461,6 +461,9 @@ HRESULT regexp_match_next(script_ctx_t*,jsdisp_t*,DWORD,jsstr_t*,struct match_st
HRESULT
parse_regexp_flags
(
const
WCHAR
*
,
DWORD
,
DWORD
*
)
DECLSPEC_HIDDEN
;
HRESULT
regexp_string_match
(
script_ctx_t
*
,
jsdisp_t
*
,
jsstr_t
*
,
jsval_t
*
)
DECLSPEC_HIDDEN
;
BOOL
bool_obj_value
(
jsdisp_t
*
)
DECLSPEC_HIDDEN
;
unsigned
array_get_length
(
jsdisp_t
*
)
DECLSPEC_HIDDEN
;
static
inline
BOOL
is_class
(
jsdisp_t
*
jsdisp
,
jsclass_t
class
)
{
return
jsdisp
->
builtin_info
->
class
==
class
;
...
...
dlls/jscript/json.c
View file @
95bdd084
...
...
@@ -17,6 +17,7 @@
*/
#include <math.h>
#include <assert.h>
#include "jscript.h"
#include "parser.h"
...
...
@@ -33,6 +34,8 @@ static const WCHAR nullW[] = {'n','u','l','l',0};
static
const
WCHAR
trueW
[]
=
{
't'
,
'r'
,
'u'
,
'e'
,
0
};
static
const
WCHAR
falseW
[]
=
{
'f'
,
'a'
,
'l'
,
's'
,
'e'
,
0
};
static
const
WCHAR
toJSONW
[]
=
{
't'
,
'o'
,
'J'
,
'S'
,
'O'
,
'N'
,
0
};
typedef
struct
{
const
WCHAR
*
ptr
;
const
WCHAR
*
end
;
...
...
@@ -322,10 +325,498 @@ static HRESULT JSON_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsign
return
S_OK
;
}
typedef
struct
{
script_ctx_t
*
ctx
;
WCHAR
*
buf
;
size_t
buf_size
;
size_t
buf_len
;
jsdisp_t
**
stack
;
size_t
stack_top
;
size_t
stack_size
;
WCHAR
gap
[
11
];
/* according to the spec, it's no longer than 10 chars */
}
stringify_ctx_t
;
static
BOOL
stringify_push_obj
(
stringify_ctx_t
*
ctx
,
jsdisp_t
*
obj
)
{
if
(
!
ctx
->
stack_size
)
{
ctx
->
stack
=
heap_alloc
(
4
*
sizeof
(
*
ctx
->
stack
));
if
(
!
ctx
->
stack
)
return
FALSE
;
ctx
->
stack_size
=
4
;
}
else
if
(
ctx
->
stack_top
==
ctx
->
stack_size
)
{
jsdisp_t
**
new_stack
;
new_stack
=
heap_realloc
(
ctx
->
stack
,
ctx
->
stack_size
*
2
*
sizeof
(
*
ctx
->
stack
));
if
(
!
new_stack
)
return
FALSE
;
ctx
->
stack
=
new_stack
;
ctx
->
stack_size
*=
2
;
}
ctx
->
stack
[
ctx
->
stack_top
++
]
=
obj
;
return
TRUE
;
}
static
void
stringify_pop_obj
(
stringify_ctx_t
*
ctx
)
{
ctx
->
stack_top
--
;
}
static
BOOL
is_on_stack
(
stringify_ctx_t
*
ctx
,
jsdisp_t
*
obj
)
{
size_t
i
=
ctx
->
stack_top
;
while
(
i
--
)
{
if
(
ctx
->
stack
[
i
]
==
obj
)
return
TRUE
;
}
return
FALSE
;
}
static
BOOL
append_string_len
(
stringify_ctx_t
*
ctx
,
const
WCHAR
*
str
,
size_t
len
)
{
if
(
!
ctx
->
buf_size
)
{
ctx
->
buf
=
heap_alloc
(
len
*
2
*
sizeof
(
WCHAR
));
if
(
!
ctx
->
buf
)
return
FALSE
;
ctx
->
buf_size
=
len
*
2
;
}
else
if
(
ctx
->
buf_len
+
len
>
ctx
->
buf_size
)
{
WCHAR
*
new_buf
;
size_t
new_size
;
new_size
=
ctx
->
buf_size
*
2
+
len
;
new_buf
=
heap_realloc
(
ctx
->
buf
,
new_size
*
sizeof
(
WCHAR
));
if
(
!
new_buf
)
return
FALSE
;
ctx
->
buf
=
new_buf
;
ctx
->
buf_size
=
new_size
;
}
if
(
len
)
memcpy
(
ctx
->
buf
+
ctx
->
buf_len
,
str
,
len
*
sizeof
(
WCHAR
));
ctx
->
buf_len
+=
len
;
return
TRUE
;
}
static
inline
BOOL
append_string
(
stringify_ctx_t
*
ctx
,
const
WCHAR
*
str
)
{
return
append_string_len
(
ctx
,
str
,
strlenW
(
str
));
}
static
inline
BOOL
append_char
(
stringify_ctx_t
*
ctx
,
WCHAR
c
)
{
return
append_string_len
(
ctx
,
&
c
,
1
);
}
static
inline
BOOL
append_simple_quote
(
stringify_ctx_t
*
ctx
,
WCHAR
c
)
{
WCHAR
str
[]
=
{
'\\'
,
c
};
return
append_string_len
(
ctx
,
str
,
2
);
}
static
HRESULT
maybe_to_primitive
(
script_ctx_t
*
ctx
,
jsval_t
val
,
jsval_t
*
r
)
{
jsdisp_t
*
obj
;
HRESULT
hres
;
if
(
!
is_object_instance
(
val
)
||
!
get_object
(
val
)
||
!
(
obj
=
iface_to_jsdisp
((
IUnknown
*
)
get_object
(
val
))))
return
jsval_copy
(
val
,
r
);
if
(
is_class
(
obj
,
JSCLASS_NUMBER
))
{
double
n
;
hres
=
to_number
(
ctx
,
val
,
&
n
);
jsdisp_release
(
obj
);
if
(
SUCCEEDED
(
hres
))
*
r
=
jsval_number
(
n
);
return
hres
;
}
if
(
is_class
(
obj
,
JSCLASS_STRING
))
{
jsstr_t
*
str
;
hres
=
to_string
(
ctx
,
val
,
&
str
);
jsdisp_release
(
obj
);
if
(
SUCCEEDED
(
hres
))
*
r
=
jsval_string
(
str
);
return
hres
;
}
if
(
is_class
(
obj
,
JSCLASS_BOOLEAN
))
{
*
r
=
jsval_bool
(
bool_obj_value
(
obj
));
jsdisp_release
(
obj
);
return
S_OK
;
}
*
r
=
jsval_obj
(
obj
);
return
S_OK
;
}
/* ECMA-262 5.1 Edition 15.12.3 (abstract operation Quote) */
static
HRESULT
json_quote
(
stringify_ctx_t
*
ctx
,
const
WCHAR
*
ptr
,
size_t
len
)
{
if
(
!
ptr
||
!
append_char
(
ctx
,
'"'
))
return
E_OUTOFMEMORY
;
while
(
len
--
)
{
switch
(
*
ptr
)
{
case
'"'
:
case
'\\'
:
if
(
!
append_simple_quote
(
ctx
,
*
ptr
))
return
E_OUTOFMEMORY
;
break
;
case
'\b'
:
if
(
!
append_simple_quote
(
ctx
,
'b'
))
return
E_OUTOFMEMORY
;
break
;
case
'\f'
:
if
(
!
append_simple_quote
(
ctx
,
'f'
))
return
E_OUTOFMEMORY
;
break
;
case
'\n'
:
if
(
!
append_simple_quote
(
ctx
,
'n'
))
return
E_OUTOFMEMORY
;
break
;
case
'\r'
:
if
(
!
append_simple_quote
(
ctx
,
'r'
))
return
E_OUTOFMEMORY
;
break
;
case
'\t'
:
if
(
!
append_simple_quote
(
ctx
,
't'
))
return
E_OUTOFMEMORY
;
break
;
default:
if
(
*
ptr
<
' '
)
{
const
WCHAR
formatW
[]
=
{
'\\'
,
'u'
,
'%'
,
'0'
,
'4'
,
'x'
,
0
};
WCHAR
buf
[
7
];
sprintfW
(
buf
,
formatW
,
*
ptr
);
if
(
!
append_string
(
ctx
,
buf
))
return
E_OUTOFMEMORY
;
}
else
{
if
(
!
append_char
(
ctx
,
*
ptr
))
return
E_OUTOFMEMORY
;
}
}
ptr
++
;
}
return
append_char
(
ctx
,
'"'
)
?
S_OK
:
E_OUTOFMEMORY
;
}
static
inline
BOOL
is_callable
(
jsdisp_t
*
obj
)
{
return
is_class
(
obj
,
JSCLASS_FUNCTION
);
}
static
HRESULT
stringify
(
stringify_ctx_t
*
ctx
,
jsval_t
val
);
/* ECMA-262 5.1 Edition 15.12.3 (abstract operation JA) */
static
HRESULT
stringify_array
(
stringify_ctx_t
*
ctx
,
jsdisp_t
*
obj
)
{
unsigned
length
,
i
,
j
;
jsval_t
val
;
HRESULT
hres
;
if
(
is_on_stack
(
ctx
,
obj
))
{
FIXME
(
"Found a cycle
\n
"
);
return
E_FAIL
;
}
if
(
!
stringify_push_obj
(
ctx
,
obj
))
return
E_OUTOFMEMORY
;
if
(
!
append_char
(
ctx
,
'['
))
return
E_OUTOFMEMORY
;
length
=
array_get_length
(
obj
);
for
(
i
=
0
;
i
<
length
;
i
++
)
{
if
(
i
&&
!
append_char
(
ctx
,
','
))
return
E_OUTOFMEMORY
;
if
(
*
ctx
->
gap
)
{
if
(
!
append_char
(
ctx
,
'\n'
))
return
E_OUTOFMEMORY
;
for
(
j
=
0
;
j
<
ctx
->
stack_top
;
j
++
)
{
if
(
!
append_string
(
ctx
,
ctx
->
gap
))
return
E_OUTOFMEMORY
;
}
}
hres
=
jsdisp_get_idx
(
obj
,
i
,
&
val
);
if
(
FAILED
(
hres
))
return
hres
;
hres
=
stringify
(
ctx
,
val
);
if
(
FAILED
(
hres
))
return
hres
;
if
(
hres
==
S_FALSE
&&
!
append_string
(
ctx
,
nullW
))
return
E_OUTOFMEMORY
;
}
if
((
length
&&
*
ctx
->
gap
&&
!
append_char
(
ctx
,
'\n'
))
||
!
append_char
(
ctx
,
']'
))
return
E_OUTOFMEMORY
;
stringify_pop_obj
(
ctx
);
return
S_OK
;
}
/* ECMA-262 5.1 Edition 15.12.3 (abstract operation JO) */
static
HRESULT
stringify_object
(
stringify_ctx_t
*
ctx
,
jsdisp_t
*
obj
)
{
DISPID
dispid
=
DISPID_STARTENUM
;
jsval_t
val
=
jsval_undefined
();
unsigned
prop_cnt
=
0
,
i
;
size_t
stepback
;
BSTR
prop_name
;
HRESULT
hres
;
if
(
is_on_stack
(
ctx
,
obj
))
{
FIXME
(
"Found a cycle
\n
"
);
return
E_FAIL
;
}
if
(
!
stringify_push_obj
(
ctx
,
obj
))
return
E_OUTOFMEMORY
;
if
(
!
append_char
(
ctx
,
'{'
))
return
E_OUTOFMEMORY
;
while
((
hres
=
IDispatchEx_GetNextDispID
(
&
obj
->
IDispatchEx_iface
,
fdexEnumDefault
,
dispid
,
&
dispid
))
==
S_OK
)
{
jsval_release
(
val
);
hres
=
jsdisp_propget
(
obj
,
dispid
,
&
val
);
if
(
FAILED
(
hres
))
return
hres
;
if
(
is_undefined
(
val
))
continue
;
stepback
=
ctx
->
buf_len
;
if
(
prop_cnt
&&
!
append_char
(
ctx
,
','
))
{
hres
=
E_OUTOFMEMORY
;
break
;
}
if
(
*
ctx
->
gap
)
{
if
(
!
append_char
(
ctx
,
'\n'
))
{
hres
=
E_OUTOFMEMORY
;
break
;
}
for
(
i
=
0
;
i
<
ctx
->
stack_top
;
i
++
)
{
if
(
!
append_string
(
ctx
,
ctx
->
gap
))
{
hres
=
E_OUTOFMEMORY
;
break
;
}
}
}
hres
=
IDispatchEx_GetMemberName
(
&
obj
->
IDispatchEx_iface
,
dispid
,
&
prop_name
);
if
(
FAILED
(
hres
))
break
;
hres
=
json_quote
(
ctx
,
prop_name
,
SysStringLen
(
prop_name
));
SysFreeString
(
prop_name
);
if
(
FAILED
(
hres
))
break
;
if
(
!
append_char
(
ctx
,
':'
)
||
(
*
ctx
->
gap
&&
!
append_char
(
ctx
,
' '
)))
{
hres
=
E_OUTOFMEMORY
;
break
;
}
hres
=
stringify
(
ctx
,
val
);
if
(
FAILED
(
hres
))
break
;
if
(
hres
==
S_FALSE
)
{
ctx
->
buf_len
=
stepback
;
continue
;
}
prop_cnt
++
;
}
jsval_release
(
val
);
if
(
FAILED
(
hres
))
return
hres
;
if
(
prop_cnt
&&
*
ctx
->
gap
)
{
if
(
!
append_char
(
ctx
,
'\n'
))
return
E_OUTOFMEMORY
;
for
(
i
=
1
;
i
<
ctx
->
stack_top
;
i
++
)
{
if
(
!
append_string
(
ctx
,
ctx
->
gap
))
{
hres
=
E_OUTOFMEMORY
;
break
;
}
}
}
if
(
!
append_char
(
ctx
,
'}'
))
return
E_OUTOFMEMORY
;
stringify_pop_obj
(
ctx
);
return
S_OK
;
}
/* ECMA-262 5.1 Edition 15.12.3 (abstract operation Str) */
static
HRESULT
stringify
(
stringify_ctx_t
*
ctx
,
jsval_t
val
)
{
jsval_t
value
;
HRESULT
hres
;
if
(
is_object_instance
(
val
)
&&
get_object
(
val
))
{
jsdisp_t
*
obj
;
DISPID
id
;
obj
=
iface_to_jsdisp
((
IUnknown
*
)
get_object
(
val
));
if
(
!
obj
)
return
S_FALSE
;
hres
=
jsdisp_get_id
(
obj
,
toJSONW
,
0
,
&
id
);
jsdisp_release
(
obj
);
if
(
hres
==
S_OK
)
FIXME
(
"Use toJSON.
\n
"
);
}
/* FIXME: Support replacer replacer. */
hres
=
maybe_to_primitive
(
ctx
->
ctx
,
val
,
&
value
);
if
(
FAILED
(
hres
))
return
hres
;
switch
(
jsval_type
(
value
))
{
case
JSV_NULL
:
if
(
!
append_string
(
ctx
,
nullW
))
hres
=
E_OUTOFMEMORY
;
break
;
case
JSV_BOOL
:
if
(
!
append_string
(
ctx
,
get_bool
(
value
)
?
trueW
:
falseW
))
hres
=
E_OUTOFMEMORY
;
break
;
case
JSV_STRING
:
{
jsstr_t
*
str
=
get_string
(
value
);
const
WCHAR
*
ptr
=
jsstr_flatten
(
str
);
if
(
ptr
)
hres
=
json_quote
(
ctx
,
ptr
,
jsstr_length
(
str
));
else
hres
=
E_OUTOFMEMORY
;
break
;
}
case
JSV_NUMBER
:
{
double
n
=
get_number
(
value
);
if
(
is_finite
(
n
))
{
const
WCHAR
*
ptr
;
jsstr_t
*
str
;
/* FIXME: Optimize. There is no need for jsstr_t here. */
hres
=
double_to_string
(
n
,
&
str
);
if
(
FAILED
(
hres
))
break
;
ptr
=
jsstr_flatten
(
str
);
assert
(
ptr
!=
NULL
);
hres
=
ptr
&&
!
append_string_len
(
ctx
,
ptr
,
jsstr_length
(
str
))
?
E_OUTOFMEMORY
:
S_OK
;
jsstr_release
(
str
);
}
else
{
if
(
!
append_string
(
ctx
,
nullW
))
hres
=
E_OUTOFMEMORY
;
}
break
;
}
case
JSV_OBJECT
:
{
jsdisp_t
*
obj
;
obj
=
iface_to_jsdisp
((
IUnknown
*
)
get_object
(
value
));
if
(
!
obj
)
{
hres
=
S_FALSE
;
break
;
}
if
(
!
is_callable
(
obj
))
hres
=
is_class
(
obj
,
JSCLASS_ARRAY
)
?
stringify_array
(
ctx
,
obj
)
:
stringify_object
(
ctx
,
obj
);
else
hres
=
S_FALSE
;
jsdisp_release
(
obj
);
break
;
}
case
JSV_UNDEFINED
:
hres
=
S_FALSE
;
break
;
case
JSV_VARIANT
:
FIXME
(
"VARIANT
\n
"
);
hres
=
E_NOTIMPL
;
break
;
}
jsval_release
(
value
);
return
hres
;
}
/* 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
)
{
FIXME
(
"
\n
"
);
return
E_NOTIMPL
;
stringify_ctx_t
stringify_ctx
=
{
ctx
,
NULL
,
0
,
0
,
NULL
,
0
,
0
,
{
0
}};
HRESULT
hres
;
TRACE
(
"
\n
"
);
if
(
argc
>=
2
&&
is_object_instance
(
argv
[
1
]))
{
FIXME
(
"Replacer %s not yet supported
\n
"
,
debugstr_jsval
(
argv
[
1
]));
return
E_NOTIMPL
;
}
if
(
argc
>=
3
)
{
jsval_t
space_val
;
hres
=
maybe_to_primitive
(
ctx
,
argv
[
2
],
&
space_val
);
if
(
FAILED
(
hres
))
return
hres
;
if
(
is_number
(
space_val
))
{
double
n
=
get_number
(
space_val
);
if
(
n
>=
1
)
{
int
i
,
len
;
if
(
n
>
10
)
n
=
10
;
len
=
floor
(
n
);
for
(
i
=
0
;
i
<
len
;
i
++
)
stringify_ctx
.
gap
[
i
]
=
' '
;
stringify_ctx
.
gap
[
len
]
=
0
;
}
}
else
if
(
is_string
(
space_val
))
{
jsstr_t
*
space_str
=
get_string
(
space_val
);
size_t
len
=
jsstr_length
(
space_str
);
if
(
len
>
10
)
len
=
10
;
jsstr_extract
(
space_str
,
0
,
len
,
stringify_ctx
.
gap
);
}
jsval_release
(
space_val
);
}
hres
=
stringify
(
&
stringify_ctx
,
argv
[
0
]);
if
(
SUCCEEDED
(
hres
)
&&
r
)
{
assert
(
!
stringify_ctx
.
stack_top
);
if
(
hres
==
S_OK
)
{
jsstr_t
*
ret
=
jsstr_alloc_len
(
stringify_ctx
.
buf
,
stringify_ctx
.
buf_len
);
if
(
ret
)
*
r
=
jsval_string
(
ret
);
else
hres
=
E_OUTOFMEMORY
;
}
else
{
*
r
=
jsval_undefined
();
}
}
heap_free
(
stringify_ctx
.
buf
);
heap_free
(
stringify_ctx
.
stack
);
return
hres
;
}
static
const
builtin_prop_t
JSON_props
[]
=
{
...
...
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