[0.4.9][JSCRIPT] Fix regression CORE-13810 "Vypress Chat 2.1.9 MSI setup fatal error"

The regression was unhidden by MSI-winesync 1.5.10 almost 7years ago:
8939969e21 == SVN r57070

Finally we can fix it by adding MS enumerator extension to Jscript.
Many thanks to the patches author
Andreas Maier <staubim@quantentunnel.de>
JIRA-nick: andy-123

fix picked from commit 0.4.12-RC-18-g 9ebb42a4c0

It went afterwards into master in slightly modified form as 0.4.13-dev-890-g 83dcae1
But I decided to take the older state from 0.4.12RC, so that I do not have to risk
touching releases/0.4.12 again to sync to "latest&greatest".

Due to the changed PROPF_* defines in jscript.h, I felt most safe by porting back also:
0.4.10-dev-188-g c6f49f5
0.4.10-dev-152-g 3f071cc
This commit is contained in:
Joachim Henze 2019-05-17 00:47:16 +02:00
parent ead395d3ae
commit a15d6418cf
20 changed files with 2307 additions and 1066 deletions

View file

@ -16,6 +16,7 @@ list(APPEND SOURCE
decode.c
dispex.c
engine.c
enumerator.c
error.c
function.c
global.c

View file

@ -49,6 +49,7 @@ typedef struct {
static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
static const WCHAR toISOStringW[] = {'t','o','I','S','O','S','t','r','i','n','g',0};
static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0};
static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
@ -632,6 +633,52 @@ static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag
return S_OK;
}
static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
DateInstance *date;
WCHAR buf[64], *p = buf;
double year;
static const WCHAR short_year_formatW[] = {'%','0','4','d',0};
static const WCHAR long_year_formatW[] = {'%','0','6','d',0};
static const WCHAR formatW[] = {'-','%','0','2','d','-','%','0','2','d',
'T','%','0','2','d',':','%','0','2','d',':','%','0','2','d','.','%','0','3','d','Z',0};
TRACE("\n");
if(!(date = date_this(jsthis)))
return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
year = year_from_time(date->time);
if(isnan(year) || year > 999999 || year < -999999) {
FIXME("year %lf should throw an exception\n", year);
return E_FAIL;
}
if(year < 0) {
*p++ = '-';
p += sprintfW(p, long_year_formatW, -(int)year);
}else if(year > 9999) {
*p++ = '+';
p += sprintfW(p, long_year_formatW, (int)year);
}else {
p += sprintfW(p, short_year_formatW, (int)year);
}
sprintfW(p, formatW, (int)month_from_time(date->time) + 1, (int)date_from_time(date->time),
(int)hour_from_time(date->time), (int)min_from_time(date->time),
(int)sec_from_time(date->time), (int)ms_from_time(date->time));
if(r) {
jsstr_t *ret;
if(!(ret = jsstr_alloc(buf)))
return E_OUTOFMEMORY;
*r = jsval_string(ret);
}
return S_OK;
}
static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -1923,6 +1970,7 @@ static const builtin_prop_t Date_props[] = {
{setYearW, Date_setYear, PROPF_METHOD|1},
{toDateStringW, Date_toDateString, PROPF_METHOD},
{toGMTStringW, Date_toGMTString, PROPF_METHOD},
{toISOStringW, Date_toISOString, PROPF_METHOD|PROPF_ES5},
{toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD},
{toLocaleStringW, Date_toLocaleString, PROPF_METHOD},
{toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD},

View file

@ -32,6 +32,7 @@ typedef enum {
PROP_JSVAL,
PROP_BUILTIN,
PROP_PROTREF,
PROP_ACCESSOR,
PROP_DELETED,
PROP_IDX
} prop_type_t;
@ -47,6 +48,10 @@ struct _dispex_prop_t {
const builtin_prop_t *p;
DWORD ref;
unsigned idx;
struct {
jsdisp_t *getter;
jsdisp_t *setter;
} accessor;
} u;
int bucket_head;
@ -216,7 +221,13 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
builtin = find_builtin_prop(This, name);
if(builtin) {
prop = alloc_prop(This, name, PROP_BUILTIN, builtin->flags);
unsigned flags = builtin->flags;
if(flags & PROPF_METHOD)
flags |= PROPF_WRITABLE | PROPF_CONFIGURABLE;
else if(builtin->setter)
flags |= PROPF_WRITABLE;
flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE;
prop = alloc_prop(This, name, PROP_BUILTIN, flags);
if(!prop)
return E_OUTOFMEMORY;
@ -232,7 +243,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
for(ptr = name; isdigitW(*ptr) && idx < 0x10000; ptr++)
idx = idx*10 + (*ptr-'0');
if(!*ptr && idx < This->builtin_info->idx_length(This)) {
prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? 0 : PROPF_CONST);
prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? PROPF_WRITABLE : 0);
if(!prop)
return E_OUTOFMEMORY;
@ -268,7 +279,6 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n
if(prop) {
if(del) {
del->type = PROP_PROTREF;
del->flags = 0;
del->u.ref = prop - This->prototype->props;
prop = del;
}else {
@ -286,15 +296,12 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n
return S_OK;
}
static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, dispex_prop_t **ret)
{
dispex_prop_t *prop;
HRESULT hres;
if(search_prot)
hres = find_prop_name_prot(This, string_hash(name), name, &prop);
else
hres = find_prop_name(This, string_hash(name), name, &prop);
hres = find_prop_name_prot(This, string_hash(name), name, &prop);
if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags);
@ -408,6 +415,9 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
}
case PROP_ACCESSOR:
FIXME("accessor\n");
return E_NOTIMPL;
case PROP_IDX:
FIXME("Invoking PROP_IDX not yet supported\n");
return E_NOTIMPL;
@ -419,11 +429,16 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
return E_FAIL;
}
static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
jsval_t *r, IServiceProvider *caller)
static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r)
{
jsdisp_t *prop_obj = This;
HRESULT hres;
while(prop->type == PROP_PROTREF) {
prop_obj = prop_obj->prototype;
prop = prop_obj->props + prop->u.ref;
}
switch(prop->type) {
case PROP_BUILTIN:
if(prop->u.p->getter) {
@ -444,14 +459,20 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
*r = jsval_obj(obj);
}
break;
case PROP_PROTREF:
hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, r, caller);
break;
case PROP_JSVAL:
hres = jsval_copy(prop->u.val, r);
break;
case PROP_ACCESSOR:
if(prop->u.accessor.getter) {
hres = jsdisp_call_value(prop->u.accessor.getter, to_disp(This),
DISPATCH_METHOD, 0, NULL, r);
}else {
*r = jsval_undefined();
hres = S_OK;
}
break;
case PROP_IDX:
hres = This->builtin_info->idx_get(This, prop->u.idx, r);
hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r);
break;
default:
ERR("type %d\n", prop->type);
@ -467,32 +488,53 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
return hres;
}
static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller)
static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val)
{
HRESULT hres;
if(prop->flags & PROPF_CONST)
return S_OK;
if(prop->type == PROP_PROTREF) {
dispex_prop_t *prop_iter = prop;
jsdisp_t *prototype_iter = This;
do {
prototype_iter = prototype_iter->prototype;
prop_iter = prototype_iter->props + prop_iter->u.ref;
} while(prop_iter->type == PROP_PROTREF);
if(prop_iter->type == PROP_ACCESSOR)
prop = prop_iter;
}
switch(prop->type) {
case PROP_BUILTIN:
if(prop->u.p->setter)
return prop->u.p->setter(This->ctx, This, val);
if(prop->u.p->setter) {
FIXME("getter with no setter\n");
return E_FAIL;
if(!prop->u.p->setter) {
TRACE("getter with no setter\n");
return S_OK;
}
/* fall through */
return prop->u.p->setter(This->ctx, This, val);
case PROP_PROTREF:
case PROP_DELETED:
prop->type = PROP_JSVAL;
prop->flags = PROPF_ENUM;
prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE;
prop->u.val = jsval_undefined();
break;
case PROP_JSVAL:
if(!(prop->flags & PROPF_WRITABLE))
return S_OK;
jsval_release(prop->u.val);
break;
case PROP_ACCESSOR:
if(!prop->u.accessor.setter) {
TRACE("no setter\n");
return S_OK;
}
return jsdisp_call_value(prop->u.accessor.setter, to_disp(This), DISPATCH_METHOD, 1, &val, NULL);
case PROP_IDX:
if(!This->builtin_info->idx_put) {
TRACE("no put_idx\n");
return S_OK;
}
return This->builtin_info->idx_put(This, prop->u.idx, val);
default:
ERR("type %d\n", prop->type);
@ -704,7 +746,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
case DISPATCH_PROPERTYGET: {
jsval_t r;
hres = prop_get(This, prop, pdp, &r, pspCaller);
hres = prop_get(This, prop, &r);
if(SUCCEEDED(hres)) {
hres = jsval_to_variant(r, pvarRes);
jsval_release(r);
@ -729,7 +771,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
if(FAILED(hres))
return hres;
hres = prop_put(This, prop, val, pspCaller);
hres = prop_put(This, prop, val);
jsval_release(val);
break;
}
@ -745,7 +787,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
{
if(prop->flags & PROPF_DONTDELETE) {
if(!(prop->flags & PROPF_CONFIGURABLE)) {
*ret = FALSE;
return S_OK;
}
@ -756,6 +798,8 @@ static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
jsval_release(prop->u.val);
prop->type = PROP_DELETED;
}
if(prop->type == PROP_ACCESSOR)
FIXME("not supported on accessor property\n");
return S_OK;
}
@ -846,7 +890,7 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex,
}
while(iter < This->props + This->prop_cnt) {
if(iter->name && (get_flags(This, iter) & PROPF_ENUM) && iter->type!=PROP_DELETED) {
if(iter->name && (get_flags(This, iter) & PROPF_ENUMERABLE) && iter->type!=PROP_DELETED) {
*pid = prop_to_id(This, iter);
return S_OK;
}
@ -957,8 +1001,19 @@ void jsdisp_free(jsdisp_t *obj)
TRACE("(%p)\n", obj);
for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
if(prop->type == PROP_JSVAL)
switch(prop->type) {
case PROP_JSVAL:
jsval_release(prop->u.val);
break;
case PROP_ACCESSOR:
if(prop->u.accessor.getter)
jsdisp_release(prop->u.accessor.getter);
if(prop->u.accessor.setter)
jsdisp_release(prop->u.accessor.setter);
break;
default:
break;
};
heap_free(prop->name);
}
heap_free(obj->props);
@ -1005,7 +1060,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
jsval_t val;
hres = prop_get(constr, prop, NULL, &val, NULL);
hres = prop_get(constr, prop, &val);
if(FAILED(hres)) {
ERR("Could not get prototype\n");
return hres;
@ -1036,7 +1091,8 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *
HRESULT hres;
if(flags & fdexNameEnsure)
hres = ensure_prop_name(jsdisp, name, TRUE, PROPF_ENUM, &prop);
hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE,
&prop);
else
hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
if(FAILED(hres))
@ -1299,33 +1355,16 @@ HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, jsval_t va
dispex_prop_t *prop;
HRESULT hres;
hres = ensure_prop_name(obj, name, FALSE, flags, &prop);
hres = ensure_prop_name(obj, name, flags, &prop);
if(FAILED(hres))
return hres;
return prop_put(obj, prop, val, NULL);
return prop_put(obj, prop, val);
}
HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
{
return jsdisp_propput(obj, name, PROPF_ENUM, val);
}
HRESULT jsdisp_propput_const(jsdisp_t *obj, const WCHAR *name, jsval_t val)
{
dispex_prop_t *prop;
HRESULT hres;
hres = ensure_prop_name(obj, name, FALSE, PROPF_CONST, &prop);
if(FAILED(hres))
return hres;
return jsval_copy(val, &prop->u.val);
}
HRESULT jsdisp_propput_dontenum(jsdisp_t *obj, const WCHAR *name, jsval_t val)
{
return jsdisp_propput(obj, name, 0, val);
return jsdisp_propput(obj, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, val);
}
HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
@ -1349,7 +1388,7 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
prop = get_prop(jsdisp, id);
if(prop)
hres = prop_put(jsdisp, prop, val, NULL);
hres = prop_put(jsdisp, prop, val);
else
hres = DISP_E_MEMBERNOTFOUND;
@ -1389,7 +1428,6 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
{
DISPPARAMS dp = {NULL, NULL, 0, 0};
dispex_prop_t *prop;
HRESULT hres;
@ -1402,13 +1440,12 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
return S_OK;
}
return prop_get(obj, prop, &dp, val, NULL);
return prop_get(obj, prop, val);
}
HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
{
WCHAR name[12];
DISPPARAMS dp = {NULL, NULL, 0, 0};
dispex_prop_t *prop;
HRESULT hres;
@ -1425,19 +1462,18 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
return DISP_E_UNKNOWNNAME;
}
return prop_get(obj, prop, &dp, r, NULL);
return prop_get(obj, prop, r);
}
HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
{
DISPPARAMS dp = {NULL,NULL,0,0};
dispex_prop_t *prop;
prop = get_prop(jsdisp, id);
if(!prop)
return DISP_E_MEMBERNOTFOUND;
return prop_get(jsdisp, prop, &dp, val, NULL);
return prop_get(jsdisp, prop, val);
}
HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
@ -1587,7 +1623,8 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL
return hres;
}
HRESULT jsdisp_is_own_prop(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only,
property_desc_t *desc)
{
dispex_prop_t *prop;
HRESULT hres;
@ -1596,11 +1633,41 @@ HRESULT jsdisp_is_own_prop(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
if(FAILED(hres))
return hres;
*ret = prop && (prop->type == PROP_JSVAL || prop->type == PROP_BUILTIN);
if(!prop)
return DISP_E_UNKNOWNNAME;
memset(desc, 0, sizeof(*desc));
switch(prop->type) {
case PROP_BUILTIN:
case PROP_JSVAL:
desc->mask |= PROPF_WRITABLE;
desc->explicit_value = TRUE;
if(!flags_only) {
hres = prop_get(obj, prop, &desc->value);
if(FAILED(hres))
return hres;
}
break;
case PROP_ACCESSOR:
desc->explicit_getter = desc->explicit_setter = TRUE;
if(!flags_only) {
desc->getter = prop->u.accessor.getter
? jsdisp_addref(prop->u.accessor.getter) : NULL;
desc->setter = prop->u.accessor.setter
? jsdisp_addref(prop->u.accessor.setter) : NULL;
}
break;
default:
return DISP_E_UNKNOWNNAME;
}
desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE);
desc->mask |= PROPF_ENUMERABLE | PROPF_CONFIGURABLE;
return S_OK;
}
HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc)
{
dispex_prop_t *prop;
HRESULT hres;
@ -1609,6 +1676,124 @@ HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
if(FAILED(hres))
return hres;
*ret = prop && (prop->flags & PROPF_ENUM) && prop->type != PROP_PROTREF;
if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0)))
return E_OUTOFMEMORY;
if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) {
prop->flags = desc->flags;
if(desc->explicit_getter || desc->explicit_setter) {
prop->type = PROP_ACCESSOR;
prop->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL;
prop->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL;
TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name),
prop->u.accessor.getter, prop->u.accessor.setter);
}else {
prop->type = PROP_JSVAL;
if(desc->explicit_value) {
hres = jsval_copy(desc->value, &prop->u.val);
if(FAILED(hres))
return hres;
}else {
prop->u.val = jsval_undefined();
}
TRACE("%s = %s\n", debugstr_w(name), debugstr_jsval(prop->u.val));
}
return S_OK;
}
TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name),
prop->flags, desc->flags, desc->mask);
if(!(prop->flags & PROPF_CONFIGURABLE)) {
if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE))
|| ((desc->mask & PROPF_ENUMERABLE)
&& ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE))))
return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
}
if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) {
if(prop->type == PROP_ACCESSOR) {
if(!(prop->flags & PROPF_CONFIGURABLE))
return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
if(prop->u.accessor.getter)
jsdisp_release(prop->u.accessor.getter);
if(prop->u.accessor.setter)
jsdisp_release(prop->u.accessor.setter);
prop->type = PROP_JSVAL;
hres = jsval_copy(desc->value, &prop->u.val);
if(FAILED(hres)) {
prop->u.val = jsval_undefined();
return hres;
}
}else {
if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) {
if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE))
return throw_type_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
if(desc->explicit_value) {
if(prop->type == PROP_JSVAL) {
BOOL eq;
hres = jsval_strict_equal(desc->value, prop->u.val, &eq);
if(FAILED(hres))
return hres;
if(!eq)
return throw_type_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
}else {
FIXME("redefinition of property type %d\n", prop->type);
}
}
}
if(desc->explicit_value) {
if(prop->type == PROP_JSVAL)
jsval_release(prop->u.val);
else
prop->type = PROP_JSVAL;
hres = jsval_copy(desc->value, &prop->u.val);
if(FAILED(hres)) {
prop->u.val = jsval_undefined();
return hres;
}
}
}
}else if(desc->explicit_getter || desc->explicit_setter) {
if(prop->type != PROP_ACCESSOR) {
if(!(prop->flags & PROPF_CONFIGURABLE))
return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
if(prop->type == PROP_JSVAL)
jsval_release(prop->u.val);
prop->type = PROP_ACCESSOR;
prop->u.accessor.getter = prop->u.accessor.setter = NULL;
}else if(!(prop->flags & PROPF_CONFIGURABLE)) {
if((desc->explicit_getter && desc->getter != prop->u.accessor.getter)
|| (desc->explicit_setter && desc->setter != prop->u.accessor.setter))
return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
}
if(desc->explicit_getter) {
if(prop->u.accessor.getter) {
jsdisp_release(prop->u.accessor.getter);
prop->u.accessor.getter = NULL;
}
if(desc->getter)
prop->u.accessor.getter = jsdisp_addref(desc->getter);
}
if(desc->explicit_setter) {
if(prop->u.accessor.setter) {
jsdisp_release(prop->u.accessor.setter);
prop->u.accessor.setter = NULL;
}
if(desc->setter)
prop->u.accessor.setter = jsdisp_addref(desc->setter);
}
}
prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask);
return S_OK;
}
HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned flags, jsval_t value)
{
property_desc_t prop_desc = { flags, flags, TRUE };
prop_desc.value = value;
return jsdisp_define_property(obj, name, &prop_desc);
}

