From: Gabriel Ivăncescu gabrielopcode@gmail.com
is_dispex_prop_id will be more useful later when we'll also have indexed props with their own vtbl, for now it avoids DISPID_VALUE.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 507 ++++++++++++++++++++++------------------- dlls/jscript/jscript.h | 7 + 2 files changed, 277 insertions(+), 237 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 5f41443f83d..fc7ca939294 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -257,7 +257,7 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref return ret; }
-static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) +static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, struct prop_desc *ret) { const builtin_prop_t *builtin; unsigned bucket, pos, prev = ~0; @@ -274,8 +274,8 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, This->props[bucket].bucket_head = pos; }
- *ret = &This->props[pos]; - return S_OK; + prop = &This->props[pos]; + goto ret_prop; }
prev = pos; @@ -300,8 +300,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
prop->type = PROP_JSVAL; prop->u.val = jsval_obj(obj); - *ret = prop; - return S_OK; + goto ret_prop; }else if(builtin->setter) flags |= PROPF_WRITABLE; flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; @@ -310,8 +309,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return E_OUTOFMEMORY;
prop->u.p = builtin; - *ret = prop; - return S_OK; + goto ret_prop; }
if(This->builtin_info->idx_length) { @@ -329,79 +327,95 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return E_OUTOFMEMORY;
prop->u.idx = idx; - *ret = prop; - return S_OK; + goto ret_prop; } }
- *ret = NULL; - return S_OK; + ret->id = 0; + return S_FALSE; + +ret_prop: + ret->vtbl = &dispex_prop_vtbl; + ret->jsdisp = This; + ret->id = prop_to_id(This, prop); + return prop->type != PROP_DELETED ? S_OK : S_FALSE; }
-static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) +static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, struct prop_desc *ret) { - dispex_prop_t *prop, *del=NULL; + dispex_prop_t *prop, *del = NULL; HRESULT hres;
- hres = find_prop_name(This, hash, name, case_insens, &prop); + hres = find_prop_name(This, hash, name, case_insens, ret); if(FAILED(hres)) return hres; - if(prop && prop->type==PROP_DELETED) { - del = prop; - } else if(prop) { + + if(hres == S_OK) { + prop = &This->props[prop_id_to_idx(ret->id)]; fix_protref_prop(This, prop); - *ret = prop; - return S_OK; + return prop->type != PROP_DELETED ? S_OK : S_FALSE; }
+ if(is_dispex_prop_id(ret->id)) + del = &This->props[prop_id_to_idx(ret->id)]; + if(This->prototype) { - hres = find_prop_name_prot(This->prototype, hash, name, case_insens, &prop); + hres = find_prop_name_prot(This->prototype, hash, name, case_insens, ret); if(FAILED(hres)) return hres; - if(prop && prop->type != PROP_DELETED) { + if(hres == S_OK) { if(del) { del->type = PROP_PROTREF; - del->u.ref = prop - This->prototype->props; + del->u.ref = prop_id_to_idx(ret->id); prop = del; }else { - prop = alloc_protref(This, prop->name, prop - This->prototype->props); + prop = alloc_protref(This, name, prop_id_to_idx(ret->id)); if(!prop) return E_OUTOFMEMORY; } - - *ret = prop; - return S_OK; + goto ret_prop; } }
- *ret = del; - return S_OK; + if(!del) { + ret->id = 0; + return S_FALSE; + } + prop = del; + +ret_prop: + ret->vtbl = &dispex_prop_vtbl; + ret->jsdisp = This; + ret->id = prop_to_id(This, prop); + return prop->type != PROP_DELETED ? S_OK : S_FALSE; }
-static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, dispex_prop_t **ret) +static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, struct prop_desc *ret) { dispex_prop_t *prop; HRESULT hres;
- hres = find_prop_name_prot(This, string_hash(name), name, case_insens, &prop); - if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) { - TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); - - if(prop) { - prop->type = PROP_JSVAL; - prop->flags = create_flags; - prop->u.val = jsval_undefined(); - }else { - prop = alloc_prop(This, name, PROP_JSVAL, create_flags); - if(!prop) - return E_OUTOFMEMORY; - } + hres = find_prop_name_prot(This, string_hash(name), name, case_insens, ret); + if(hres != S_FALSE) + return hres;
- prop->u.val = jsval_undefined(); + if(is_dispex_prop_id(ret->id)) { + prop = &This->props[prop_id_to_idx(ret->id)]; + prop->type = PROP_JSVAL; + prop->flags = create_flags; + }else { + prop = alloc_prop(This, name, PROP_JSVAL, create_flags); + if(!prop) + return E_OUTOFMEMORY; }
- *ret = prop; - return hres; + TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); + + prop->u.val = jsval_undefined(); + ret->vtbl = &dispex_prop_vtbl; + ret->jsdisp = This; + ret->id = prop_to_id(This, prop); + return S_OK; }
static IDispatch *get_this(DISPPARAMS *dp) @@ -663,6 +677,38 @@ static HRESULT dispex_prop_delete(struct prop_desc *prop, BOOL *ret) return delete_prop(&prop->jsdisp->props[prop_id_to_idx(prop->id)], ret); }
+static HRESULT dispex_prop_get_desc(struct prop_desc *prop, BOOL flags_only, property_desc_t *desc) +{ + dispex_prop_t *p = &prop->jsdisp->props[prop_id_to_idx(prop->id)]; + HRESULT hres; + + switch(p->type) { + case PROP_BUILTIN: + case PROP_JSVAL: + case PROP_IDX: + desc->explicit_value = TRUE; + if(!flags_only) { + hres = dispex_prop_get(prop, to_disp(prop->jsdisp), &desc->value); + if(FAILED(hres)) + return hres; + } + break; + case PROP_ACCESSOR: + desc->mask = PROPF_ENUMERABLE | PROPF_CONFIGURABLE; + desc->explicit_getter = desc->explicit_setter = TRUE; + if(!flags_only) { + desc->getter = p->u.accessor.getter ? jsdisp_addref(p->u.accessor.getter) : NULL; + desc->setter = p->u.accessor.setter ? jsdisp_addref(p->u.accessor.setter) : NULL; + } + break; + default: + return DISP_E_UNKNOWNNAME; + } + + desc->flags = p->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE); + return S_OK; +} + static void *dispex_prop_get_name(struct prop_desc *prop, BOOL bstr) { const WCHAR *name = prop->jsdisp->props[prop_id_to_idx(prop->id)].name; @@ -671,12 +717,135 @@ static void *dispex_prop_get_name(struct prop_desc *prop, BOOL bstr) return jsstr_alloc(name); }
+static HRESULT dispex_prop_define(struct prop_desc *prop, property_desc_t *desc) +{ + dispex_prop_t *p = &prop->jsdisp->props[prop_id_to_idx(prop->id)]; + script_ctx_t *ctx = prop->jsdisp->ctx; + HRESULT hres; + + if(p->type == PROP_DELETED || p->type == PROP_PROTREF) { + if(p->type == PROP_PROTREF && !prop->jsdisp->extensible) + return throw_error(ctx, JS_E_OBJECT_NONEXTENSIBLE, p->name); + + p->flags = desc->flags; + if(desc->explicit_getter || desc->explicit_setter) { + p->type = PROP_ACCESSOR; + p->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL; + p->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL; + TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(p->name), + p->u.accessor.getter, p->u.accessor.setter); + }else { + p->type = PROP_JSVAL; + if(desc->explicit_value) { + hres = jsval_copy(desc->value, &p->u.val); + if(FAILED(hres)) + return hres; + }else { + p->u.val = jsval_undefined(); + } + TRACE("%s = %s\n", debugstr_w(p->name), debugstr_jsval(p->u.val)); + } + return S_OK; + } + + TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(p->name), + p->flags, desc->flags, desc->mask); + + if(!(p->flags & PROPF_CONFIGURABLE)) { + if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE)) + || ((desc->mask & PROPF_ENUMERABLE) + && ((desc->flags & PROPF_ENUMERABLE) != (p->flags & PROPF_ENUMERABLE)))) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, p->name); + } + + if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { + if(p->type == PROP_ACCESSOR) { + if(!(p->flags & PROPF_CONFIGURABLE)) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, p->name); + if(p->u.accessor.getter) + jsdisp_release(p->u.accessor.getter); + if(p->u.accessor.setter) + jsdisp_release(p->u.accessor.setter); + + p->type = PROP_JSVAL; + hres = jsval_copy(desc->value, &p->u.val); + if(FAILED(hres)) { + p->u.val = jsval_undefined(); + return hres; + } + }else { + if(!(p->flags & PROPF_CONFIGURABLE) && !(p->flags & PROPF_WRITABLE)) { + if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE)) + return throw_error(ctx, JS_E_NONWRITABLE_MODIFIED, p->name); + if(desc->explicit_value) { + if(p->type == PROP_JSVAL) { + BOOL eq; + hres = jsval_strict_equal(desc->value, p->u.val, &eq); + if(FAILED(hres)) + return hres; + if(!eq) + return throw_error(ctx, JS_E_NONWRITABLE_MODIFIED, p->name); + }else { + FIXME("redefinition of property type %d\n", p->type); + } + } + } + if(desc->explicit_value) { + if(p->type == PROP_JSVAL) + jsval_release(p->u.val); + else + p->type = PROP_JSVAL; + hres = jsval_copy(desc->value, &p->u.val); + if(FAILED(hres)) { + p->u.val = jsval_undefined(); + return hres; + } + } + } + }else if(desc->explicit_getter || desc->explicit_setter) { + if(p->type != PROP_ACCESSOR) { + if(!(p->flags & PROPF_CONFIGURABLE)) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, p->name); + if(p->type == PROP_JSVAL) + jsval_release(p->u.val); + p->type = PROP_ACCESSOR; + p->u.accessor.getter = p->u.accessor.setter = NULL; + }else if(!(p->flags & PROPF_CONFIGURABLE)) { + if((desc->explicit_getter && desc->getter != p->u.accessor.getter) + || (desc->explicit_setter && desc->setter != p->u.accessor.setter)) + return throw_error(ctx, JS_E_NONCONFIGURABLE_REDEFINED, p->name); + } + + if(desc->explicit_getter) { + if(p->u.accessor.getter) { + jsdisp_release(p->u.accessor.getter); + p->u.accessor.getter = NULL; + } + if(desc->getter) + p->u.accessor.getter = jsdisp_addref(desc->getter); + } + if(desc->explicit_setter) { + if(p->u.accessor.setter) { + jsdisp_release(p->u.accessor.setter); + p->u.accessor.setter = NULL; + } + if(desc->setter) + p->u.accessor.setter = jsdisp_addref(desc->setter); + } + } + + p->flags = (p->flags & ~desc->mask) | (desc->flags & desc->mask); + return S_OK; +} + static const struct prop_desc_vtbl dispex_prop_vtbl = { dispex_prop_get, dispex_prop_put, dispex_prop_invoke, dispex_prop_delete, - dispex_prop_get_name + dispex_prop_get_desc, + dispex_prop_get_name, + dispex_prop_define };
HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) @@ -687,7 +856,7 @@ HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
static HRESULT fill_props(jsdisp_t *obj) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
if(obj->builtin_info->idx_length) { @@ -707,7 +876,8 @@ static HRESULT fill_props(jsdisp_t *obj)
static HRESULT fill_protrefs(jsdisp_t *This) { - dispex_prop_t *iter, *prop; + struct prop_desc prop; + dispex_prop_t *iter; HRESULT hres;
hres = fill_props(This); @@ -725,15 +895,14 @@ static HRESULT fill_protrefs(jsdisp_t *This) hres = find_prop_name(This, iter->hash, iter->name, FALSE, &prop); if(FAILED(hres)) return hres; - if(!prop || prop->type==PROP_DELETED) { - if(prop) { - prop->type = PROP_PROTREF; - prop->flags = 0; - prop->u.ref = iter - This->prototype->props; - }else { - prop = alloc_protref(This, iter->name, iter - This->prototype->props); - if(!prop) - return E_OUTOFMEMORY; + if(hres != S_OK) { + if(is_dispex_prop_id(prop.id)) { + dispex_prop_t *p = &This->props[prop_id_to_idx(prop.id)]; + p->type = PROP_PROTREF; + p->flags = 0; + p->u.ref = iter - This->prototype->props; + }else if(!alloc_protref(This, iter->name, iter - This->prototype->props)) { + return E_OUTOFMEMORY; } } } @@ -2105,7 +2274,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; + struct prop_desc prop; BOOL b; HRESULT hres;
@@ -2117,12 +2286,12 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, &prop); if(FAILED(hres)) return hres; - if(!prop) { + if(hres != S_OK) { TRACE("not found\n"); return S_OK; }
- return delete_prop(prop, &b); + return prop.vtbl->delete(&prop, &b); }
static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) @@ -2343,15 +2512,15 @@ void jsdisp_release(jsdisp_t *jsdisp)
HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr) { + struct prop_desc prop; jsdisp_t *prot = NULL; - dispex_prop_t *prop; HRESULT hres;
hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, &prop); - if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { + if(hres == S_OK) { jsval_t val;
- hres = prop_get(constr, to_disp(constr), prop, &val); + hres = prop.vtbl->get(&prop, to_disp(constr), &val); if(FAILED(hres)) { ERR("Could not get prototype\n"); return hres; @@ -2381,7 +2550,7 @@ jsdisp_t *iface_to_jsdisp(IDispatch *iface)
HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
if(jsdisp->extensible && (flags & fdexNameEnsure)) @@ -2392,8 +2561,8 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * if(FAILED(hres)) return hres;
- if(prop && prop->type!=PROP_DELETED) { - *id = prop_to_id(jsdisp, prop); + if(hres == S_OK) { + *id = prop.id; return S_OK; }
@@ -2445,17 +2614,14 @@ HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_
HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, &prop); - if(FAILED(hres)) - return hres; - - if(!prop || prop->type == PROP_DELETED) - return JS_E_INVALID_PROPERTY; + if(hres != S_OK) + return FAILED(hres) ? hres : JS_E_INVALID_PROPERTY;
- return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + return prop.vtbl->invoke(&prop, to_disp(disp), flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); }
static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r, @@ -2683,7 +2849,7 @@ HRESULT disp_call_value_with_caller(script_ctx_t *ctx, IDispatch *disp, jsval_t
HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw, jsval_t val) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
if(obj->extensible) @@ -2692,10 +2858,10 @@ HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; - if(!prop || (prop->type == PROP_DELETED && !obj->extensible)) + if(hres != S_OK && (!prop.id || !obj->extensible)) return throw ? JS_E_INVALID_ACTION : S_OK;
- return prop_put(obj, prop, val); + return prop.vtbl->put(&prop, val); }
HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val) @@ -2786,25 +2952,25 @@ HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name,
HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres;
- if(!prop || prop->type==PROP_DELETED) { + if(hres != S_OK) { *val = jsval_undefined(); return S_OK; }
- return prop_get(obj, to_disp(obj), prop, val); + return prop.vtbl->get(&prop, to_disp(obj), val); }
HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) { + struct prop_desc prop; WCHAR name[12]; - dispex_prop_t *prop; HRESULT hres;
swprintf(name, ARRAY_SIZE(name), L"%d", idx); @@ -2813,12 +2979,12 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) if(FAILED(hres)) return hres;
- if(!prop || prop->type==PROP_DELETED) { + if(hres != S_OK) { *r = jsval_undefined(); return DISP_E_UNKNOWNNAME; }
- return prop_get(obj, to_disp(obj), prop, r); + return prop.vtbl->get(&prop, to_disp(obj), r); }
HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) @@ -2858,18 +3024,18 @@ HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val
HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) { + struct prop_desc prop; WCHAR buf[12]; - dispex_prop_t *prop; BOOL b; HRESULT hres;
swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
hres = find_prop_name(obj, string_hash(buf), buf, FALSE, &prop); - if(FAILED(hres) || !prop) - return hres; + if(hres != S_OK) + return FAILED(hres) ? hres : S_OK;
- hres = delete_prop(prop, &b); + hres = prop.vtbl->delete(&prop, &b); if(FAILED(hres)) return hres; return b ? S_OK : JS_E_INVALID_ACTION; @@ -2951,7 +3117,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL
jsdisp = iface_to_jsdisp(disp); if(jsdisp) { - dispex_prop_t *prop; + struct prop_desc prop; const WCHAR *ptr;
ptr = jsstr_flatten(name); @@ -2961,8 +3127,8 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL }
hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop); - if(prop) { - hres = delete_prop(prop, ret); + if(hres == S_OK) { + hres = prop.vtbl->delete(&prop, ret); }else { *ret = TRUE; hres = S_OK; @@ -3004,173 +3170,40 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only, property_desc_t *desc) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); - if(FAILED(hres)) - return hres; - - if(!prop) - return DISP_E_UNKNOWNNAME; + if(hres != S_OK) + return FAILED(hres) ? hres : DISP_E_UNKNOWNNAME;
memset(desc, 0, sizeof(*desc)); - - switch(prop->type) { - case PROP_BUILTIN: - case PROP_JSVAL: - case PROP_IDX: - desc->mask |= PROPF_WRITABLE; - desc->explicit_value = TRUE; - if(!flags_only) { - hres = prop_get(obj, to_disp(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; + desc->mask = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; + return prop.vtbl->get_desc(&prop, flags_only, desc); }
HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc) { - dispex_prop_t *prop; + struct prop_desc prop; HRESULT hres;
hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres;
- if((!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) && !obj->extensible) + if(hres != S_OK && !obj->extensible) return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name);
- 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 %lx 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_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_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_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_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_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_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); - } + if(!prop.id) { + dispex_prop_t *p = alloc_prop(obj, name, PROP_DELETED, 0); + if(!p) + return E_OUTOFMEMORY; + prop.vtbl = &dispex_prop_vtbl; + prop.jsdisp = obj; + prop.id = prop_to_id(obj, p); }
- prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask); - return S_OK; + return prop.vtbl->define(&prop, desc); }
HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned flags, jsval_t value) diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 06be65fd153..66de77856ad 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -259,9 +259,16 @@ struct prop_desc_vtbl { HRESULT (*put)(struct prop_desc*,jsval_t); HRESULT (*invoke)(struct prop_desc*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); HRESULT (*delete)(struct prop_desc*,BOOL*); + HRESULT (*get_desc)(struct prop_desc*,BOOL,property_desc_t*); void *(*get_name)(struct prop_desc*,BOOL); + HRESULT (*define)(struct prop_desc*,property_desc_t*); };
+static inline BOOL is_dispex_prop_id(DISPID id) +{ + return id > 0; +} + enum jsdisp_enum_type { JSDISP_ENUM_ALL, JSDISP_ENUM_OWN,