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