View file

@ -0,0 +1,363 @@
/*
* Copyright 2019 Andreas Maier
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include "jscript.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
typedef struct {
jsdisp_t dispex;
/* IEnumVARIANT returned by _NewEnum */
IEnumVARIANT *enumvar;
/* current item */
jsval_t item;
BOOL atend;
} EnumeratorInstance;
static const WCHAR atEndW[] = {'a','t','E','n','d',0};
static const WCHAR itemW[] = {'i','t','e','m',0};
static const WCHAR moveFirstW[] = {'m','o','v','e','F','i','r','s','t',0};
static const WCHAR moveNextW[] = {'m','o','v','e','N','e','x','t',0};
static inline EnumeratorInstance *enumerator_from_jsdisp(jsdisp_t *jsdisp)
{
return CONTAINING_RECORD(jsdisp, EnumeratorInstance, dispex);
}
static inline EnumeratorInstance *enumerator_from_vdisp(vdisp_t *vdisp)
{
return enumerator_from_jsdisp(vdisp->u.jsdisp);
}
static inline EnumeratorInstance *enumerator_this(vdisp_t *jsthis)
{
return is_vclass(jsthis, JSCLASS_ENUMERATOR) ? enumerator_from_vdisp(jsthis) : NULL;
}
static inline HRESULT enumvar_get_next_item(EnumeratorInstance *This)
{
HRESULT hres;
VARIANT nextitem;
if (This->atend)
return S_OK;
/* dont leak pervious value */
jsval_release(This->item);
/* not at end ... get next item */
VariantInit(&nextitem);
hres = IEnumVARIANT_Next(This->enumvar, 1, &nextitem, NULL);
if (hres == S_OK)
{
hres = variant_to_jsval(&nextitem, &This->item);
if (FAILED(hres))
{
WARN("failed to convert jsval to variant!");
This->item = jsval_undefined();
}
}
else
{
This->item = jsval_undefined();
This->atend = TRUE;
}
VariantClear(&nextitem);
return S_OK;
}
static void Enumerator_destructor(jsdisp_t *dispex)
{
EnumeratorInstance *This = enumerator_from_jsdisp(dispex);
TRACE("\n");
jsval_release(This->item);
heap_free(dispex);
}
static HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
EnumeratorInstance *This;
if (!(This = enumerator_this(jsthis)))
return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL);
if (r)
*r = jsval_bool(This->atend);
TRACE("%d\n", This->atend);
return S_OK;
}
static HRESULT Enumerator_item(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
EnumeratorInstance *This;
TRACE("\n");
if (!(This = enumerator_this(jsthis)))
return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL);
return r ? jsval_copy(This->item, r) : S_OK;
}
static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
EnumeratorInstance *This;
HRESULT hres = S_OK;
TRACE("\n");
if (!(This = enumerator_this(jsthis)))
return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL);
if (This->enumvar)
{
This->atend = FALSE;
hres = IEnumVARIANT_Reset(This->enumvar);
if (!FAILED(hres))
hres = enumvar_get_next_item(This);
}
if (r)
*r = jsval_undefined();
return hres;
}
static HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
EnumeratorInstance *This;
HRESULT hres = S_OK;
TRACE("\n");
if (!(This = enumerator_this(jsthis)))
return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL);
if (This->enumvar)
hres = enumvar_get_next_item(This);
if (r)
*r = jsval_undefined();
return hres;
}
static const builtin_prop_t Enumerator_props[] = {
{atEndW, Enumerator_atEnd, PROPF_METHOD},
{itemW, Enumerator_item, PROPF_METHOD},
{moveFirstW, Enumerator_moveFirst, PROPF_METHOD},
{moveNextW, Enumerator_moveNext, PROPF_METHOD},
};
static const builtin_info_t Enumerator_info = {
JSCLASS_ENUMERATOR,
{NULL, NULL, 0},
(sizeof(Enumerator_props) / sizeof(Enumerator_props[0])),
Enumerator_props,
NULL,
NULL
};
static const builtin_info_t EnumeratorInst_info = {
JSCLASS_ENUMERATOR,
{NULL, NULL, 0, NULL},
0,
NULL,
Enumerator_destructor,
NULL
};
static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
jsdisp_t *obj;
jsval_t *arg0;
HRESULT hres;
TRACE("\n");
switch(flags) {
case DISPATCH_CONSTRUCT: {
if (argc > 1)
return throw_syntax_error(ctx, JS_E_INVALIDARG, NULL);
arg0 = (argc == 1) ? &argv[0] : 0;
hres = create_enumerator(ctx, arg0, &obj);
if(FAILED(hres))
return hres;
*r = jsval_obj(obj);
break;
}
default:
FIXME("unimplemented flags: %x\n", flags);
return E_NOTIMPL;
}
return S_OK;
}
static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret)
{
EnumeratorInstance *enumerator;
HRESULT hres;
enumerator = heap_alloc_zero(sizeof(EnumeratorInstance));
if(!enumerator)
return E_OUTOFMEMORY;
if(object_prototype)
hres = init_dispex(&enumerator->dispex, ctx, &Enumerator_info, object_prototype);
else
hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info,
ctx->enumerator_constr);
if(FAILED(hres))
{
heap_free(enumerator);
return hres;
}
*ret = enumerator;
return S_OK;
}
static const builtin_info_t EnumeratorConstr_info = {
JSCLASS_FUNCTION,
DEFAULT_FUNCTION_VALUE,
0,
NULL,
NULL,
NULL
};
HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
{
EnumeratorInstance *enumerator;
HRESULT hres;
static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
hres = alloc_enumerator(ctx, object_prototype, &enumerator);
if(FAILED(hres))
return hres;
hres = create_builtin_constructor(ctx, EnumeratorConstr_value,
EnumeratorW, &EnumeratorConstr_info,
PROPF_CONSTR|7, &enumerator->dispex, ret);
jsdisp_release(&enumerator->dispex);
return hres;
}
HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret)
{
EnumeratorInstance *enumerator;
HRESULT hres;
IDispatch *obj;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT varresult;
BOOL atend;
IEnumVARIANT *enumvar;
memset(&varresult, 0, sizeof(VARIANT));
VariantInit(&varresult);
/* new Enumerator() */
if (argv == NULL)
{
enumvar = NULL;
atend = TRUE;
}
else if (is_object_instance(*argv))
{
obj = get_object(*argv);
/* Try to get a IEnumVARIANT by _NewEnum */
hres = IDispatch_Invoke(obj,
DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, &varresult,
NULL, NULL);
if (FAILED(hres))
{
WARN("Enumerator: no DISPID_NEWENUM.\n");
hres = E_INVALIDARG;
goto cleanuperr;
}
if ((V_VT(&varresult) == VT_DISPATCH) ||
(V_VT(&varresult) == VT_UNKNOWN))
{
hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult),
&IID_IEnumVARIANT, (void**)&enumvar);
if (FAILED(hres))
{
hres = E_INVALIDARG;
goto cleanuperr;
}
}
else
{
FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult));
hres = E_INVALIDARG;
goto cleanuperr;
}
VariantClear(&varresult);
atend = FALSE;
}
else
{
FIXME("I don't know how to handle this type!\n");
hres = E_NOTIMPL;
goto cleanuperr;
}
hres = alloc_enumerator(ctx, NULL, &enumerator);
if(FAILED(hres))
goto cleanuperr;
enumerator->atend = atend;
enumerator->enumvar = enumvar;
hres = enumvar_get_next_item(enumerator);
if (FAILED(hres))
goto cleanuperr;
*ret = &enumerator->dispex;
return S_OK;
cleanuperr:
VariantClear(&varresult);
if (enumerator)
heap_free(enumerator);
return hres;
}

