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