libport: Remove support for PPC32.
[wine.git] / dlls / jscript / jsutils.c
blob421116f171bd1077ddfa8a4c9ac6da2ada41be78
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
20 #include <math.h>
21 #include <assert.h>
23 #include "jscript.h"
24 #include "engine.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
29 WINE_DECLARE_DEBUG_CHANNEL(heap);
31 const char *debugstr_jsval(const jsval_t v)
33 switch(jsval_type(v)) {
34 case JSV_UNDEFINED:
35 return "undefined";
36 case JSV_NULL:
37 return "null";
38 case JSV_OBJECT:
39 return wine_dbg_sprintf("obj(%p)", get_object(v));
40 case JSV_STRING:
41 return wine_dbg_sprintf("str(%s)", debugstr_jsstr(get_string(v)));
42 case JSV_NUMBER:
43 return wine_dbg_sprintf("%lf", get_number(v));
44 case JSV_BOOL:
45 return get_bool(v) ? "true" : "false";
46 case JSV_VARIANT:
47 return debugstr_variant(get_variant(v));
50 assert(0);
51 return NULL;
54 BOOL is_finite(double n)
56 return !isnan(n) && !isinf(n);
59 #define MIN_BLOCK_SIZE 128
60 #define ARENA_FREE_FILLER 0xaa
62 static inline DWORD block_size(DWORD block)
64 return MIN_BLOCK_SIZE << block;
67 void heap_pool_init(heap_pool_t *heap)
69 memset(heap, 0, sizeof(*heap));
70 list_init(&heap->custom_blocks);
73 void *heap_pool_alloc(heap_pool_t *heap, DWORD size)
75 struct list *list;
76 void *tmp;
78 if(!heap->block_cnt) {
79 if(!heap->blocks) {
80 heap->blocks = heap_alloc(sizeof(void*));
81 if(!heap->blocks)
82 return NULL;
85 tmp = heap_alloc(block_size(0));
86 if(!tmp)
87 return NULL;
89 heap->blocks[0] = tmp;
90 heap->block_cnt = 1;
93 if(heap->offset + size <= block_size(heap->last_block)) {
94 tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
95 heap->offset += size;
96 return tmp;
99 if(size <= block_size(heap->last_block+1)) {
100 if(heap->last_block+1 == heap->block_cnt) {
101 tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
102 if(!tmp)
103 return NULL;
105 heap->blocks = tmp;
106 heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
107 if(!heap->blocks[heap->block_cnt])
108 return NULL;
110 heap->block_cnt++;
113 heap->last_block++;
114 heap->offset = size;
115 return heap->blocks[heap->last_block];
118 list = heap_alloc(size + sizeof(struct list));
119 if(!list)
120 return NULL;
122 list_add_head(&heap->custom_blocks, list);
123 return list+1;
126 void *heap_pool_grow(heap_pool_t *heap, void *mem, DWORD size, DWORD inc)
128 void *ret;
130 if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
131 && heap->offset+inc < block_size(heap->last_block)) {
132 heap->offset += inc;
133 return mem;
136 ret = heap_pool_alloc(heap, size+inc);
137 if(ret) /* FIXME: avoid copying for custom blocks */
138 memcpy(ret, mem, size);
139 return ret;
142 void heap_pool_clear(heap_pool_t *heap)
144 struct list *tmp;
146 if(!heap)
147 return;
149 while((tmp = list_head(&heap->custom_blocks))) {
150 list_remove(tmp);
151 heap_free(tmp);
154 if(WARN_ON(heap)) {
155 DWORD i;
157 for(i=0; i < heap->block_cnt; i++)
158 memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
161 heap->last_block = heap->offset = 0;
162 heap->mark = FALSE;
165 void heap_pool_free(heap_pool_t *heap)
167 DWORD i;
169 heap_pool_clear(heap);
171 for(i=0; i < heap->block_cnt; i++)
172 heap_free(heap->blocks[i]);
173 heap_free(heap->blocks);
175 heap_pool_init(heap);
178 heap_pool_t *heap_pool_mark(heap_pool_t *heap)
180 if(heap->mark)
181 return NULL;
183 heap->mark = TRUE;
184 return heap;
187 void jsval_release(jsval_t val)
189 switch(jsval_type(val)) {
190 case JSV_OBJECT:
191 if(get_object(val))
192 IDispatch_Release(get_object(val));
193 break;
194 case JSV_STRING:
195 jsstr_release(get_string(val));
196 break;
197 case JSV_VARIANT:
198 VariantClear(get_variant(val));
199 heap_free(get_variant(val));
200 break;
201 default:
202 break;
206 static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
208 VARIANT *v;
209 HRESULT hres;
211 __JSVAL_TYPE(*val) = JSV_VARIANT;
212 __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
213 if(!v) {
214 *val = jsval_undefined();
215 return E_OUTOFMEMORY;
218 V_VT(v) = VT_EMPTY;
219 hres = VariantCopy(v, var);
220 if(FAILED(hres)) {
221 *val = jsval_undefined();
222 heap_free(v);
224 return hres;
227 HRESULT jsval_copy(jsval_t v, jsval_t *r)
229 switch(jsval_type(v)) {
230 case JSV_UNDEFINED:
231 case JSV_NULL:
232 case JSV_NUMBER:
233 case JSV_BOOL:
234 *r = v;
235 return S_OK;
236 case JSV_OBJECT:
237 if(get_object(v))
238 IDispatch_AddRef(get_object(v));
239 *r = v;
240 return S_OK;
241 case JSV_STRING: {
242 jsstr_addref(get_string(v));
243 *r = v;
244 return S_OK;
246 case JSV_VARIANT:
247 return jsval_variant(r, get_variant(v));
250 assert(0);
251 return E_FAIL;
254 HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
256 if(V_VT(var) == (VT_VARIANT|VT_BYREF))
257 var = V_VARIANTREF(var);
259 switch(V_VT(var)) {
260 case VT_EMPTY:
261 *r = jsval_undefined();
262 return S_OK;
263 case VT_NULL:
264 *r = jsval_null();
265 return S_OK;
266 case VT_BOOL:
267 *r = jsval_bool(V_BOOL(var));
268 return S_OK;
269 case VT_I4:
270 *r = jsval_number(V_I4(var));
271 return S_OK;
272 case VT_R8:
273 *r = jsval_number(V_R8(var));
274 return S_OK;
275 case VT_BSTR: {
276 jsstr_t *str;
278 if(V_BSTR(var)) {
279 str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var)));
280 if(!str)
281 return E_OUTOFMEMORY;
282 }else {
283 str = jsstr_null_bstr();
286 *r = jsval_string(str);
287 return S_OK;
289 case VT_DISPATCH: {
290 if(V_DISPATCH(var))
291 IDispatch_AddRef(V_DISPATCH(var));
292 *r = jsval_disp(V_DISPATCH(var));
293 return S_OK;
295 case VT_I1:
296 *r = jsval_number(V_I1(var));
297 return S_OK;
298 case VT_UI1:
299 *r = jsval_number(V_UI1(var));
300 return S_OK;
301 case VT_I2:
302 *r = jsval_number(V_I2(var));
303 return S_OK;
304 case VT_UI2:
305 *r = jsval_number(V_UI2(var));
306 return S_OK;
307 case VT_INT:
308 *r = jsval_number(V_INT(var));
309 return S_OK;
310 case VT_UI4:
311 *r = jsval_number(V_UI4(var));
312 return S_OK;
313 case VT_UI8:
315 * Native doesn't support VT_UI8 here, but it's needed for IE9+ APIs
316 * (native IE9 doesn't use jscript.dll for JavaScript).
318 *r = jsval_number(V_UI8(var));
319 return S_OK;
320 case VT_R4:
321 *r = jsval_number(V_R4(var));
322 return S_OK;
323 case VT_UNKNOWN:
324 if(V_UNKNOWN(var)) {
325 IDispatch *disp;
326 HRESULT hres;
328 hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp);
329 if(SUCCEEDED(hres)) {
330 *r = jsval_disp(disp);
331 return S_OK;
333 }else {
334 *r = jsval_disp(NULL);
335 return S_OK;
337 /* fall through */
338 default:
339 return jsval_variant(r, var);
343 HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
345 switch(jsval_type(val)) {
346 case JSV_UNDEFINED:
347 V_VT(retv) = VT_EMPTY;
348 return S_OK;
349 case JSV_NULL:
350 V_VT(retv) = VT_NULL;
351 return S_OK;
352 case JSV_OBJECT:
353 V_VT(retv) = VT_DISPATCH;
354 if(get_object(val))
355 IDispatch_AddRef(get_object(val));
356 V_DISPATCH(retv) = get_object(val);
357 return S_OK;
358 case JSV_STRING:
359 V_VT(retv) = VT_BSTR;
360 return jsstr_to_bstr(get_string(val), &V_BSTR(retv));
361 case JSV_NUMBER: {
362 double n = get_number(val);
364 if(is_int32(n)) {
365 V_VT(retv) = VT_I4;
366 V_I4(retv) = n;
367 }else {
368 V_VT(retv) = VT_R8;
369 V_R8(retv) = n;
372 return S_OK;
374 case JSV_BOOL:
375 V_VT(retv) = VT_BOOL;
376 V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE;
377 return S_OK;
378 case JSV_VARIANT:
379 V_VT(retv) = VT_EMPTY;
380 return VariantCopy(retv, get_variant(val));
383 assert(0);
384 return E_FAIL;
387 /* ECMA-262 3rd Edition 9.1 */
388 HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
390 if(is_object_instance(val)) {
391 jsdisp_t *jsdisp;
392 jsval_t prim;
393 DISPID id;
394 HRESULT hres;
396 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
397 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
399 if(!get_object(val)) {
400 *ret = jsval_null();
401 return S_OK;
404 jsdisp = iface_to_jsdisp(get_object(val));
405 if(!jsdisp)
406 return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
408 if(hint == NO_HINT)
409 hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
411 /* Native implementation doesn't throw TypeErrors, returns strange values */
413 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id);
414 if(SUCCEEDED(hres)) {
415 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
416 if(FAILED(hres)) {
417 WARN("call error - forwarding exception\n");
418 jsdisp_release(jsdisp);
419 return hres;
420 }else if(!is_object_instance(prim)) {
421 jsdisp_release(jsdisp);
422 *ret = prim;
423 return S_OK;
424 }else {
425 IDispatch_Release(get_object(prim));
429 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id);
430 if(SUCCEEDED(hres)) {
431 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
432 if(FAILED(hres)) {
433 WARN("call error - forwarding exception\n");
434 jsdisp_release(jsdisp);
435 return hres;
436 }else if(!is_object_instance(prim)) {
437 jsdisp_release(jsdisp);
438 *ret = prim;
439 return S_OK;
440 }else {
441 IDispatch_Release(get_object(prim));
445 jsdisp_release(jsdisp);
447 WARN("failed\n");
448 return JS_E_TO_PRIMITIVE;
451 return jsval_copy(val, ret);
455 /* ECMA-262 3rd Edition 9.2 */
456 HRESULT to_boolean(jsval_t val, BOOL *ret)
458 switch(jsval_type(val)) {
459 case JSV_UNDEFINED:
460 case JSV_NULL:
461 *ret = FALSE;
462 return S_OK;
463 case JSV_OBJECT:
464 *ret = get_object(val) != NULL;
465 return S_OK;
466 case JSV_STRING:
467 *ret = jsstr_length(get_string(val)) != 0;
468 return S_OK;
469 case JSV_NUMBER:
470 *ret = !isnan(get_number(val)) && get_number(val);
471 return S_OK;
472 case JSV_BOOL:
473 *ret = get_bool(val);
474 return S_OK;
475 case JSV_VARIANT:
476 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
477 return E_NOTIMPL;
480 assert(0);
481 return E_FAIL;
484 static int hex_to_int(WCHAR c)
486 if('0' <= c && c <= '9')
487 return c-'0';
489 if('a' <= c && c <= 'f')
490 return c-'a'+10;
492 if('A' <= c && c <= 'F')
493 return c-'A'+10;
495 return -1;
498 /* ECMA-262 3rd Edition 9.3.1 */
499 static HRESULT str_to_number(jsstr_t *str, double *ret)
501 const WCHAR *ptr;
502 BOOL neg = FALSE;
503 DOUBLE d = 0.0;
505 static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
507 ptr = jsstr_flatten(str);
508 if(!ptr)
509 return E_OUTOFMEMORY;
511 while(iswspace(*ptr))
512 ptr++;
514 if(*ptr == '-') {
515 neg = TRUE;
516 ptr++;
517 }else if(*ptr == '+') {
518 ptr++;
521 if(!wcsncmp(ptr, infinityW, ARRAY_SIZE(infinityW))) {
522 ptr += ARRAY_SIZE(infinityW);
523 while(*ptr && iswspace(*ptr))
524 ptr++;
526 if(*ptr)
527 *ret = NAN;
528 else
529 *ret = neg ? -INFINITY : INFINITY;
530 return S_OK;
533 if(*ptr == '0' && ptr[1] == 'x') {
534 DWORD l = 0;
536 ptr += 2;
537 while((l = hex_to_int(*ptr)) != -1) {
538 d = d*16 + l;
539 ptr++;
542 *ret = d;
543 return S_OK;
546 while(is_digit(*ptr))
547 d = d*10 + (*ptr++ - '0');
549 if(*ptr == 'e' || *ptr == 'E') {
550 BOOL eneg = FALSE;
551 LONG l = 0;
553 ptr++;
554 if(*ptr == '-') {
555 ptr++;
556 eneg = TRUE;
557 }else if(*ptr == '+') {
558 ptr++;
561 while(is_digit(*ptr))
562 l = l*10 + (*ptr++ - '0');
563 if(eneg)
564 l = -l;
566 d *= pow(10, l);
567 }else if(*ptr == '.') {
568 DOUBLE dec = 0.1;
570 ptr++;
571 while(is_digit(*ptr)) {
572 d += dec * (*ptr++ - '0');
573 dec *= 0.1;
577 while(iswspace(*ptr))
578 ptr++;
580 if(*ptr) {
581 *ret = NAN;
582 return S_OK;
585 if(neg)
586 d = -d;
588 *ret = d;
589 return S_OK;
592 /* ECMA-262 3rd Edition 9.3 */
593 HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret)
595 switch(jsval_type(val)) {
596 case JSV_UNDEFINED:
597 *ret = NAN;
598 return S_OK;
599 case JSV_NULL:
600 *ret = 0;
601 return S_OK;
602 case JSV_NUMBER:
603 *ret = get_number(val);
604 return S_OK;
605 case JSV_STRING:
606 return str_to_number(get_string(val), ret);
607 case JSV_OBJECT: {
608 jsval_t prim;
609 HRESULT hres;
611 hres = to_primitive(ctx, val, &prim, HINT_NUMBER);
612 if(FAILED(hres))
613 return hres;
615 hres = to_number(ctx, prim, ret);
616 jsval_release(prim);
617 return hres;
619 case JSV_BOOL:
620 *ret = get_bool(val) ? 1 : 0;
621 return S_OK;
622 case JSV_VARIANT:
623 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
624 return E_NOTIMPL;
627 assert(0);
628 return E_FAIL;
631 /* ECMA-262 3rd Edition 9.4 */
632 HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret)
634 double n;
635 HRESULT hres;
637 hres = to_number(ctx, v, &n);
638 if(FAILED(hres))
639 return hres;
641 if(isnan(n))
642 *ret = 0;
643 else
644 *ret = n >= 0.0 ? floor(n) : -floor(-n);
645 return S_OK;
648 static INT32 double_to_int32(double number)
650 INT32 exp, result;
651 union {
652 double d;
653 INT64 n;
654 } bits;
656 bits.d = number;
657 exp = ((INT32)(bits.n >> 52) & 0x7ff) - 0x3ff;
659 /* If exponent < 0 there will be no bits to the left of the decimal point
660 * after rounding; if the exponent is > 83 then no bits of precision can be
661 * left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
662 * of fractional precision).
663 * Note this case handles 0, -0, and all infinite, NaN & denormal values. */
664 if(exp < 0 || exp > 83)
665 return 0;
667 /* Select the appropriate 32-bits from the floating point mantissa. If the
668 * exponent is 52 then the bits we need to select are already aligned to the
669 * lowest bits of the 64-bit integer representation of the number, no need
670 * to shift. If the exponent is greater than 52 we need to shift the value
671 * left by (exp - 52), if the value is less than 52 we need to shift right
672 * accordingly. */
673 result = (exp > 52) ? bits.n << (exp - 52) : bits.n >> (52 - exp);
675 /* IEEE-754 double precision values are stored omitting an implicit 1 before
676 * the decimal point; we need to reinsert this now. We may also the shifted
677 * invalid bits into the result that are not a part of the mantissa (the sign
678 * and exponent bits from the floatingpoint representation); mask these out. */
679 if(exp < 32) {
680 INT32 missing_one = 1 << exp;
681 result &= missing_one - 1;
682 result += missing_one;
685 /* If the input value was negative (we could test either 'number' or 'bits',
686 * but testing 'bits' is likely faster) invert the result appropriately. */
687 return bits.n < 0 ? -result : result;
690 /* ECMA-262 3rd Edition 9.5 */
691 HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret)
693 double n;
694 HRESULT hres;
696 hres = to_number(ctx, v, &n);
697 if(FAILED(hres))
698 return hres;
700 *ret = double_to_int32(n);
701 return S_OK;
704 /* ECMA-262 3rd Edition 9.6 */
705 HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, UINT32 *ret)
707 double n;
708 HRESULT hres;
710 hres = to_number(ctx, val, &n);
711 if(FAILED(hres))
712 return hres;
714 *ret = double_to_int32(n);
715 return S_OK;
718 HRESULT double_to_string(double n, jsstr_t **str)
720 static const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
722 if(isnan(n)) {
723 *str = jsstr_nan();
724 }else if(isinf(n)) {
725 *str = jsstr_alloc(n<0 ? InfinityW : InfinityW+1);
726 }else if(is_int32(n)) {
727 WCHAR buf[12];
728 _ltow_s(n, buf, ARRAY_SIZE(buf), 10);
729 *str = jsstr_alloc(buf);
730 }else {
731 VARIANT strv, v;
732 HRESULT hres;
734 /* FIXME: Don't use VariantChangeTypeEx */
735 V_VT(&v) = VT_R8;
736 V_R8(&v) = n;
737 V_VT(&strv) = VT_EMPTY;
738 hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
739 if(FAILED(hres))
740 return hres;
742 *str = jsstr_alloc(V_BSTR(&strv));
743 SysFreeString(V_BSTR(&strv));
746 return *str ? S_OK : E_OUTOFMEMORY;
749 /* ECMA-262 3rd Edition 9.8 */
750 HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
752 static const WCHAR nullW[] = {'n','u','l','l',0};
753 static const WCHAR trueW[] = {'t','r','u','e',0};
754 static const WCHAR falseW[] = {'f','a','l','s','e',0};
756 switch(jsval_type(val)) {
757 case JSV_UNDEFINED:
758 *str = jsstr_undefined();
759 return S_OK;
760 case JSV_NULL:
761 *str = jsstr_alloc(nullW);
762 break;
763 case JSV_NUMBER:
764 return double_to_string(get_number(val), str);
765 case JSV_STRING:
766 *str = jsstr_addref(get_string(val));
767 break;
768 case JSV_OBJECT: {
769 jsval_t prim;
770 HRESULT hres;
772 hres = to_primitive(ctx, val, &prim, HINT_STRING);
773 if(FAILED(hres))
774 return hres;
776 hres = to_string(ctx, prim, str);
777 jsval_release(prim);
778 return hres;
780 case JSV_BOOL:
781 *str = jsstr_alloc(get_bool(val) ? trueW : falseW);
782 break;
783 default:
784 FIXME("unsupported %s\n", debugstr_jsval(val));
785 return E_NOTIMPL;
788 return *str ? S_OK : E_OUTOFMEMORY;
791 HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str)
793 HRESULT hres;
795 hres = to_string(ctx, val, str);
796 if(FAILED(hres))
797 return hres;
799 *ret_str = jsstr_flatten(*str);
800 if(!*ret_str) {
801 jsstr_release(*str);
802 return E_OUTOFMEMORY;
805 return S_OK;
808 /* ECMA-262 3rd Edition 9.9 */
809 HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
811 jsdisp_t *dispex;
812 HRESULT hres;
814 switch(jsval_type(val)) {
815 case JSV_STRING:
816 hres = create_string(ctx, get_string(val), &dispex);
817 if(FAILED(hres))
818 return hres;
820 *disp = to_disp(dispex);
821 break;
822 case JSV_NUMBER:
823 hres = create_number(ctx, get_number(val), &dispex);
824 if(FAILED(hres))
825 return hres;
827 *disp = to_disp(dispex);
828 break;
829 case JSV_OBJECT:
830 if(get_object(val)) {
831 *disp = get_object(val);
832 IDispatch_AddRef(*disp);
833 }else {
834 jsdisp_t *obj;
836 hres = create_object(ctx, NULL, &obj);
837 if(FAILED(hres))
838 return hres;
840 *disp = to_disp(obj);
842 break;
843 case JSV_BOOL:
844 hres = create_bool(ctx, get_bool(val), &dispex);
845 if(FAILED(hres))
846 return hres;
848 *disp = to_disp(dispex);
849 break;
850 case JSV_UNDEFINED:
851 case JSV_NULL:
852 WARN("object expected\n");
853 return JS_E_OBJECT_EXPECTED;
854 case JSV_VARIANT:
855 switch(V_VT(get_variant(val))) {
856 case VT_ARRAY|VT_VARIANT:
857 hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex);
858 if(FAILED(hres))
859 return hres;
861 *disp = to_disp(dispex);
862 break;
864 default:
865 FIXME("Unsupported %s\n", debugstr_variant(get_variant(val)));
866 return E_NOTIMPL;
868 break;
871 return S_OK;
874 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
876 jsexcept_t ei;
877 jsval_t val;
878 HRESULT hres;
880 hres = variant_to_jsval(src, &val);
881 if(FAILED(hres))
882 return hres;
884 enter_script(ctx, &ei);
886 switch(vt) {
887 case VT_I2:
888 case VT_I4: {
889 INT i;
891 hres = to_int32(ctx, val, &i);
892 if(SUCCEEDED(hres)) {
893 if(vt == VT_I4)
894 V_I4(dst) = i;
895 else
896 V_I2(dst) = i;
898 break;
900 case VT_UI2: {
901 UINT32 i;
903 hres = to_uint32(ctx, val, &i);
904 if(SUCCEEDED(hres))
905 V_UI2(dst) = i;
906 break;
908 case VT_R8: {
909 double n;
910 hres = to_number(ctx, val, &n);
911 if(SUCCEEDED(hres))
912 V_R8(dst) = n;
913 break;
915 case VT_R4: {
916 double n;
918 hres = to_number(ctx, val, &n);
919 if(SUCCEEDED(hres))
920 V_R4(dst) = n;
921 break;
923 case VT_BOOL: {
924 BOOL b;
926 hres = to_boolean(val, &b);
927 if(SUCCEEDED(hres))
928 V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE;
929 break;
931 case VT_BSTR: {
932 jsstr_t *str;
934 hres = to_string(ctx, val, &str);
935 if(FAILED(hres))
936 break;
938 hres = jsstr_to_bstr(str, &V_BSTR(dst));
939 break;
941 case VT_EMPTY:
942 hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
943 break;
944 case VT_NULL:
945 hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
946 break;
947 default:
948 FIXME("vt %d not implemented\n", vt);
949 hres = E_NOTIMPL;
952 jsval_release(val);
953 leave_script(ctx, hres);
954 if(FAILED(hres))
955 return hres;
957 V_VT(dst) = vt;
958 return S_OK;
961 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
963 return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
966 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
968 JSCaller *This = impl_from_IServiceProvider(iface);
970 if(IsEqualGUID(&IID_IUnknown, riid)) {
971 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
972 *ppv = &This->IServiceProvider_iface;
973 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
974 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
975 *ppv = &This->IServiceProvider_iface;
976 }else {
977 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
978 *ppv = NULL;
979 return E_NOINTERFACE;
982 IUnknown_AddRef((IUnknown*)*ppv);
983 return S_OK;
986 static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
988 JSCaller *This = impl_from_IServiceProvider(iface);
989 LONG ref = InterlockedIncrement(&This->ref);
991 TRACE("(%p) ref=%d\n", This, ref);
993 return ref;
996 static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
998 JSCaller *This = impl_from_IServiceProvider(iface);
999 LONG ref = InterlockedIncrement(&This->ref);
1001 TRACE("(%p) ref=%d\n", This, ref);
1003 if(!ref) {
1004 assert(!This->ctx);
1005 heap_free(This);
1008 return ref;
1011 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
1012 REFIID riid, void **ppv)
1014 JSCaller *This = impl_from_IServiceProvider(iface);
1016 if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
1017 TRACE("(%p)->(SID_VariantConversion)\n", This);
1018 return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
1021 FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1023 *ppv = NULL;
1024 return E_NOINTERFACE;
1027 static const IServiceProviderVtbl ServiceProviderVtbl = {
1028 JSCaller_QueryInterface,
1029 JSCaller_AddRef,
1030 JSCaller_Release,
1031 JSCaller_QueryService
1034 HRESULT create_jscaller(script_ctx_t *ctx)
1036 JSCaller *ret;
1038 ret = heap_alloc(sizeof(*ret));
1039 if(!ret)
1040 return E_OUTOFMEMORY;
1042 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1043 ret->ref = 1;
1044 ret->ctx = ctx;
1046 ctx->jscaller = ret;
1047 return S_OK;