View file

@ -193,15 +193,19 @@ static HRESULT create_error(script_ctx_t *ctx, jsdisp_t *constr,
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(err, numberW, jsval_number((INT)number));
hres = jsdisp_define_data_property(err, numberW, PROPF_WRITABLE | PROPF_CONFIGURABLE,
jsval_number((INT)number));
if(FAILED(hres)) {
jsdisp_release(err);
return hres;
}
hres = jsdisp_propput_name(err, messageW, jsval_string(msg));
hres = jsdisp_define_data_property(err, messageW,
PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE,
jsval_string(msg));
if(SUCCEEDED(hres))
hres = jsdisp_propput_dontenum(err, descriptionW, jsval_string(msg));
hres = jsdisp_define_data_property(err, descriptionW, PROPF_WRITABLE | PROPF_CONFIGURABLE,
jsval_string(msg));
if(FAILED(hres)) {
jsdisp_release(err);
return hres;
@ -355,7 +359,8 @@ HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
return E_OUTOFMEMORY;
}
hres = jsdisp_propput_dontenum(err, nameW, jsval_string(str));
hres = jsdisp_define_data_property(err, nameW, PROPF_WRITABLE | PROPF_CONFIGURABLE,
jsval_string(str));
jsstr_release(str);
if(SUCCEEDED(hres))
hres = create_builtin_constructor(ctx, constr_val[i], names[i], NULL,

View file

@ -180,11 +180,13 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame)
args->argc = frame->argc;
args->frame = frame;
hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(args->argc));
hres = jsdisp_define_data_property(&args->jsdisp, lengthW, PROPF_WRITABLE | PROPF_CONFIGURABLE,
jsval_number(args->argc));
if(SUCCEEDED(hres))
hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&args->function->dispex)));
hres = jsdisp_define_data_property(&args->jsdisp, caleeW, PROPF_WRITABLE | PROPF_CONFIGURABLE,
jsval_obj(&args->function->dispex));
if(SUCCEEDED(hres))
hres = jsdisp_propput(frame->base_scope->jsobj, argumentsW, PROPF_DONTDELETE, jsval_obj(&args->jsdisp));
hres = jsdisp_propput(frame->base_scope->jsobj, argumentsW, PROPF_WRITABLE, jsval_obj(&args->jsdisp));
if(FAILED(hres)) {
jsdisp_release(&args->jsdisp);
return hres;
@ -358,12 +360,6 @@ static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t
return S_OK;
}
static HRESULT Function_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -588,9 +584,9 @@ static void Function_destructor(jsdisp_t *dispex)
static const builtin_prop_t Function_props[] = {
{applyW, Function_apply, PROPF_METHOD|2},
{argumentsW, NULL, 0, Function_get_arguments, builtin_set_const},
{argumentsW, NULL, 0, Function_get_arguments},
{callW, Function_call, PROPF_METHOD|1},
{lengthW, NULL, 0, Function_get_length, Function_set_length},
{lengthW, NULL, 0, Function_get_length},
{toStringW, Function_toString, PROPF_METHOD}
};
@ -604,8 +600,8 @@ static const builtin_info_t Function_info = {
};
static const builtin_prop_t FunctionInst_props[] = {
{argumentsW, NULL, 0, Function_get_arguments, builtin_set_const},
{lengthW, NULL, 0, Function_get_length, Function_set_length}
{argumentsW, NULL, 0, Function_get_arguments},
{lengthW, NULL, 0, Function_get_length}
};
static const builtin_info_t FunctionInst_info = {
@ -645,11 +641,6 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_
return S_OK;
}
static inline HRESULT set_prototype(script_ctx_t *ctx, jsdisp_t *dispex, jsdisp_t *prototype)
{
return jsdisp_propput_dontenum(dispex, prototypeW, jsval_obj(prototype));
}
HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name,
const builtin_info_t *builtin_info, DWORD flags, jsdisp_t *prototype, jsdisp_t **ret)
{
@ -661,9 +652,10 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc,
return hres;
if(builtin_info)
hres = jsdisp_propput_const(&function->dispex, lengthW, jsval_number(function->length));
hres = jsdisp_define_data_property(&function->dispex, lengthW, 0,
jsval_number(function->length));
if(SUCCEEDED(hres))
hres = set_prototype(ctx, &function->dispex, prototype);
hres = jsdisp_define_data_property(&function->dispex, prototypeW, 0, jsval_obj(prototype));
if(FAILED(hres)) {
jsdisp_release(&function->dispex);
return hres;
@ -680,7 +672,8 @@ static HRESULT set_constructor_prop(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_
{
static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r',0};
return jsdisp_propput_dontenum(prot, constructorW, jsval_obj(constr));
return jsdisp_define_data_property(prot, constructorW, PROPF_WRITABLE | PROPF_CONFIGURABLE,
jsval_obj(constr));
}
HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name,
@ -716,7 +709,8 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod
hres = create_function(ctx, NULL, PROPF_CONSTR, FALSE, NULL, &function);
if(SUCCEEDED(hres)) {
hres = set_prototype(ctx, &function->dispex, prototype);
hres = jsdisp_define_data_property(&function->dispex, prototypeW, PROPF_WRITABLE,
jsval_obj(prototype));
if(SUCCEEDED(hres))
hres = set_constructor_prop(ctx, &function->dispex, prototype);
if(FAILED(hres))
@ -874,7 +868,7 @@ HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(SUCCEEDED(hres)) {
constr->value_proc = FunctionConstr_value;
constr->name = FunctionW;
hres = set_prototype(ctx, &constr->dispex, &prot->dispex);
hres = jsdisp_define_data_property(&constr->dispex, prototypeW, 0, jsval_obj(&prot->dispex));
if(SUCCEEDED(hres))
hres = set_constructor_prop(ctx, &constr->dispex, &prot->dispex);
if(FAILED(hres))

View file

@ -113,13 +113,6 @@ static WCHAR int_to_char(int i)
return 'A'+i-10;
}
static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -942,7 +935,6 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
static const builtin_prop_t JSGlobal_props[] = {
{CollectGarbageW, JSGlobal_CollectGarbage, PROPF_METHOD},
{EnumeratorW, JSGlobal_Enumerator, PROPF_METHOD|7},
{_GetObjectW, JSGlobal_GetObject, PROPF_METHOD|2},
{ScriptEngineW, JSGlobal_ScriptEngine, PROPF_METHOD},
{ScriptEngineBuildVersionW, JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD},
@ -978,7 +970,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, FunctionW, jsval_obj(ctx->function_constr));
hres = jsdisp_define_data_property(ctx->global, FunctionW, PROPF_WRITABLE,
jsval_obj(ctx->function_constr));
if(FAILED(hres))
return hres;
@ -986,7 +979,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, ObjectW, jsval_obj(ctx->object_constr));
hres = jsdisp_define_data_property(ctx->global, ObjectW, PROPF_WRITABLE,
jsval_obj(ctx->object_constr));
if(FAILED(hres))
return hres;
@ -994,7 +988,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, ArrayW, jsval_obj(ctx->array_constr));
hres = jsdisp_define_data_property(ctx->global, ArrayW, PROPF_WRITABLE,
jsval_obj(ctx->array_constr));
if(FAILED(hres))
return hres;
@ -1002,7 +997,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, BooleanW, jsval_obj(ctx->bool_constr));
hres = jsdisp_define_data_property(ctx->global, BooleanW, PROPF_WRITABLE,
jsval_obj(ctx->bool_constr));
if(FAILED(hres))
return hres;
@ -1010,7 +1006,17 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, DateW, jsval_obj(ctx->date_constr));
hres = jsdisp_define_data_property(ctx->global, DateW, PROPF_WRITABLE,
jsval_obj(ctx->date_constr));
if(FAILED(hres))
return hres;
hres = create_enumerator_constr(ctx, object_prototype, &ctx->enumerator_constr);
if(FAILED(hres))
return hres;
hres = jsdisp_define_data_property(ctx->global, EnumeratorW, PROPF_WRITABLE,
jsval_obj(ctx->enumerator_constr));
if(FAILED(hres))
return hres;
@ -1018,35 +1024,43 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, ErrorW, jsval_obj(ctx->error_constr));
hres = jsdisp_define_data_property(ctx->global, ErrorW, PROPF_WRITABLE,
jsval_obj(ctx->error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, EvalErrorW, jsval_obj(ctx->eval_error_constr));
hres = jsdisp_define_data_property(ctx->global, EvalErrorW, PROPF_WRITABLE,
jsval_obj(ctx->eval_error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, RangeErrorW, jsval_obj(ctx->range_error_constr));
hres = jsdisp_define_data_property(ctx->global, RangeErrorW, PROPF_WRITABLE,
jsval_obj(ctx->range_error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, ReferenceErrorW, jsval_obj(ctx->reference_error_constr));
hres = jsdisp_define_data_property(ctx->global, ReferenceErrorW, PROPF_WRITABLE,
jsval_obj(ctx->reference_error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, RegExpErrorW, jsval_obj(ctx->regexp_error_constr));
hres = jsdisp_define_data_property(ctx->global, RegExpErrorW, PROPF_WRITABLE,
jsval_obj(ctx->regexp_error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, SyntaxErrorW, jsval_obj(ctx->syntax_error_constr));
hres = jsdisp_define_data_property(ctx->global, SyntaxErrorW, PROPF_WRITABLE,
jsval_obj(ctx->syntax_error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, TypeErrorW, jsval_obj(ctx->type_error_constr));
hres = jsdisp_define_data_property(ctx->global, TypeErrorW, PROPF_WRITABLE,
jsval_obj(ctx->type_error_constr));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, URIErrorW, jsval_obj(ctx->uri_error_constr));
hres = jsdisp_define_data_property(ctx->global, URIErrorW, PROPF_WRITABLE,
jsval_obj(ctx->uri_error_constr));
if(FAILED(hres))
return hres;
@ -1054,7 +1068,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, NumberW, jsval_obj(ctx->number_constr));
hres = jsdisp_define_data_property(ctx->global, NumberW, PROPF_WRITABLE,
jsval_obj(ctx->number_constr));
if(FAILED(hres))
return hres;
@ -1062,7 +1077,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, RegExpW, jsval_obj(ctx->regexp_constr));
hres = jsdisp_define_data_property(ctx->global, RegExpW, PROPF_WRITABLE,
jsval_obj(ctx->regexp_constr));
if(FAILED(hres))
return hres;
@ -1070,7 +1086,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, StringW, jsval_obj(ctx->string_constr));
hres = jsdisp_define_data_property(ctx->global, StringW, PROPF_WRITABLE,
jsval_obj(ctx->string_constr));
if(FAILED(hres))
return hres;
@ -1078,7 +1095,8 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, VBArrayW, jsval_obj(ctx->vbarray_constr));
hres = jsdisp_define_data_property(ctx->global, VBArrayW, PROPF_WRITABLE,
jsval_obj(ctx->vbarray_constr));
if(FAILED(hres))
return hres;
@ -1087,6 +1105,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
HRESULT init_global(script_ctx_t *ctx)
{
unsigned const_flags = ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? 0 : PROPF_WRITABLE;
jsdisp_t *math, *object_prototype, *constr;
HRESULT hres;
@ -1110,7 +1129,7 @@ HRESULT init_global(script_ctx_t *ctx)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, MathW, jsval_obj(math));
hres = jsdisp_define_data_property(ctx->global, MathW, PROPF_WRITABLE, jsval_obj(math));
jsdisp_release(math);
if(FAILED(hres))
return hres;
@ -1122,7 +1141,7 @@ HRESULT init_global(script_ctx_t *ctx)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, JSONW, jsval_obj(json));
hres = jsdisp_define_data_property(ctx->global, JSONW, PROPF_WRITABLE, jsval_obj(json));
jsdisp_release(json);
if(FAILED(hres))
return hres;
@ -1132,19 +1151,20 @@ HRESULT init_global(script_ctx_t *ctx)
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, ActiveXObjectW, jsval_obj(constr));
hres = jsdisp_define_data_property(ctx->global, ActiveXObjectW, PROPF_WRITABLE,
jsval_obj(constr));
jsdisp_release(constr);
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, undefinedW, jsval_undefined());
hres = jsdisp_define_data_property(ctx->global, undefinedW, const_flags, jsval_undefined());
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, NaNW, jsval_number(NAN));
hres = jsdisp_define_data_property(ctx->global, NaNW, const_flags, jsval_number(NAN));
if(FAILED(hres))
return hres;
hres = jsdisp_propput_dontenum(ctx->global, InfinityW, jsval_number(INFINITY));
hres = jsdisp_define_data_property(ctx->global, InfinityW, const_flags, jsval_number(INFINITY));
return hres;
}

