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