Newer
Older
/*
* Copyright 2008 Jacek Caban for CodeWeavers
*
* 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 "config.h"
#include "wine/port.h"
#include <assert.h>
#include "engine.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
WINE_DECLARE_DEBUG_CHANNEL(heap);
const char *debugstr_variant(const VARIANT *v)
{
if(!v)
return "(null)";
switch(V_VT(v)) {
case VT_EMPTY:
case VT_I4:
return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
case VT_UI4:
return wine_dbg_sprintf("{VT_UI4: %u}", V_UI4(v));
case VT_R8:
return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
case VT_BSTR:
return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
case VT_DISPATCH:
return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
case VT_BOOL:
return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
case VT_ARRAY|VT_VARIANT:
return "{VT_ARRAY|VT_VARIANT: ...}";
default:
return wine_dbg_sprintf("{vt %d}", V_VT(v));
}
}
const char *debugstr_jsval(const jsval_t v)
{
switch(v.type) {
case JSV_UNDEFINED:
return "undefined";
case JSV_NULL:
return "null";
case JSV_OBJECT:
return wine_dbg_sprintf("obj(%p)", get_object(v));
case JSV_STRING:
return debugstr_w(get_string(v));
case JSV_NUMBER:
return wine_dbg_sprintf("%lf", get_number(v));
case JSV_BOOL:
return get_bool(v) ? "true" : "false";
case JSV_VARIANT:
return debugstr_variant(get_variant(v));
}
assert(0);
return NULL;
}
#define ARENA_FREE_FILLER 0xaa
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
static inline DWORD block_size(DWORD block)
{
return MIN_BLOCK_SIZE << block;
}
void jsheap_init(jsheap_t *heap)
{
memset(heap, 0, sizeof(*heap));
list_init(&heap->custom_blocks);
}
void *jsheap_alloc(jsheap_t *heap, DWORD size)
{
struct list *list;
void *tmp;
if(!heap->block_cnt) {
if(!heap->blocks) {
heap->blocks = heap_alloc(sizeof(void*));
if(!heap->blocks)
return NULL;
}
tmp = heap_alloc(block_size(0));
if(!tmp)
return NULL;
heap->blocks[0] = tmp;
heap->block_cnt = 1;
}
if(heap->offset + size <= block_size(heap->last_block)) {
tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
heap->offset += size;
return tmp;
}
if(size <= block_size(heap->last_block+1)) {
if(heap->last_block+1 == heap->block_cnt) {
tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
if(!tmp)
return NULL;
heap->blocks = tmp;
heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
if(!heap->blocks[heap->block_cnt])
return NULL;
heap->block_cnt++;
}
heap->last_block++;
heap->offset = size;
return heap->blocks[heap->last_block];
}
list = heap_alloc(size + sizeof(struct list));
if(!list)
return NULL;
list_add_head(&heap->custom_blocks, list);
return list+1;
}
void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
{
if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
&& heap->offset+inc < block_size(heap->last_block)) {
heap->offset += inc;
return mem;
}
ret = jsheap_alloc(heap, size+inc);
if(ret) /* FIXME: avoid copying for custom blocks */
memcpy(ret, mem, size);
return ret;
void jsheap_clear(jsheap_t *heap)
{
struct list *tmp;
while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
list_remove(tmp);
heap_free(tmp);
}
if(WARN_ON(heap)) {
DWORD i;
for(i=0; i < heap->block_cnt; i++)
memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
}
}
void jsheap_free(jsheap_t *heap)
{
DWORD i;
jsheap_clear(heap);
for(i=0; i < heap->block_cnt; i++)
heap_free(heap->blocks[i]);
heap_free(heap->blocks);
jsheap_init(heap);
}
jsheap_t *jsheap_mark(jsheap_t *heap)
{
if(heap->mark)
return NULL;
heap->mark = TRUE;
return heap;
}
Jacek Caban
committed
static BSTR clone_bstr(BSTR str)
{
return SysAllocStringLen(str, str ? SysStringLen(str) : 0);
}
void jsval_release(jsval_t val)
{
switch(val.type) {
case JSV_OBJECT:
if(val.u.obj)
IDispatch_Release(val.u.obj);
Jacek Caban
committed
break;
case JSV_STRING:
SysFreeString(val.u.str);
break;
case JSV_VARIANT:
VariantClear(val.u.v);
heap_free(val.u.v);
break;
default:
break;
}
}
HRESULT jsval_variant(jsval_t *val, VARIANT *var)
{
HRESULT hres;
val->type = JSV_VARIANT;
val->u.v = heap_alloc(sizeof(VARIANT));
if(!val->u.v)
return E_OUTOFMEMORY;
V_VT(val->u.v) = VT_EMPTY;
Jacek Caban
committed
hres = VariantCopy(val->u.v, var);
if(FAILED(hres))
heap_free(val->u.v);
return hres;
}
HRESULT jsval_copy(jsval_t v, jsval_t *r)
{
switch(v.type) {
case JSV_UNDEFINED:
case JSV_NULL:
case JSV_NUMBER:
case JSV_BOOL:
*r = v;
return S_OK;
case JSV_OBJECT:
if(get_object(v))
IDispatch_AddRef(get_object(v));
*r = v;
return S_OK;
case JSV_STRING: {
BSTR str = clone_bstr(get_string(v));
if(!str)
return E_OUTOFMEMORY;
*r = jsval_string(str);
return S_OK;
}
case JSV_VARIANT:
return jsval_variant(r, get_variant(v));
}
assert(0);
return E_FAIL;
}
Jacek Caban
committed
HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
{
switch(V_VT(var)) {
case VT_EMPTY:
*r = jsval_undefined();
return S_OK;
case VT_NULL:
*r = jsval_null();
return S_OK;
case VT_BOOL:
*r = jsval_bool(V_BOOL(var));
return S_OK;
case VT_I4:
*r = jsval_number(V_I4(var));
return S_OK;
case VT_R8:
*r = jsval_number(V_R8(var));
return S_OK;
case VT_BSTR: {
BSTR str;
if(V_BSTR(var)) {
str = clone_bstr(V_BSTR(var));
if(!str)
return E_OUTOFMEMORY;
}else {
str = NULL;
}
Jacek Caban
committed
*r = jsval_string(str);
return S_OK;
}
case VT_DISPATCH: {
if(V_DISPATCH(var))
IDispatch_AddRef(V_DISPATCH(var));
Jacek Caban
committed
*r = jsval_disp(V_DISPATCH(var));
return S_OK;
}
case VT_I2:
*r = jsval_number(V_I2(var));
return S_OK;
Jacek Caban
committed
case VT_INT:
*r = jsval_number(V_INT(var));
return S_OK;
Jacek Caban
committed
default:
return jsval_variant(r, var);
}
}
HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
{
switch(val.type) {
case JSV_UNDEFINED:
V_VT(retv) = VT_EMPTY;
return S_OK;
case JSV_NULL:
V_VT(retv) = VT_NULL;
return S_OK;
case JSV_OBJECT:
V_VT(retv) = VT_DISPATCH;
if(val.u.obj)
IDispatch_AddRef(val.u.obj);
Jacek Caban
committed
V_DISPATCH(retv) = val.u.obj;
return S_OK;
case JSV_STRING:
V_VT(retv) = VT_BSTR;
if(val.u.str) {
V_BSTR(retv) = clone_bstr(val.u.str);
if(!V_BSTR(retv))
return E_OUTOFMEMORY;
}else {
V_BSTR(retv) = NULL;
}
Jacek Caban
committed
return S_OK;
case JSV_NUMBER:
num_set_val(retv, val.u.n);
return S_OK;
case JSV_BOOL:
V_VT(retv) = VT_BOOL;
V_BOOL(retv) = val.u.b ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
case JSV_VARIANT:
V_VT(retv) = VT_EMPTY;
Jacek Caban
committed
return VariantCopy(retv, val.u.v);
}
assert(0);
return E_FAIL;
}
/* ECMA-262 3rd Edition 9.1 */
HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret, hint_t hint)
{
switch(V_VT(v)) {
case VT_EMPTY:
case VT_NULL:
case VT_BOOL:
case VT_I4:
case VT_R8:
*ret = *v;
break;
case VT_BSTR:
V_VT(ret) = VT_BSTR;
V_BSTR(ret) = SysAllocString(V_BSTR(v));
break;
jsdisp_t *jsdisp;
DISPID id;
HRESULT hres;
static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
if(!V_DISPATCH(v)) {
V_VT(ret) = VT_NULL;
break;
}
jsdisp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
jsval_t val;
HRESULT hres;
hres = disp_propget(ctx, V_DISPATCH(v), DISPID_VALUE, &val, ei);
if(FAILED(hres))
return hres;
hres = jsval_to_variant(val, ret);
jsval_release(val);
return hres;
if(hint == NO_HINT)
hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
/* Native implementation doesn't throw TypeErrors, returns strange values */
hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id);
if(SUCCEEDED(hres)) {
hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, ret, ei);
WARN("call error - forwarding exception\n");
jsdisp_release(jsdisp);
return hres;
}
else if(V_VT(ret) != VT_DISPATCH) {
jsdisp_release(jsdisp);
return S_OK;
}
else
IDispatch_Release(V_DISPATCH(ret));
}
hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id);
if(SUCCEEDED(hres)) {
hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, ret, ei);
WARN("call error - forwarding exception\n");
jsdisp_release(jsdisp);
return hres;
}
else if(V_VT(ret) != VT_DISPATCH) {
jsdisp_release(jsdisp);
return S_OK;
}
else
IDispatch_Release(V_DISPATCH(ret));
}
jsdisp_release(jsdisp);
return throw_type_error(ctx, ei, JS_E_TO_PRIMITIVE, NULL);
default:
FIXME("Unimplemented for vt %d\n", V_VT(v));
return E_NOTIMPL;
}
return S_OK;
}
/* ECMA-262 3rd Edition 9.1 */
HRESULT to_primitive_jsval(script_ctx_t *ctx, jsval_t val, jsexcept_t *ei, jsval_t *ret, hint_t hint)
{
if(is_object_instance(val)) {
VARIANT var, retv;
HRESULT hres;
V_VT(&var) = VT_DISPATCH;
V_DISPATCH(&var) = get_object(val);
hres = to_primitive(ctx, &var, ei, &retv, hint);
if(FAILED(hres))
return hres;
hres = variant_to_jsval(&retv, ret);
VariantClear(&retv);
return hres;
}
return jsval_copy(val, ret);
}
/* ECMA-262 3rd Edition 9.2 */
HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
{
switch(V_VT(v)) {
case VT_EMPTY:
case VT_NULL:
*b = VARIANT_FALSE;
break;
case VT_I4:
*b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
break;
case VT_R8:
if(isnan(V_R8(v))) *b = VARIANT_FALSE;
else *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
break;
case VT_BSTR:
*b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
break;
case VT_DISPATCH:
*b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
break;
case VT_BOOL:
*b = V_BOOL(v);
break;
default:
FIXME("unimplemented for vt %d\n", V_VT(v));
return E_NOTIMPL;
}
return S_OK;
}
/* ECMA-262 3rd Edition 9.2 */
HRESULT to_boolean_jsval(jsval_t v, BOOL *ret)
{
VARIANT_BOOL b;
VARIANT var;
HRESULT hres;
if(v.type == JSV_BOOL) {
*ret = v.u.b;
return S_OK;
}
hres = jsval_to_variant(v, &var);
if(FAILED(hres))
return hres;
hres = to_boolean(&var, &b);
VariantClear(&var);
if(FAILED(hres))
return hres;
*ret = !!b;
return S_OK;
}
static int hex_to_int(WCHAR c)
{
if('0' <= c && c <= '9')
return c-'0';
if('a' <= c && c <= 'f')
return c-'a'+10;
if('A' <= c && c <= 'F')
return c-'A'+10;
return -1;
}
/* ECMA-262 3rd Edition 9.3.1 */
static HRESULT str_to_number(BSTR str, double *ret)
{
const WCHAR *ptr = str;
BOOL neg = FALSE;
DOUBLE d = 0.0;
static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
if(!ptr) {
*ret = 0;
return S_OK;
}
while(isspaceW(*ptr))
ptr++;
if(*ptr == '-') {
neg = TRUE;
ptr++;
}else if(*ptr == '+') {
ptr++;
}
if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
ptr += sizeof(infinityW)/sizeof(WCHAR);
while(*ptr && isspaceW(*ptr))
ptr++;
*ret = neg ? -INFINITY : INFINITY;
if(*ptr == '0' && ptr[1] == 'x') {
DWORD l = 0;
ptr += 2;
while((l = hex_to_int(*ptr)) != -1) {
d = d*16 + l;
ptr++;
}
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
return S_OK;
}
while(isdigitW(*ptr))
d = d*10 + (*ptr++ - '0');
if(*ptr == 'e' || *ptr == 'E') {
BOOL eneg = FALSE;
LONG l = 0;
ptr++;
if(*ptr == '-') {
ptr++;
eneg = TRUE;
}else if(*ptr == '+') {
ptr++;
}
while(isdigitW(*ptr))
l = l*10 + (*ptr++ - '0');
if(eneg)
l = -l;
d *= pow(10, l);
}else if(*ptr == '.') {
DOUBLE dec = 0.1;
ptr++;
while(isdigitW(*ptr)) {
d += dec * (*ptr++ - '0');
dec *= 0.1;
}
}
while(isspaceW(*ptr))
ptr++;
if(*ptr) {
}
if(neg)
d = -d;
return S_OK;
}
/* ECMA-262 3rd Edition 9.3 */
HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, double *ret)
case VT_EMPTY:
case VT_NULL:
*ret = V_I4(v);
break;
case VT_BSTR:
return str_to_number(V_BSTR(v), ret);
case VT_DISPATCH: {
VARIANT prim;
HRESULT hres;
hres = to_primitive(ctx, v, ei, &prim, HINT_NUMBER);
if(FAILED(hres))
return hres;
hres = to_number(ctx, &prim, ei, ret);
VariantClear(&prim);
return hres;
}
case VT_BOOL:
*ret = V_BOOL(v) ? 1 : 0;
default:
FIXME("unimplemented for vt %d\n", V_VT(v));
return E_NOTIMPL;
}
return S_OK;
}
Jacek Caban
committed
/* ECMA-262 3rd Edition 9.3 */
HRESULT to_number_jsval(script_ctx_t *ctx, jsval_t v, jsexcept_t *ei, double *ret)
{
VARIANT var;
HRESULT hres;
if(v.type == JSV_NUMBER) {
*ret = v.u.n;
return S_OK;
}
hres = jsval_to_variant(v, &var);
if(FAILED(hres))
return hres;
hres = to_number(ctx, &var, ei, ret);
VariantClear(&var);
return hres;
}
/* ECMA-262 3rd Edition 9.4 */
HRESULT to_integer(script_ctx_t *ctx, jsval_t v, jsexcept_t *ei, double *ret)
hres = to_number_jsval(ctx, v, ei, &n);
if(FAILED(hres))
return hres;
if(isnan(n))
*ret = 0;
else
*ret = n >= 0.0 ? floor(n) : -floor(-n);
/* ECMA-262 3rd Edition 9.5 */
HRESULT to_int32_var(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
if(V_VT(v) == VT_I4) {
*ret = V_I4(v);
return S_OK;
}
hres = to_number(ctx, v, ei, &n);
if(FAILED(hres))
return hres;
*ret = isnan(n) || isinf(n) ? 0 : n;
/* ECMA-262 3rd Edition 9.5 */
HRESULT to_int32(script_ctx_t *ctx, jsval_t v, jsexcept_t *ei, INT *ret)
{
double n;
HRESULT hres;
hres = to_number_jsval(ctx, v, ei, &n);
if(FAILED(hres))
return hres;
*ret = isnan(n) || isinf(n) ? 0 : n;
return S_OK;
}
/* ECMA-262 3rd Edition 9.6 */
HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
{
if(V_VT(v) == VT_I4) {
*ret = V_I4(v);
return S_OK;
}
hres = to_number(ctx, v, ei, &n);
if(FAILED(hres))
return hres;
*ret = isnan(n) || isinf(n) ? 0 : n;
/* ECMA-262 3rd Edition 9.6 */
HRESULT to_uint32_jsval(script_ctx_t *ctx, jsval_t v, jsexcept_t *ei, DWORD *ret)
{
VARIANT var;
HRESULT hres;
hres = jsval_to_variant(v, &var);
if(FAILED(hres))
return hres;
hres = to_uint32(ctx, &var, ei, ret);
VariantClear(&var);
return hres;
}
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
{
WCHAR buf[12], *p;
BOOL neg = FALSE;
if(!i) {
static const WCHAR zeroW[] = {'0',0};
return SysAllocString(zeroW);
}
if(i < 0) {
neg = TRUE;
i = -i;
}
p = buf + sizeof(buf)/sizeof(*buf)-1;
*p-- = 0;
while(i) {
*p-- = i%10 + '0';
i /= 10;
}
if(neg)
*p = '-';
else
p++;
return SysAllocString(p);
}
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
HRESULT double_to_bstr(double n, BSTR *str)
{
const WCHAR NaNW[] = {'N','a','N',0};
const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
if(isnan(n)) {
*str = SysAllocString(NaNW);
}else if(isinf(n)) {
*str = SysAllocString(n<0 ? InfinityW : InfinityW+1);
}else {
VARIANT strv, v;
HRESULT hres;
V_VT(&v) = VT_R8;
V_R8(&v) = n;
V_VT(&strv) = VT_EMPTY;
hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
if(FAILED(hres))
return hres;
*str = V_BSTR(&strv);
}
return *str ? S_OK : E_OUTOFMEMORY;
}
/* ECMA-262 3rd Edition 9.8 */
HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
{
const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
const WCHAR nullW[] = {'n','u','l','l',0};
const WCHAR trueW[] = {'t','r','u','e',0};
const WCHAR falseW[] = {'f','a','l','s','e',0};
case VT_EMPTY:
*str = SysAllocString(undefinedW);
break;
case VT_NULL:
*str = SysAllocString(nullW);
break;
case VT_I4:
*str = int_to_bstr(V_I4(v));
break;
return double_to_bstr(V_R8(v), str);
case VT_BSTR:
*str = SysAllocString(V_BSTR(v));
case VT_DISPATCH: {
VARIANT prim;
HRESULT hres;
hres = to_primitive(ctx, v, ei, &prim, HINT_STRING);
if(FAILED(hres))
return hres;
hres = to_string(ctx, &prim, ei, str);
VariantClear(&prim);
return hres;
}
case VT_BOOL:
*str = SysAllocString(V_BOOL(v) ? trueW : falseW);
break;
default:
FIXME("unsupported vt %d\n", V_VT(v));
return *str ? S_OK : E_OUTOFMEMORY;
Jacek Caban
committed
/* ECMA-262 3rd Edition 9.8 */
HRESULT to_string_jsval(script_ctx_t *ctx, jsval_t v, jsexcept_t *ei, BSTR *str)
{
VARIANT var;
HRESULT hres;
if(v.type == JSV_STRING) {
*str = clone_bstr(v.u.str);
return *str ? S_OK : E_OUTOFMEMORY;
}
hres = jsval_to_variant(v, &var);
if(FAILED(hres))
return hres;
hres = to_string(ctx, &var, ei, str);
VariantClear(&var);
return hres;
}
/* ECMA-262 3rd Edition 9.9 */
HRESULT to_object(script_ctx_t *ctx, VARIANT *v, IDispatch **disp)
jsdisp_t *dispex;
HRESULT hres;
hres = create_string(ctx, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
if(FAILED(hres))
return hres;
break;
case VT_I4:
case VT_R8:
hres = create_number(ctx, num_val(v), &dispex);
if(FAILED(hres))
return hres;
if(V_DISPATCH(v)) {
IDispatch_AddRef(V_DISPATCH(v));
*disp = V_DISPATCH(v);
}else {
jsdisp_t *obj;
hres = create_object(ctx, NULL, &obj);
if(FAILED(hres))
return hres;
hres = create_bool(ctx, V_BOOL(v), &dispex);
if(FAILED(hres))
return hres;
*disp = to_disp(dispex);
break;
case VT_ARRAY|VT_VARIANT:
hres = create_vbarray(ctx, V_ARRAY(v), &dispex);
if(FAILED(hres))
return hres;
default:
FIXME("unsupported vt %d\n", V_VT(v));
return E_NOTIMPL;
}
return S_OK;
}
/* ECMA-262 3rd Edition 9.9 */
HRESULT to_object_jsval(script_ctx_t *ctx, jsval_t v, IDispatch **disp)
{
VARIANT var;
HRESULT hres;
if(is_object_instance(v)) {
*disp = get_object(v);
IDispatch_AddRef(*disp);
return S_OK;
}
hres = jsval_to_variant(v, &var);
if(FAILED(hres))
return hres;
return to_object(ctx, &var, disp);