View file

@ -52,6 +52,7 @@ typedef struct _jsval_t jsval_t;
typedef struct _jsstr_t jsstr_t;
typedef struct _script_ctx_t script_ctx_t;
typedef struct _dispex_prop_t dispex_prop_t;
typedef struct _property_desc_t property_desc_t;
typedef struct {
void **blocks;
@ -89,12 +90,12 @@ typedef struct jsdisp_t jsdisp_t;
extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN;
#define PROPF_ARGMASK 0x00ff
#define PROPF_METHOD 0x0100
#define PROPF_ENUM 0x0200
#define PROPF_CONSTR 0x0400
#define PROPF_CONST 0x0800
#define PROPF_DONTDELETE 0x1000
#define PROPF_ARGMASK 0x00ff
#define PROPF_METHOD 0x0100
#define PROPF_ENUMERABLE 0x0200
#define PROPF_CONSTR 0x0400
#define PROPF_WRITABLE 0x0800
#define PROPF_CONFIGURABLE 0x1000
#define PROPF_VERSION_MASK 0x01ff0000
#define PROPF_VERSION_SHIFT 16
@ -115,6 +116,7 @@ typedef enum {
JSCLASS_ARRAY,
JSCLASS_BOOLEAN,
JSCLASS_DATE,
JSCLASS_ENUMERATOR,
JSCLASS_ERROR,
JSCLASS_FUNCTION,
JSCLASS_GLOBAL,
@ -285,8 +287,6 @@ HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propget(jsdisp_t*,DISPID,jsval_t*) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput(jsdisp_t*,const WCHAR*,DWORD,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput_name(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput_const(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput_dontenum(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propput_idx(jsdisp_t*,DWORD,jsval_t) DECLSPEC_HIDDEN;
HRESULT jsdisp_propget_name(jsdisp_t*,LPCWSTR,jsval_t*) DECLSPEC_HIDDEN;
HRESULT jsdisp_get_idx(jsdisp_t*,DWORD,jsval_t*) DECLSPEC_HIDDEN;
@ -294,8 +294,9 @@ HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*) DECLSPEC_HIDDEN;
HRESULT disp_delete(IDispatch*,DISPID,BOOL*) DECLSPEC_HIDDEN;
HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*) DECLSPEC_HIDDEN;
HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD) DECLSPEC_HIDDEN;
HRESULT jsdisp_is_own_prop(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
HRESULT jsdisp_is_enumerable(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
HRESULT jsdisp_get_own_property(jsdisp_t*,const WCHAR*,BOOL,property_desc_t*) DECLSPEC_HIDDEN;
HRESULT jsdisp_define_property(jsdisp_t*,const WCHAR*,property_desc_t*) DECLSPEC_HIDDEN;
HRESULT jsdisp_define_data_property(jsdisp_t*,const WCHAR*,unsigned,jsval_t) DECLSPEC_HIDDEN;
HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD,
jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
@ -326,6 +327,7 @@ HRESULT create_bool(script_ctx_t*,BOOL,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_number(script_ctx_t*,double,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_vbarray(script_ctx_t*,SAFEARRAY*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_json(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret) DECLSPEC_HIDDEN;
typedef enum {
NO_HINT,
@ -378,6 +380,17 @@ typedef struct {
#include "jsval.h"
struct _property_desc_t {
unsigned flags;
unsigned mask;
BOOL explicit_value;
jsval_t value;
BOOL explicit_getter;
jsdisp_t *getter;
BOOL explicit_setter;
jsdisp_t *setter;
};
typedef struct {
EXCEPINFO ei;
jsval_t val;
@ -424,6 +437,7 @@ struct _script_ctx_t {
jsdisp_t *array_constr;
jsdisp_t *bool_constr;
jsdisp_t *date_constr;
jsdisp_t *enumerator_constr;
jsdisp_t *error_constr;
jsdisp_t *eval_error_constr;
jsdisp_t *range_error_constr;
@ -456,6 +470,7 @@ HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_bool_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_date_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT init_error_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN;
HRESULT create_enumerator_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_number_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_object_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
HRESULT create_regexp_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN;
@ -546,6 +561,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags)
#define JS_E_VBARRAY_EXPECTED MAKE_JSERROR(IDS_NOT_VBARRAY)
#define JS_E_INVALID_DELETE MAKE_JSERROR(IDS_INVALID_DELETE)
#define JS_E_JSCRIPT_EXPECTED MAKE_JSERROR(IDS_JSCRIPT_EXPECTED)
#define JS_E_ENUMERATOR_EXPECTED MAKE_JSERROR(IDS_NOT_ENUMERATOR)
#define JS_E_REGEXP_SYNTAX MAKE_JSERROR(IDS_REGEXP_SYNTAX_ERROR)
#define JS_E_INVALID_URI_CODING MAKE_JSERROR(IDS_URI_INVALID_CODING)
#define JS_E_INVALID_URI_CHAR MAKE_JSERROR(IDS_URI_INVALID_CHAR)
@ -553,6 +569,10 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags)
#define JS_E_PRECISION_OUT_OF_RANGE MAKE_JSERROR(IDS_PRECISION_OUT_OF_RANGE)
#define JS_E_INVALID_LENGTH MAKE_JSERROR(IDS_INVALID_LENGTH)
#define JS_E_ARRAY_EXPECTED MAKE_JSERROR(IDS_ARRAY_EXPECTED)
#define JS_E_NONCONFIGURABLE_REDEFINED MAKE_JSERROR(IDS_NONCONFIGURABLE_REDEFINED)
#define JS_E_NONWRITABLE_MODIFIED MAKE_JSERROR(IDS_NONWRITABLE_MODIFIED)
#define JS_E_PROP_DESC_MISMATCH MAKE_JSERROR(IDS_PROP_DESC_MISMATCH)
#define JS_E_INVALID_WRITABLE_PROP_DESC MAKE_JSERROR(IDS_INVALID_WRITABLE_PROP_DESC)
static inline BOOL is_jscript_error(HRESULT hres)
{

View file

@ -768,6 +768,12 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un
TRACE("\n");
if(!argc) {
if(r)
*r = jsval_undefined();
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;

View file

@ -256,12 +256,6 @@ static HRESULT RegExp_get_source(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r
return S_OK;
}
static HRESULT RegExp_set_source(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT RegExp_get_global(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
{
TRACE("\n");
@ -270,12 +264,6 @@ static HRESULT RegExp_get_global(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r
return S_OK;
}
static HRESULT RegExp_set_global(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT RegExp_get_ignoreCase(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
{
TRACE("\n");
@ -284,12 +272,6 @@ static HRESULT RegExp_get_ignoreCase(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_
return S_OK;
}
static HRESULT RegExp_set_ignoreCase(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT RegExp_get_multiline(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
{
TRACE("\n");
@ -298,12 +280,6 @@ static HRESULT RegExp_get_multiline(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t
return S_OK;
}
static HRESULT RegExp_set_multiline(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
{
FIXME("\n");
return E_NOTIMPL;
}
static INT index_from_val(script_ctx_t *ctx, jsval_t v)
{
double n;
@ -607,11 +583,11 @@ static void RegExp_destructor(jsdisp_t *dispex)
static const builtin_prop_t RegExp_props[] = {
{execW, RegExp_exec, PROPF_METHOD|1},
{globalW, NULL,0, RegExp_get_global, RegExp_set_global},
{ignoreCaseW, NULL,0, RegExp_get_ignoreCase, RegExp_set_ignoreCase},
{globalW, NULL,0, RegExp_get_global},
{ignoreCaseW, NULL,0, RegExp_get_ignoreCase},
{lastIndexW, NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
{multilineW, NULL,0, RegExp_get_multiline, RegExp_set_multiline},
{sourceW, NULL,0, RegExp_get_source, RegExp_set_source},
{multilineW, NULL,0, RegExp_get_multiline},
{sourceW, NULL,0, RegExp_get_source},
{testW, RegExp_test, PROPF_METHOD|1},
{toStringW, RegExp_toString, PROPF_METHOD}
};
@ -626,11 +602,11 @@ static const builtin_info_t RegExp_info = {
};
static const builtin_prop_t RegExpInst_props[] = {
{globalW, NULL,0, RegExp_get_global, RegExp_set_global},
{ignoreCaseW, NULL,0, RegExp_get_ignoreCase, RegExp_set_ignoreCase},
{globalW, NULL,0, RegExp_get_global},
{ignoreCaseW, NULL,0, RegExp_get_ignoreCase},
{lastIndexW, NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex},
{multilineW, NULL,0, RegExp_get_multiline, RegExp_set_multiline},
{sourceW, NULL,0, RegExp_get_source, RegExp_set_source}
{multilineW, NULL,0, RegExp_get_multiline},
{sourceW, NULL,0, RegExp_get_source}
};
static const builtin_info_t RegExpInst_info = {

View file

@ -659,11 +659,18 @@ HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret)
double n;
HRESULT hres;
const double p32 = (double)0xffffffff + 1;
hres = to_number(ctx, v, &n);
if(FAILED(hres))
return hres;
*ret = is_finite(n) ? n : 0;
if(is_finite(n))
n = n > 0 ? fmod(n, p32) : -fmod(-n, p32);
else
n = 0;
*ret = (UINT32)n;
return S_OK;
}

View file

@ -135,7 +135,7 @@ static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lva
return 1;
if(lval)
*lval = ctx->ptr;
*lval = word;
ctx->ptr = p1;
return 0;
}
@ -487,18 +487,18 @@ static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret)
HRESULT hres;
if(*ctx->ptr == '0') {
LONG d, l = 0;
ctx->ptr++;
if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
double r = 0;
int d;
if(++ctx->ptr == ctx->end) {
ERR("unexpected end of file\n");
return FALSE;
}
while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
l = l*16 + d;
r = r*16 + d;
ctx->ptr++;
}
@ -508,7 +508,7 @@ static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret)
return FALSE;
}
*ret = l;
*ret = r;
return TRUE;
}

View file

@ -559,7 +559,8 @@ HRESULT create_math(script_ctx_t *ctx, jsdisp_t **ret)
}
for(i=0; i < sizeof(constants)/sizeof(*constants); i++) {
hres = jsdisp_propput_const(math, constants[i].name, jsval_number(constants[i].val));
hres = jsdisp_define_data_property(math, constants[i].name, 0,
jsval_number(constants[i].val));
if(FAILED(hres)) {
jsdisp_release(math);
return hres;

View file

@ -32,8 +32,21 @@ static const WCHAR propertyIsEnumerableW[] =
{'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
static const WCHAR getOwnPropertyDescriptorW[] =
{'g','e','t','O','w','n','P','r','o','p','e','r','t','y','D','e','s','c','r','i','p','t','o','r',0};
static const WCHAR definePropertyW[] = {'d','e','f','i','n','e','P','r','o','p','e','r','t','y',0};
static const WCHAR definePropertiesW[] = {'d','e','f','i','n','e','P','r','o','p','e','r','t','i','e','s',0};
static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0};
static const WCHAR configurableW[] = {'c','o','n','f','i','g','u','r','a','b','l','e',0};
static const WCHAR enumerableW[] = {'e','n','u','m','e','r','a','b','l','e',0};
static const WCHAR valueW[] = {'v','a','l','u','e',0};
static const WCHAR writableW[] = {'w','r','i','t','a','b','l','e',0};
static const WCHAR getW[] = {'g','e','t',0};
static const WCHAR setW[] = {'s','e','t',0};
static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -53,7 +66,7 @@ static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u
static const WCHAR regexpW[] = {'R','e','g','E','x','p',0};
static const WCHAR stringW[] = {'S','t','r','i','n','g',0};
/* Keep in sync with jsclass_t enum */
static const WCHAR *names[] = {NULL, arrayW, booleanW, dateW, errorW,
static const WCHAR *names[] = {NULL, arrayW, booleanW, dateW, objectW, errorW,
functionW, NULL, mathW, numberW, objectW, regexpW, stringW, objectW, objectW, objectW};
TRACE("\n");
@ -130,20 +143,21 @@ static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD fl
return hres;
if(is_jsdisp(jsthis)) {
property_desc_t prop_desc;
const WCHAR *name_str;
BOOL result;
name_str = jsstr_flatten(name);
if(name_str)
hres = jsdisp_is_own_prop(jsthis->u.jsdisp, name_str, &result);
else
hres = E_OUTOFMEMORY;
if(!name_str) {
jsstr_release(name);
return E_OUTOFMEMORY;
}
hres = jsdisp_get_own_property(jsthis->u.jsdisp, name_str, TRUE, &prop_desc);
jsstr_release(name);
if(FAILED(hres))
if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
return hres;
if(r)
*r = jsval_bool(result);
if(r) *r = jsval_bool(hres == S_OK);
return S_OK;
}
@ -169,9 +183,9 @@ static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD fl
static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
property_desc_t prop_desc;
const WCHAR *name;
jsstr_t *name_str;
BOOL ret;
HRESULT hres;
TRACE("\n");
@ -190,13 +204,13 @@ static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, W
if(FAILED(hres))
return hres;
hres = jsdisp_is_enumerable(jsthis->u.jsdisp, name, &ret);
hres = jsdisp_get_own_property(jsthis->u.jsdisp, name, TRUE, &prop_desc);
jsstr_release(name_str);
if(FAILED(hres))
if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
return hres;
if(r)
*r = jsval_bool(ret);
*r = jsval_bool(hres == S_OK && (prop_desc.flags & PROPF_ENUMERABLE) != 0);
return S_OK;
}
@ -252,6 +266,274 @@ static const builtin_info_t ObjectInst_info = {
NULL
};
static void release_property_descriptor(property_desc_t *desc)
{
if(desc->explicit_value)
jsval_release(desc->value);
if(desc->getter)
jsdisp_release(desc->getter);
if(desc->setter)
jsdisp_release(desc->setter);
}
static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, property_desc_t *desc)
{
DISPID id;
jsval_t v;
BOOL b;
HRESULT hres;
memset(desc, 0, sizeof(*desc));
desc->value = jsval_undefined();
hres = jsdisp_get_id(attr_obj, enumerableW, 0, &id);
if(SUCCEEDED(hres)) {
desc->mask |= PROPF_ENUMERABLE;
hres = jsdisp_propget(attr_obj, id, &v);
if(FAILED(hres))
return hres;
hres = to_boolean(v, &b);
jsval_release(v);
if(FAILED(hres))
return hres;
if(b)
desc->flags |= PROPF_ENUMERABLE;
}else if(hres != DISP_E_UNKNOWNNAME) {
return hres;
}
hres = jsdisp_get_id(attr_obj, configurableW, 0, &id);
if(SUCCEEDED(hres)) {
desc->mask |= PROPF_CONFIGURABLE;
hres = jsdisp_propget(attr_obj, id, &v);
if(FAILED(hres))
return hres;
hres = to_boolean(v, &b);
jsval_release(v);
if(FAILED(hres))
return hres;
if(b)
desc->flags |= PROPF_CONFIGURABLE;
}else if(hres != DISP_E_UNKNOWNNAME) {
return hres;
}
hres = jsdisp_get_id(attr_obj, valueW, 0, &id);
if(SUCCEEDED(hres)) {
hres = jsdisp_propget(attr_obj, id, &desc->value);
if(FAILED(hres))
return hres;
desc->explicit_value = TRUE;
}else if(hres != DISP_E_UNKNOWNNAME) {
return hres;
}
hres = jsdisp_get_id(attr_obj, writableW, 0, &id);
if(SUCCEEDED(hres)) {
desc->mask |= PROPF_WRITABLE;
hres = jsdisp_propget(attr_obj, id, &v);
if(SUCCEEDED(hres)) {
hres = to_boolean(v, &b);
jsval_release(v);
if(SUCCEEDED(hres) && b)
desc->flags |= PROPF_WRITABLE;
}
}else if(hres == DISP_E_UNKNOWNNAME) {
hres = S_OK;
}
if(FAILED(hres)) {
release_property_descriptor(desc);
return hres;
}
hres = jsdisp_get_id(attr_obj, getW, 0, &id);
if(SUCCEEDED(hres)) {
desc->explicit_getter = TRUE;
hres = jsdisp_propget(attr_obj, id, &v);
if(SUCCEEDED(hres) && !is_undefined(v)) {
if(!is_object_instance(v)) {
FIXME("getter is not an object\n");
jsval_release(v);
hres = E_FAIL;
}else {
/* FIXME: Check IsCallable */
desc->getter = to_jsdisp(get_object(v));
if(!desc->getter)
FIXME("getter is not JS object\n");
}
}
}else if(hres == DISP_E_UNKNOWNNAME) {
hres = S_OK;
}
if(FAILED(hres)) {
release_property_descriptor(desc);
return hres;
}
hres = jsdisp_get_id(attr_obj, setW, 0, &id);
if(SUCCEEDED(hres)) {
desc->explicit_setter = TRUE;
hres = jsdisp_propget(attr_obj, id, &v);
if(SUCCEEDED(hres) && !is_undefined(v)) {
if(!is_object_instance(v)) {
FIXME("setter is not an object\n");
jsval_release(v);
hres = E_FAIL;
}else {
/* FIXME: Check IsCallable */
desc->setter = to_jsdisp(get_object(v));
if(!desc->setter)
FIXME("setter is not JS object\n");
}
}
}else if(hres == DISP_E_UNKNOWNNAME) {
hres = S_OK;
}
if(FAILED(hres)) {
release_property_descriptor(desc);
return hres;
}
if(desc->explicit_getter || desc->explicit_setter) {
if(desc->explicit_value)
hres = throw_type_error(ctx, JS_E_PROP_DESC_MISMATCH, NULL);
else if(desc->mask & PROPF_WRITABLE)
hres = throw_type_error(ctx, JS_E_INVALID_WRITABLE_PROP_DESC, NULL);
}
if(FAILED(hres))
release_property_descriptor(desc);
return hres;
}
static HRESULT Object_defineProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
unsigned argc, jsval_t *argv, jsval_t *r)
{
property_desc_t prop_desc;
jsdisp_t *obj, *attr_obj;
const WCHAR *name;
jsstr_t *name_str;
HRESULT hres;
TRACE("\n");
if(argc < 1 || !is_object_instance(argv[0]))
return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
obj = to_jsdisp(get_object(argv[0]));
if(!obj) {
FIXME("not implemented non-JS object\n");
return E_NOTIMPL;
}
hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
if(FAILED(hres))
return hres;
if(argc >= 3 && is_object_instance(argv[2])) {
attr_obj = to_jsdisp(get_object(argv[2]));
if(attr_obj) {
hres = to_property_descriptor(ctx, attr_obj, &prop_desc);
}else {
FIXME("not implemented non-JS object\n");
hres = E_NOTIMPL;
}
}else {
hres = throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
}
jsstr_release(name_str);
if(FAILED(hres))
return hres;
hres = jsdisp_define_property(obj, name, &prop_desc);
release_property_descriptor(&prop_desc);
return hres;
}
static HRESULT Object_defineProperties(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
unsigned argc, jsval_t *argv, jsval_t *r)
{
FIXME("\n");
return E_NOTIMPL;
}
static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
unsigned argc, jsval_t *argv, jsval_t *r)
{
property_desc_t prop_desc;
jsdisp_t *obj, *desc_obj;
const WCHAR *name;
jsstr_t *name_str;
HRESULT hres;
TRACE("\n");
if(argc < 1 || !is_object_instance(argv[0]))
return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
obj = to_jsdisp(get_object(argv[0]));
if(!obj) {
FIXME("not implemented non-JS object\n");
return E_NOTIMPL;
}
hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
if(FAILED(hres))
return hres;
hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc);
jsstr_release(name_str);
if(hres == DISP_E_UNKNOWNNAME) {
if(r) *r = jsval_undefined();
return S_OK;
}
if(FAILED(hres))
return hres;
hres = create_object(ctx, NULL, &desc_obj);
if(FAILED(hres))
return hres;
if(prop_desc.explicit_getter || prop_desc.explicit_setter) {
hres = jsdisp_propput_name(desc_obj, getW, prop_desc.getter
? jsval_obj(prop_desc.getter) : jsval_undefined());
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, setW, prop_desc.setter
? jsval_obj(prop_desc.setter) : jsval_undefined());
}else {
hres = jsdisp_propput_name(desc_obj, valueW, prop_desc.value);
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, writableW,
jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE)));
}
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, enumerableW,
jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE)));
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, configurableW,
jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE)));
release_property_descriptor(&prop_desc);
if(SUCCEEDED(hres) && r)
*r = jsval_obj(desc_obj);
else
jsdisp_release(desc_obj);
return hres;
}
static const builtin_prop_t ObjectConstr_props[] = {
{definePropertiesW, Object_defineProperties, PROPF_ES5|PROPF_METHOD|2},
{definePropertyW, Object_defineProperty, PROPF_ES5|PROPF_METHOD|2},
{getOwnPropertyDescriptorW, Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2}
};
static const builtin_info_t ObjectConstr_info = {
JSCLASS_FUNCTION,
DEFAULT_FUNCTION_VALUE,
sizeof(ObjectConstr_props)/sizeof(*ObjectConstr_props),
ObjectConstr_props,
NULL,
NULL
};
static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -303,7 +585,7 @@ HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdi
{
static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, NULL, PROPF_CONSTR,
return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, &ObjectConstr_info, PROPF_CONSTR,
object_prototype, ret);
}

File diff suppressed because it is too large Load diff

View file

@ -53,33 +53,33 @@ extern int parser_debug;
kDELETE = 263,
kDO = 264,
kELSE = 265,
kIF = 266,
kFINALLY = 267,
kFOR = 268,
kIN = 269,
kINSTANCEOF = 270,
kNEW = 271,
kNULL = 272,
kRETURN = 273,
kSWITCH = 274,
kTHIS = 275,
kTHROW = 276,
kTRUE = 277,
kFALSE = 278,
kTRY = 279,
kTYPEOF = 280,
kVAR = 281,
kVOID = 282,
kWHILE = 283,
kWITH = 284,
tANDAND = 285,
tOROR = 286,
tINC = 287,
tDEC = 288,
tHTMLCOMMENT = 289,
kDIVEQ = 290,
kDCOL = 291,
kFUNCTION = 292,
kFUNCTION = 266,
kIF = 267,
kFINALLY = 268,
kFOR = 269,
kIN = 270,
kINSTANCEOF = 271,
kNEW = 272,
kNULL = 273,
kRETURN = 274,
kSWITCH = 275,
kTHIS = 276,
kTHROW = 277,
kTRUE = 278,
kFALSE = 279,
kTRY = 280,
kTYPEOF = 281,
kVAR = 282,
kVOID = 283,
kWHILE = 284,
kWITH = 285,
tANDAND = 286,
tOROR = 287,
tINC = 288,
tDEC = 289,
tHTMLCOMMENT = 290,
kDIVEQ = 291,
kDCOL = 292,
tIdentifier = 293,
tAssignOper = 294,
tEqOper = 295,

View file

@ -164,11 +164,11 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
}
/* keywords */
%token kBREAK kCASE kCATCH kCONTINUE kDEFAULT kDELETE kDO kELSE kIF kFINALLY kFOR kIN
%token kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE kTRY kTYPEOF kVAR kVOID kWHILE kWITH
%token <identifier> kBREAK kCASE kCATCH kCONTINUE kDEFAULT kDELETE kDO kELSE kFUNCTION kIF kFINALLY kFOR kIN
%token <identifier> kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE kTRY kTYPEOF kVAR kVOID kWHILE kWITH
%token tANDAND tOROR tINC tDEC tHTMLCOMMENT kDIVEQ kDCOL
%token <srcptr> kFUNCTION '}'
%token <srcptr> '}'
/* tokens */
%token <identifier> tIdentifier
@ -241,6 +241,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
%type <literal> BooleanLiteral
%type <srcptr> KFunction
%type <ival> AssignOper
%type <identifier> IdentifierName ReservedAsIdentifier
%nonassoc LOWER_THAN_ELSE
%nonassoc kELSE
@ -272,7 +273,7 @@ FunctionExpression
{ $$ = new_function_expression(ctx, $4, $6, $9, $2, $1, $10-$1+1); }
KFunction
: kFUNCTION { $$ = $1; }
: kFUNCTION { $$ = ctx->ptr - 8; }
/* ECMA-262 3rd Edition 13 */
FunctionBody
@ -711,7 +712,7 @@ MemberExpression
| FunctionExpression { $$ = $1; }
| MemberExpression '[' Expression ']'
{ $$ = new_binary_expression(ctx, EXPR_ARRAY, $1, $3); }
| MemberExpression '.' tIdentifier
| MemberExpression '.' IdentifierName
{ $$ = new_member_expression(ctx, $1, $3); }
| kNEW MemberExpression Arguments
{ $$ = new_new_expression(ctx, $2, $3); }
@ -724,7 +725,7 @@ CallExpression
{ $$ = new_call_expression(ctx, $1, $2); }
| CallExpression '[' Expression ']'
{ $$ = new_binary_expression(ctx, EXPR_ARRAY, $1, $3); }
| CallExpression '.' tIdentifier
| CallExpression '.' IdentifierName
{ $$ = new_member_expression(ctx, $1, $3); }
/* ECMA-262 3rd Edition 11.2 */
@ -787,7 +788,7 @@ PropertyNameAndValueList
/* ECMA-262 3rd Edition 11.1.5 */
PropertyName
: tIdentifier { $$ = new_string_literal(ctx, $1); }
: IdentifierName { $$ = new_string_literal(ctx, $1); }
| tStringLiteral { $$ = new_string_literal(ctx, $1); }
| tNumericLiteral { $$ = $1; }
@ -796,6 +797,49 @@ Identifier_opt
: /* empty*/ { $$ = NULL; }
| tIdentifier { $$ = $1; }
/* ECMA-262 5.1 Edition 7.6 */
IdentifierName
: tIdentifier { $$ = $1; }
| ReservedAsIdentifier
{
if(ctx->script->version < SCRIPTLANGUAGEVERSION_ES5) {
WARN("%s keyword used as an identifier in legacy mode.\n",
debugstr_w($1));
YYABORT;
}
$$ = $1;
}
ReservedAsIdentifier
: kBREAK { $$ = $1; }
| kCASE { $$ = $1; }
| kCATCH { $$ = $1; }
| kCONTINUE { $$ = $1; }
| kDEFAULT { $$ = $1; }
| kDELETE { $$ = $1; }
| kDO { $$ = $1; }
| kELSE { $$ = $1; }
| kFALSE { $$ = $1; }
| kFINALLY { $$ = $1; }
| kFOR { $$ = $1; }
| kFUNCTION { $$ = $1; }
| kIF { $$ = $1; }
| kIN { $$ = $1; }
| kINSTANCEOF { $$ = $1; }
| kNEW { $$ = $1; }
| kNULL { $$ = $1; }
| kRETURN { $$ = $1; }
| kSWITCH { $$ = $1; }
| kTHIS { $$ = $1; }
| kTHROW { $$ = $1; }
| kTRUE { $$ = $1; }
| kTRY { $$ = $1; }
| kTYPEOF { $$ = $1; }
| kVAR { $$ = $1; }
| kVOID { $$ = $1; }
| kWHILE { $$ = $1; }
| kWITH { $$ = $1; }
/* ECMA-262 3rd Edition 7.8 */
Literal
: kNULL { $$ = new_null_literal(ctx); }

View file

@ -58,6 +58,7 @@
#define IDS_INVALID_DELETE 0x1394
#define IDS_NOT_VBARRAY 0x1395
#define IDS_JSCRIPT_EXPECTED 0x1396
#define IDS_NOT_ENUMERATOR 0x1397
#define IDS_REGEXP_SYNTAX_ERROR 0x1399
#define IDS_URI_INVALID_CHAR 0x13A0
#define IDS_URI_INVALID_CODING 0x13A1
@ -65,3 +66,9 @@
#define IDS_PRECISION_OUT_OF_RANGE 0x13A3
#define IDS_INVALID_LENGTH 0x13A5
#define IDS_ARRAY_EXPECTED 0x13A7
#define IDS_INVALID_WRITABLE_PROP_DESC 0x13AC
#define IDS_NONCONFIGURABLE_REDEFINED 0x13D6
#define IDS_NONWRITABLE_MODIFIED 0x13D7
/* FIXME: This is not compatible with native, but we would
* conflict with IDS_UNSUPPORTED_ACTION otherwise */
#define IDS_PROP_DESC_MISMATCH 0x1F00

View file

@ -63,6 +63,7 @@ static const WCHAR toLowerCaseW[] = {'t','o','L','o','w','e','r','C','a','s','e'
static const WCHAR toUpperCaseW[] = {'t','o','U','p','p','e','r','C','a','s','e',0};
static const WCHAR toLocaleLowerCaseW[] = {'t','o','L','o','c','a','l','e','L','o','w','e','r','C','a','s','e',0};
static const WCHAR toLocaleUpperCaseW[] = {'t','o','L','o','c','a','l','e','U','p','p','e','r','C','a','s','e',0};
static const WCHAR trimW[] = {'t','r','i','m',0};
static const WCHAR localeCompareW[] = {'l','o','c','a','l','e','C','o','m','p','a','r','e',0};
static const WCHAR fromCharCodeW[] = {'f','r','o','m','C','h','a','r','C','o','d','e',0};
@ -119,12 +120,6 @@ static HRESULT String_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r
return S_OK;
}
static HRESULT String_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
{
FIXME("%p\n", jsthis);
return E_NOTIMPL;
}
static HRESULT stringobj_to_string(vdisp_t *jsthis, jsval_t *r)
{
StringInstance *string;
@ -1471,6 +1466,41 @@ static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD
return E_NOTIMPL;
}
static HRESULT String_trim(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc,
jsval_t *argv, jsval_t *r)
{
const WCHAR *str, *begin, *end;
jsstr_t *jsstr;
unsigned len;
HRESULT hres;
hres = to_flat_string(ctx, jsval_disp(jsthis->u.disp), &jsstr, &str);
if(FAILED(hres)) {
WARN("to_flat_string failed: %08x\n", hres);
return hres;
}
len = jsstr_length(jsstr);
TRACE("%s\n", debugstr_wn(str, len));
for(begin = str, end = str + len; begin < end && isspaceW(*begin); begin++);
while(end > begin + 1 && isspaceW(*(end-1))) end--;
if(r) {
jsstr_t *ret;
if(begin == str && end == str + len)
ret = jsstr_addref(jsstr);
else
ret = jsstr_alloc_len(begin, end - begin);
if(ret)
*r = jsval_string(ret);
else
hres = E_OUTOFMEMORY;
}
jsstr_release(jsstr);
return hres;
}
static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -1539,7 +1569,7 @@ static const builtin_prop_t String_props[] = {
{indexOfW, String_indexOf, PROPF_METHOD|2},
{italicsW, String_italics, PROPF_METHOD},
{lastIndexOfW, String_lastIndexOf, PROPF_METHOD|2},
{lengthW, NULL,0, String_get_length, String_set_length},
{lengthW, NULL,0, String_get_length},
{linkW, String_link, PROPF_METHOD|1},
{localeCompareW, String_localeCompare, PROPF_METHOD|1},
{matchW, String_match, PROPF_METHOD|1},
@ -1558,6 +1588,7 @@ static const builtin_prop_t String_props[] = {
{toLowerCaseW, String_toLowerCase, PROPF_METHOD},
{toStringW, String_toString, PROPF_METHOD},
{toUpperCaseW, String_toUpperCase, PROPF_METHOD},
{trimW, String_trim, PROPF_ES5|PROPF_METHOD},
{valueOfW, String_valueOf, PROPF_METHOD}
};
@ -1571,7 +1602,7 @@ static const builtin_info_t String_info = {
};
static const builtin_prop_t StringInst_props[] = {
{lengthW, NULL,0, String_get_length, String_set_length}
{lengthW, NULL,0, String_get_length}
};
static const builtin_info_t StringInst_info = {

View file

@ -85,7 +85,7 @@ reactos/dll/win32/inseng # Synced to WineStaging-3.3
reactos/dll/win32/iphlpapi # Out of sync
reactos/dll/win32/itircl # Synced to WineStaging-3.3
reactos/dll/win32/itss # Synced to WineStaging-3.3
reactos/dll/win32/jscript # Synced to WineStaging-3.3
reactos/dll/win32/jscript # Synced to WineStaging-3.9
reactos/dll/win32/jsproxy # Synced to WineStaging-3.3
reactos/dll/win32/loadperf # Synced to WineStaging-3.3
reactos/dll/win32/lz32 # Synced to WineStaging-3.3