jscript: Fix warning with older compilers.
[wine] / dlls / jscript / jsutils.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <math.h>
23 #include <assert.h>
24
25 #include "jscript.h"
26 #include "engine.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
31 WINE_DECLARE_DEBUG_CHANNEL(heap);
32
33 const char *debugstr_variant(const VARIANT *v)
34 {
35     if(!v)
36         return "(null)";
37
38     switch(V_VT(v)) {
39     case VT_EMPTY:
40         return "{VT_EMPTY}";
41     case VT_NULL:
42         return "{VT_NULL}";
43     case VT_I4:
44         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
45     case VT_UI4:
46         return wine_dbg_sprintf("{VT_UI4: %u}", V_UI4(v));
47     case VT_R8:
48         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
49     case VT_BSTR:
50         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
51     case VT_DISPATCH:
52         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
53     case VT_BOOL:
54         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
55     case VT_ARRAY|VT_VARIANT:
56         return "{VT_ARRAY|VT_VARIANT: ...}";
57     default:
58         return wine_dbg_sprintf("{vt %d}", V_VT(v));
59     }
60 }
61
62 const char *debugstr_jsval(const jsval_t v)
63 {
64     switch(jsval_type(v)) {
65     case JSV_UNDEFINED:
66         return "undefined";
67     case JSV_NULL:
68         return "null";
69     case JSV_OBJECT:
70         return wine_dbg_sprintf("obj(%p)", get_object(v));
71     case JSV_STRING:
72         return wine_dbg_sprintf("str(%s)", debugstr_jsstr(get_string(v)));
73     case JSV_NUMBER:
74         return wine_dbg_sprintf("%lf", get_number(v));
75     case JSV_BOOL:
76         return get_bool(v) ? "true" : "false";
77     case JSV_VARIANT:
78         return debugstr_variant(get_variant(v));
79     }
80
81     assert(0);
82     return NULL;
83 }
84
85 #define MIN_BLOCK_SIZE  128
86 #define ARENA_FREE_FILLER  0xaa
87
88 static inline DWORD block_size(DWORD block)
89 {
90     return MIN_BLOCK_SIZE << block;
91 }
92
93 void heap_pool_init(heap_pool_t *heap)
94 {
95     memset(heap, 0, sizeof(*heap));
96     list_init(&heap->custom_blocks);
97 }
98
99 void *heap_pool_alloc(heap_pool_t *heap, DWORD size)
100 {
101     struct list *list;
102     void *tmp;
103
104     if(!heap->block_cnt) {
105         if(!heap->blocks) {
106             heap->blocks = heap_alloc(sizeof(void*));
107             if(!heap->blocks)
108                 return NULL;
109         }
110
111         tmp = heap_alloc(block_size(0));
112         if(!tmp)
113             return NULL;
114
115         heap->blocks[0] = tmp;
116         heap->block_cnt = 1;
117     }
118
119     if(heap->offset + size <= block_size(heap->last_block)) {
120         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
121         heap->offset += size;
122         return tmp;
123     }
124
125     if(size <= block_size(heap->last_block+1)) {
126         if(heap->last_block+1 == heap->block_cnt) {
127             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
128             if(!tmp)
129                 return NULL;
130
131             heap->blocks = tmp;
132             heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
133             if(!heap->blocks[heap->block_cnt])
134                 return NULL;
135
136             heap->block_cnt++;
137         }
138
139         heap->last_block++;
140         heap->offset = size;
141         return heap->blocks[heap->last_block];
142     }
143
144     list = heap_alloc(size + sizeof(struct list));
145     if(!list)
146         return NULL;
147
148     list_add_head(&heap->custom_blocks, list);
149     return list+1;
150 }
151
152 void *heap_pool_grow(heap_pool_t *heap, void *mem, DWORD size, DWORD inc)
153 {
154     void *ret;
155
156     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
157        && heap->offset+inc < block_size(heap->last_block)) {
158         heap->offset += inc;
159         return mem;
160     }
161
162     ret = heap_pool_alloc(heap, size+inc);
163     if(ret) /* FIXME: avoid copying for custom blocks */
164         memcpy(ret, mem, size);
165     return ret;
166 }
167
168 void heap_pool_clear(heap_pool_t *heap)
169 {
170     struct list *tmp;
171
172     if(!heap)
173         return;
174
175     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
176         list_remove(tmp);
177         heap_free(tmp);
178     }
179
180     if(WARN_ON(heap)) {
181         DWORD i;
182
183         for(i=0; i < heap->block_cnt; i++)
184             memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
185     }
186
187     heap->last_block = heap->offset = 0;
188     heap->mark = FALSE;
189 }
190
191 void heap_pool_free(heap_pool_t *heap)
192 {
193     DWORD i;
194
195     heap_pool_clear(heap);
196
197     for(i=0; i < heap->block_cnt; i++)
198         heap_free(heap->blocks[i]);
199     heap_free(heap->blocks);
200
201     heap_pool_init(heap);
202 }
203
204 heap_pool_t *heap_pool_mark(heap_pool_t *heap)
205 {
206     if(heap->mark)
207         return NULL;
208
209     heap->mark = TRUE;
210     return heap;
211 }
212
213 void jsval_release(jsval_t val)
214 {
215     switch(jsval_type(val)) {
216     case JSV_OBJECT:
217         if(get_object(val))
218             IDispatch_Release(get_object(val));
219         break;
220     case JSV_STRING:
221         jsstr_release(get_string(val));
222         break;
223     case JSV_VARIANT:
224         VariantClear(get_variant(val));
225         heap_free(get_variant(val));
226         break;
227     default:
228         break;
229     }
230 }
231
232 static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
233 {
234     VARIANT *v;
235     HRESULT hres;
236
237     __JSVAL_TYPE(*val) = JSV_VARIANT;
238     __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
239     if(!v)
240         return E_OUTOFMEMORY;
241
242     V_VT(v) = VT_EMPTY;
243     hres = VariantCopy(v, var);
244     if(FAILED(hres))
245         heap_free(v);
246     return hres;
247 }
248
249 HRESULT jsval_copy(jsval_t v, jsval_t *r)
250 {
251     switch(jsval_type(v)) {
252     case JSV_UNDEFINED:
253     case JSV_NULL:
254     case JSV_NUMBER:
255     case JSV_BOOL:
256         *r = v;
257         return S_OK;
258     case JSV_OBJECT:
259         if(get_object(v))
260             IDispatch_AddRef(get_object(v));
261         *r = v;
262         return S_OK;
263     case JSV_STRING: {
264         jsstr_addref(get_string(v));
265         *r = v;
266         return S_OK;
267     }
268     case JSV_VARIANT:
269         return jsval_variant(r, get_variant(v));
270     }
271
272     assert(0);
273     return E_FAIL;
274 }
275
276 HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
277 {
278     switch(V_VT(var)) {
279     case VT_EMPTY:
280         *r = jsval_undefined();
281         return S_OK;
282     case VT_NULL:
283         *r = jsval_null();
284         return S_OK;
285     case VT_BOOL:
286         *r = jsval_bool(V_BOOL(var));
287         return S_OK;
288     case VT_I4:
289         *r = jsval_number(V_I4(var));
290         return S_OK;
291     case VT_R8:
292         *r = jsval_number(V_R8(var));
293         return S_OK;
294     case VT_BSTR: {
295         jsstr_t *str;
296
297         str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var)));
298         if(!str)
299             return E_OUTOFMEMORY;
300         if(!V_BSTR(var))
301             str->length_flags |= JSSTR_FLAG_NULLBSTR;
302
303         *r = jsval_string(str);
304         return S_OK;
305     }
306     case VT_DISPATCH: {
307         if(V_DISPATCH(var))
308             IDispatch_AddRef(V_DISPATCH(var));
309         *r = jsval_disp(V_DISPATCH(var));
310         return S_OK;
311     }
312     case VT_I2:
313         *r = jsval_number(V_I2(var));
314         return S_OK;
315     case VT_INT:
316         *r = jsval_number(V_INT(var));
317         return S_OK;
318     case VT_UNKNOWN:
319         if(V_UNKNOWN(var)) {
320             IDispatch *disp;
321             HRESULT hres;
322
323             hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp);
324             if(SUCCEEDED(hres)) {
325                 *r = jsval_disp(disp);
326                 return S_OK;
327             }
328         }
329         /* fall through */
330     default:
331         return jsval_variant(r, var);
332     }
333 }
334
335 HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
336 {
337     switch(jsval_type(val)) {
338     case JSV_UNDEFINED:
339         V_VT(retv) = VT_EMPTY;
340         return S_OK;
341     case JSV_NULL:
342         V_VT(retv) = VT_NULL;
343         return S_OK;
344     case JSV_OBJECT:
345         V_VT(retv) = VT_DISPATCH;
346         if(get_object(val))
347             IDispatch_AddRef(get_object(val));
348         V_DISPATCH(retv) = get_object(val);
349         return S_OK;
350     case JSV_STRING: {
351         jsstr_t *str = get_string(val);
352
353         V_VT(retv) = VT_BSTR;
354         if(str->length_flags & JSSTR_FLAG_NULLBSTR) {
355             V_BSTR(retv) = NULL;
356         }else {
357             V_BSTR(retv) = SysAllocStringLen(NULL, jsstr_length(str));
358             if(V_BSTR(retv))
359                 jsstr_flush(str, V_BSTR(retv));
360             else
361                 return E_OUTOFMEMORY;
362         }
363         return S_OK;
364     }
365     case JSV_NUMBER: {
366         double n = get_number(val);
367
368         if(is_int32(n)) {
369             V_VT(retv) = VT_I4;
370             V_I4(retv) = n;
371         }else {
372             V_VT(retv) = VT_R8;
373             V_R8(retv) = n;
374         }
375
376         return S_OK;
377     }
378     case JSV_BOOL:
379         V_VT(retv) = VT_BOOL;
380         V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE;
381         return S_OK;
382     case JSV_VARIANT:
383         V_VT(retv) = VT_EMPTY;
384         return VariantCopy(retv, get_variant(val));
385     }
386
387     assert(0);
388     return E_FAIL;
389 }
390
391 /* ECMA-262 3rd Edition    9.1 */
392 HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
393 {
394     if(is_object_instance(val)) {
395         jsdisp_t *jsdisp;
396         jsval_t prim;
397         DISPID id;
398         HRESULT hres;
399
400         static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
401         static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
402
403         if(!get_object(val)) {
404             *ret = jsval_null();
405             return S_OK;
406         }
407
408         jsdisp = iface_to_jsdisp((IUnknown*)get_object(val));
409         if(!jsdisp)
410             return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
411
412         if(hint == NO_HINT)
413             hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
414
415         /* Native implementation doesn't throw TypeErrors, returns strange values */
416
417         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id);
418         if(SUCCEEDED(hres)) {
419             hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
420             if(FAILED(hres)) {
421                 WARN("call error - forwarding exception\n");
422                 jsdisp_release(jsdisp);
423                 return hres;
424             }else if(!is_object_instance(prim)) {
425                 jsdisp_release(jsdisp);
426                 *ret = prim;
427                 return S_OK;
428             }else {
429                 IDispatch_Release(get_object(prim));
430             }
431         }
432
433         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id);
434         if(SUCCEEDED(hres)) {
435             hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
436             if(FAILED(hres)) {
437                 WARN("call error - forwarding exception\n");
438                 jsdisp_release(jsdisp);
439                 return hres;
440             }else if(!is_object_instance(prim)) {
441                 jsdisp_release(jsdisp);
442                 *ret = prim;
443                 return S_OK;
444             }else {
445                 IDispatch_Release(get_object(prim));
446             }
447         }
448
449         jsdisp_release(jsdisp);
450
451         WARN("failed\n");
452         return throw_type_error(ctx, JS_E_TO_PRIMITIVE, NULL);
453     }
454
455     return jsval_copy(val, ret);
456
457 }
458
459 /* ECMA-262 3rd Edition    9.2 */
460 HRESULT to_boolean(jsval_t val, BOOL *ret)
461 {
462     switch(jsval_type(val)) {
463     case JSV_UNDEFINED:
464     case JSV_NULL:
465         *ret = FALSE;
466         return S_OK;
467     case JSV_OBJECT:
468         *ret = get_object(val) != NULL;
469         return S_OK;
470     case JSV_STRING:
471         *ret = jsstr_length(get_string(val)) != 0;
472         return S_OK;
473     case JSV_NUMBER:
474         *ret = !isnan(get_number(val)) && get_number(val);
475         return S_OK;
476     case JSV_BOOL:
477         *ret = get_bool(val);
478         return S_OK;
479     case JSV_VARIANT:
480         FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
481         return E_NOTIMPL;
482     }
483
484     assert(0);
485     return E_FAIL;
486 }
487
488 static int hex_to_int(WCHAR c)
489 {
490     if('0' <= c && c <= '9')
491         return c-'0';
492
493     if('a' <= c && c <= 'f')
494         return c-'a'+10;
495
496     if('A' <= c && c <= 'F')
497         return c-'A'+10;
498
499     return -1;
500 }
501
502 /* ECMA-262 3rd Edition    9.3.1 */
503 static HRESULT str_to_number(jsstr_t *str, double *ret)
504 {
505     const WCHAR *ptr = str->str;
506     BOOL neg = FALSE;
507     DOUBLE d = 0.0;
508
509     static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
510
511     if(!ptr) {
512         *ret = 0;
513         return S_OK;
514     }
515
516     while(isspaceW(*ptr))
517         ptr++;
518
519     if(*ptr == '-') {
520         neg = TRUE;
521         ptr++;
522     }else if(*ptr == '+') {
523         ptr++;
524     }
525
526     if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
527         ptr += sizeof(infinityW)/sizeof(WCHAR);
528         while(*ptr && isspaceW(*ptr))
529             ptr++;
530
531         if(*ptr)
532             *ret = NAN;
533         else
534             *ret = neg ? -INFINITY : INFINITY;
535         return S_OK;
536     }
537
538     if(*ptr == '0' && ptr[1] == 'x') {
539         DWORD l = 0;
540
541         ptr += 2;
542         while((l = hex_to_int(*ptr)) != -1) {
543             d = d*16 + l;
544             ptr++;
545         }
546
547         *ret = d;
548         return S_OK;
549     }
550
551     while(isdigitW(*ptr))
552         d = d*10 + (*ptr++ - '0');
553
554     if(*ptr == 'e' || *ptr == 'E') {
555         BOOL eneg = FALSE;
556         LONG l = 0;
557
558         ptr++;
559         if(*ptr == '-') {
560             ptr++;
561             eneg = TRUE;
562         }else if(*ptr == '+') {
563             ptr++;
564         }
565
566         while(isdigitW(*ptr))
567             l = l*10 + (*ptr++ - '0');
568         if(eneg)
569             l = -l;
570
571         d *= pow(10, l);
572     }else if(*ptr == '.') {
573         DOUBLE dec = 0.1;
574
575         ptr++;
576         while(isdigitW(*ptr)) {
577             d += dec * (*ptr++ - '0');
578             dec *= 0.1;
579         }
580     }
581
582     while(isspaceW(*ptr))
583         ptr++;
584
585     if(*ptr) {
586         *ret = NAN;
587         return S_OK;
588     }
589
590     if(neg)
591         d = -d;
592
593     *ret = d;
594     return S_OK;
595 }
596
597 /* ECMA-262 3rd Edition    9.3 */
598 HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret)
599 {
600     switch(jsval_type(val)) {
601     case JSV_UNDEFINED:
602         *ret = NAN;
603         return S_OK;
604     case JSV_NULL:
605         *ret = 0;
606         return S_OK;
607     case JSV_NUMBER:
608         *ret = get_number(val);
609         return S_OK;
610     case JSV_STRING:
611         return str_to_number(get_string(val), ret);
612     case JSV_OBJECT: {
613         jsval_t prim;
614         HRESULT hres;
615
616         hres = to_primitive(ctx, val, &prim, HINT_NUMBER);
617         if(FAILED(hres))
618             return hres;
619
620         hres = to_number(ctx, prim, ret);
621         jsval_release(prim);
622         return hres;
623     }
624     case JSV_BOOL:
625         *ret = get_bool(val) ? 1 : 0;
626         return S_OK;
627     case JSV_VARIANT:
628         FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
629         return E_NOTIMPL;
630     };
631
632     assert(0);
633     return E_FAIL;
634 }
635
636 /* ECMA-262 3rd Edition    9.4 */
637 HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret)
638 {
639     double n;
640     HRESULT hres;
641
642     hres = to_number(ctx, v, &n);
643     if(FAILED(hres))
644         return hres;
645
646     if(isnan(n))
647         *ret = 0;
648     else
649         *ret = n >= 0.0 ? floor(n) : -floor(-n);
650     return S_OK;
651 }
652
653 /* ECMA-262 3rd Edition    9.5 */
654 HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret)
655 {
656     double n;
657     HRESULT hres;
658
659     hres = to_number(ctx, v, &n);
660     if(FAILED(hres))
661         return hres;
662
663     *ret = isnan(n) || isinf(n) ? 0 : n;
664     return S_OK;
665 }
666
667 /* ECMA-262 3rd Edition    9.6 */
668 HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, DWORD *ret)
669 {
670     INT32 n;
671     HRESULT hres;
672
673     hres = to_int32(ctx, val, &n);
674     if(SUCCEEDED(hres))
675         *ret = n;
676     return hres;
677 }
678
679 static jsstr_t *int_to_string(int i)
680 {
681     WCHAR buf[12], *p;
682     BOOL neg = FALSE;
683
684     if(!i) {
685         static const WCHAR zeroW[] = {'0',0};
686         return jsstr_alloc(zeroW);
687     }
688
689     if(i < 0) {
690         neg = TRUE;
691         i = -i;
692     }
693
694     p = buf + sizeof(buf)/sizeof(*buf)-1;
695     *p-- = 0;
696     while(i) {
697         *p-- = i%10 + '0';
698         i /= 10;
699     }
700
701     if(neg)
702         *p = '-';
703     else
704         p++;
705
706     return jsstr_alloc(p);
707 }
708
709 HRESULT double_to_string(double n, jsstr_t **str)
710 {
711     const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
712
713     if(isnan(n)) {
714         *str = jsstr_nan();
715     }else if(isinf(n)) {
716         *str = jsstr_alloc(n<0 ? InfinityW : InfinityW+1);
717     }else if(is_int32(n)) {
718         *str = int_to_string(n);
719     }else {
720         VARIANT strv, v;
721         HRESULT hres;
722
723         /* FIXME: Don't use VariantChangeTypeEx */
724         V_VT(&v) = VT_R8;
725         V_R8(&v) = n;
726         V_VT(&strv) = VT_EMPTY;
727         hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
728         if(FAILED(hres))
729             return hres;
730
731         *str = jsstr_alloc(V_BSTR(&strv));
732         SysFreeString(V_BSTR(&strv));
733     }
734
735     return *str ? S_OK : E_OUTOFMEMORY;
736 }
737
738 /* ECMA-262 3rd Edition    9.8 */
739 HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
740 {
741     const WCHAR nullW[] = {'n','u','l','l',0};
742     const WCHAR trueW[] = {'t','r','u','e',0};
743     const WCHAR falseW[] = {'f','a','l','s','e',0};
744
745     switch(jsval_type(val)) {
746     case JSV_UNDEFINED:
747         *str = jsstr_undefined();
748         return S_OK;
749     case JSV_NULL:
750         *str = jsstr_alloc(nullW);
751         break;
752     case JSV_NUMBER:
753         return double_to_string(get_number(val), str);
754     case JSV_STRING:
755         *str = jsstr_addref(get_string(val));
756         break;
757     case JSV_OBJECT: {
758         jsval_t prim;
759         HRESULT hres;
760
761         hres = to_primitive(ctx, val, &prim, HINT_STRING);
762         if(FAILED(hres))
763             return hres;
764
765         hres = to_string(ctx, prim, str);
766         jsval_release(prim);
767         return hres;
768     }
769     case JSV_BOOL:
770         *str = jsstr_alloc(get_bool(val) ? trueW : falseW);
771         break;
772     default:
773         FIXME("unsupported %s\n", debugstr_jsval(val));
774         return E_NOTIMPL;
775     }
776
777     return *str ? S_OK : E_OUTOFMEMORY;
778 }
779
780 /* ECMA-262 3rd Edition    9.9 */
781 HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
782 {
783     jsdisp_t *dispex;
784     HRESULT hres;
785
786     switch(jsval_type(val)) {
787     case JSV_STRING:
788         hres = create_string(ctx, get_string(val), &dispex);
789         if(FAILED(hres))
790             return hres;
791
792         *disp = to_disp(dispex);
793         break;
794     case JSV_NUMBER:
795         hres = create_number(ctx, get_number(val), &dispex);
796         if(FAILED(hres))
797             return hres;
798
799         *disp = to_disp(dispex);
800         break;
801     case JSV_OBJECT:
802         if(get_object(val)) {
803             *disp = get_object(val);
804             IDispatch_AddRef(*disp);
805         }else {
806             jsdisp_t *obj;
807
808             hres = create_object(ctx, NULL, &obj);
809             if(FAILED(hres))
810                 return hres;
811
812             *disp = to_disp(obj);
813         }
814         break;
815     case JSV_BOOL:
816         hres = create_bool(ctx, get_bool(val), &dispex);
817         if(FAILED(hres))
818             return hres;
819
820         *disp = to_disp(dispex);
821         break;
822     case JSV_UNDEFINED:
823     case JSV_NULL:
824         WARN("object expected\n");
825         return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
826     case JSV_VARIANT:
827         switch(V_VT(get_variant(val))) {
828         case VT_ARRAY|VT_VARIANT:
829             hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex);
830             if(FAILED(hres))
831                 return hres;
832
833             *disp = to_disp(dispex);
834             break;
835
836         default:
837             FIXME("Unsupported %s\n", debugstr_variant(get_variant(val)));
838             return E_NOTIMPL;
839         }
840         break;
841     }
842
843     return S_OK;
844 }
845
846 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
847 {
848     jsval_t val;
849     HRESULT hres;
850
851     clear_ei(ctx);
852     hres = variant_to_jsval(src, &val);
853     if(FAILED(hres))
854         return hres;
855
856     switch(vt) {
857     case VT_I2:
858     case VT_I4: {
859         INT i;
860
861         hres = to_int32(ctx, val, &i);
862         if(SUCCEEDED(hres)) {
863             if(vt == VT_I4)
864                 V_I4(dst) = i;
865             else
866                 V_I2(dst) = i;
867         }
868         break;
869     }
870     case VT_R8: {
871         double n;
872         hres = to_number(ctx, val, &n);
873         if(SUCCEEDED(hres))
874             V_R8(dst) = n;
875         break;
876     }
877     case VT_R4: {
878         double n;
879
880         hres = to_number(ctx, val, &n);
881         if(SUCCEEDED(hres))
882             V_R4(dst) = n;
883         break;
884     }
885     case VT_BOOL: {
886         BOOL b;
887
888         hres = to_boolean(val, &b);
889         if(SUCCEEDED(hres))
890             V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE;
891         break;
892     }
893     case VT_BSTR: {
894         jsstr_t *str;
895
896         hres = to_string(ctx, val, &str);
897         if(FAILED(hres))
898             break;
899
900         if(str->length_flags & JSSTR_FLAG_NULLBSTR) {
901             V_BSTR(dst) = NULL;
902             break;
903         }
904
905         V_BSTR(dst) = SysAllocStringLen(NULL, jsstr_length(str));
906         if(V_BSTR(dst))
907             jsstr_flush(str, V_BSTR(dst));
908         else
909             hres = E_OUTOFMEMORY;
910         break;
911     }
912     case VT_EMPTY:
913         hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
914         break;
915     case VT_NULL:
916         hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
917         break;
918     default:
919         FIXME("vt %d not implemented\n", vt);
920         hres = E_NOTIMPL;
921     }
922
923     jsval_release(val);
924     if(FAILED(hres))
925         return hres;
926
927     V_VT(dst) = vt;
928     return S_OK;
929 }
930
931 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
932 {
933     return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
934 }
935
936 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
937 {
938     JSCaller *This = impl_from_IServiceProvider(iface);
939
940     if(IsEqualGUID(&IID_IUnknown, riid)) {
941         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
942         *ppv = &This->IServiceProvider_iface;
943     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
944         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
945         *ppv = &This->IServiceProvider_iface;
946     }else {
947         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
948         *ppv = NULL;
949         return E_NOINTERFACE;
950     }
951
952     IUnknown_AddRef((IUnknown*)*ppv);
953     return S_OK;
954 }
955
956 static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
957 {
958     JSCaller *This = impl_from_IServiceProvider(iface);
959     LONG ref = InterlockedIncrement(&This->ref);
960
961     TRACE("(%p) ref=%d\n", This, ref);
962
963     return ref;
964 }
965
966 static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
967 {
968     JSCaller *This = impl_from_IServiceProvider(iface);
969     LONG ref = InterlockedIncrement(&This->ref);
970
971     TRACE("(%p) ref=%d\n", This, ref);
972
973     if(!ref) {
974         assert(!This->ctx);
975         heap_free(This);
976     }
977
978     return ref;
979 }
980
981 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
982         REFIID riid, void **ppv)
983 {
984     JSCaller *This = impl_from_IServiceProvider(iface);
985
986     if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
987         TRACE("(%p)->(SID_VariantConversion)\n", This);
988         return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
989     }
990
991     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
992
993     *ppv = NULL;
994     return E_NOINTERFACE;
995 }
996
997 static const IServiceProviderVtbl ServiceProviderVtbl = {
998     JSCaller_QueryInterface,
999     JSCaller_AddRef,
1000     JSCaller_Release,
1001     JSCaller_QueryService
1002 };
1003
1004 HRESULT create_jscaller(script_ctx_t *ctx)
1005 {
1006     JSCaller *ret;
1007
1008     ret = heap_alloc(sizeof(*ret));
1009     if(!ret)
1010         return E_OUTOFMEMORY;
1011
1012     ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1013     ret->ref = 1;
1014     ret->ctx = ctx;
1015
1016     ctx->jscaller = ret;
1017     return S_OK;
1018 }