include: Make sure __int64 is correctly defined on PPC64.
[wine.git] / dlls / jscript / jsutils.c
blob3c3cd012490e3ca0ab6fe58862e29d2a5d1cf192
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 #define MIN_BLOCK_SIZE 128
55 #define ARENA_FREE_FILLER 0xaa
57 static inline DWORD block_size(DWORD block)
59 return MIN_BLOCK_SIZE << block;
62 void heap_pool_init(heap_pool_t *heap)
64 memset(heap, 0, sizeof(*heap));
65 list_init(&heap->custom_blocks);
68 void *heap_pool_alloc(heap_pool_t *heap, DWORD size)
70 struct list *list;
71 void *tmp;
73 if(!heap->block_cnt) {
74 if(!heap->blocks) {
75 heap->blocks = heap_alloc(sizeof(void*));
76 if(!heap->blocks)
77 return NULL;
80 tmp = heap_alloc(block_size(0));
81 if(!tmp)
82 return NULL;
84 heap->blocks[0] = tmp;
85 heap->block_cnt = 1;
88 if(heap->offset + size <= block_size(heap->last_block)) {
89 tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
90 heap->offset += size;
91 return tmp;
94 if(size <= block_size(heap->last_block+1)) {
95 if(heap->last_block+1 == heap->block_cnt) {
96 tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
97 if(!tmp)
98 return NULL;
100 heap->blocks = tmp;
101 heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
102 if(!heap->blocks[heap->block_cnt])
103 return NULL;
105 heap->block_cnt++;
108 heap->last_block++;
109 heap->offset = size;
110 return heap->blocks[heap->last_block];
113 list = heap_alloc(size + sizeof(struct list));
114 if(!list)
115 return NULL;
117 list_add_head(&heap->custom_blocks, list);
118 return list+1;
121 void *heap_pool_grow(heap_pool_t *heap, void *mem, DWORD size, DWORD inc)
123 void *ret;
125 if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
126 && heap->offset+inc < block_size(heap->last_block)) {
127 heap->offset += inc;
128 return mem;
131 ret = heap_pool_alloc(heap, size+inc);
132 if(ret) /* FIXME: avoid copying for custom blocks */
133 memcpy(ret, mem, size);
134 return ret;
137 void heap_pool_clear(heap_pool_t *heap)
139 struct list *tmp;
141 if(!heap)
142 return;
144 while((tmp = list_head(&heap->custom_blocks))) {
145 list_remove(tmp);
146 heap_free(tmp);
149 if(WARN_ON(heap)) {
150 DWORD i;
152 for(i=0; i < heap->block_cnt; i++)
153 memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
156 heap->last_block = heap->offset = 0;
157 heap->mark = FALSE;
160 void heap_pool_free(heap_pool_t *heap)
162 DWORD i;
164 heap_pool_clear(heap);
166 for(i=0; i < heap->block_cnt; i++)
167 heap_free(heap->blocks[i]);
168 heap_free(heap->blocks);
170 heap_pool_init(heap);
173 heap_pool_t *heap_pool_mark(heap_pool_t *heap)
175 if(heap->mark)
176 return NULL;
178 heap->mark = TRUE;
179 return heap;
182 void jsval_release(jsval_t val)
184 switch(jsval_type(val)) {
185 case JSV_OBJECT:
186 if(get_object(val))
187 IDispatch_Release(get_object(val));
188 break;
189 case JSV_STRING:
190 jsstr_release(get_string(val));
191 break;
192 case JSV_VARIANT:
193 VariantClear(get_variant(val));
194 heap_free(get_variant(val));
195 break;
196 default:
197 break;
201 static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
203 VARIANT *v;
204 HRESULT hres;
206 __JSVAL_TYPE(*val) = JSV_VARIANT;
207 __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
208 if(!v) {
209 *val = jsval_undefined();
210 return E_OUTOFMEMORY;
213 V_VT(v) = VT_EMPTY;
214 hres = VariantCopy(v, var);
215 if(FAILED(hres)) {
216 *val = jsval_undefined();
217 heap_free(v);
219 return hres;
222 HRESULT jsval_copy(jsval_t v, jsval_t *r)
224 switch(jsval_type(v)) {
225 case JSV_UNDEFINED:
226 case JSV_NULL:
227 case JSV_NUMBER:
228 case JSV_BOOL:
229 *r = v;
230 return S_OK;
231 case JSV_OBJECT:
232 if(get_object(v))
233 IDispatch_AddRef(get_object(v));
234 *r = v;
235 return S_OK;
236 case JSV_STRING: {
237 jsstr_addref(get_string(v));
238 *r = v;
239 return S_OK;
241 case JSV_VARIANT:
242 return jsval_variant(r, get_variant(v));
245 assert(0);
246 return E_FAIL;
249 HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
251 if(V_VT(var) == (VT_VARIANT|VT_BYREF))
252 var = V_VARIANTREF(var);
254 switch(V_VT(var)) {
255 case VT_EMPTY:
256 *r = jsval_undefined();
257 return S_OK;
258 case VT_NULL:
259 *r = jsval_null();
260 return S_OK;
261 case VT_BOOL:
262 *r = jsval_bool(V_BOOL(var));
263 return S_OK;
264 case VT_I4:
265 *r = jsval_number(V_I4(var));
266 return S_OK;
267 case VT_R8:
268 *r = jsval_number(V_R8(var));
269 return S_OK;
270 case VT_BSTR: {
271 jsstr_t *str;
273 if(V_BSTR(var)) {
274 str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var)));
275 if(!str)
276 return E_OUTOFMEMORY;
277 }else {
278 str = jsstr_null_bstr();
281 *r = jsval_string(str);
282 return S_OK;
284 case VT_DISPATCH: {
285 if(V_DISPATCH(var))
286 IDispatch_AddRef(V_DISPATCH(var));
287 *r = jsval_disp(V_DISPATCH(var));
288 return S_OK;
290 case VT_I1:
291 *r = jsval_number(V_I1(var));
292 return S_OK;
293 case VT_UI1:
294 *r = jsval_number(V_UI1(var));
295 return S_OK;
296 case VT_I2:
297 *r = jsval_number(V_I2(var));
298 return S_OK;
299 case VT_UI2:
300 *r = jsval_number(V_UI2(var));
301 return S_OK;
302 case VT_INT:
303 *r = jsval_number(V_INT(var));
304 return S_OK;
305 case VT_UI4:
306 *r = jsval_number(V_UI4(var));
307 return S_OK;
308 case VT_UI8:
310 * Native doesn't support VT_UI8 here, but it's needed for IE9+ APIs
311 * (native IE9 doesn't use jscript.dll for JavaScript).
313 *r = jsval_number(V_UI8(var));
314 return S_OK;
315 case VT_R4:
316 *r = jsval_number(V_R4(var));
317 return S_OK;
318 case VT_CY:
319 /* FIXME: Native converts VT_CY to a special kind number type, which is
320 * never converted to VT_I4 when it's converted back to VARIANT. */
321 *r = jsval_number((double)V_CY(var).int64 / 10000.0);
322 WARN("VT_CY: %lf\n", get_number(*r));
323 return S_OK;
324 case VT_UNKNOWN:
325 if(V_UNKNOWN(var)) {
326 IDispatch *disp;
327 HRESULT hres;
329 hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp);
330 if(SUCCEEDED(hres)) {
331 *r = jsval_disp(disp);
332 return S_OK;
334 }else {
335 *r = jsval_disp(NULL);
336 return S_OK;
338 /* fall through */
339 default:
340 return jsval_variant(r, var);
344 HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
346 switch(jsval_type(val)) {
347 case JSV_UNDEFINED:
348 V_VT(retv) = VT_EMPTY;
349 return S_OK;
350 case JSV_NULL:
351 V_VT(retv) = VT_NULL;
352 return S_OK;
353 case JSV_OBJECT:
354 V_VT(retv) = VT_DISPATCH;
355 if(get_object(val))
356 IDispatch_AddRef(get_object(val));
357 V_DISPATCH(retv) = get_object(val);
358 return S_OK;
359 case JSV_STRING:
360 V_VT(retv) = VT_BSTR;
361 return jsstr_to_bstr(get_string(val), &V_BSTR(retv));
362 case JSV_NUMBER: {
363 double n = get_number(val);
365 if(is_int32(n)) {
366 V_VT(retv) = VT_I4;
367 V_I4(retv) = n;
368 }else {
369 V_VT(retv) = VT_R8;
370 V_R8(retv) = n;
373 return S_OK;
375 case JSV_BOOL:
376 V_VT(retv) = VT_BOOL;
377 V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE;
378 return S_OK;
379 case JSV_VARIANT:
380 V_VT(retv) = VT_EMPTY;
381 return VariantCopy(retv, get_variant(val));
384 assert(0);
385 return E_FAIL;
388 /* ECMA-262 3rd Edition 9.1 */
389 HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
391 if(is_object_instance(val)) {
392 jsdisp_t *jsdisp;
393 jsval_t prim;
394 DISPID id;
395 HRESULT hres;
397 if(!get_object(val)) {
398 *ret = jsval_null();
399 return S_OK;
402 jsdisp = iface_to_jsdisp(get_object(val));
403 if(!jsdisp)
404 return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
406 if(hint == NO_HINT)
407 hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
409 /* Native implementation doesn't throw TypeErrors, returns strange values */
411 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? L"toString" : L"valueOf", 0, &id);
412 if(SUCCEEDED(hres)) {
413 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
414 if(FAILED(hres)) {
415 WARN("call error - forwarding exception\n");
416 jsdisp_release(jsdisp);
417 return hres;
418 }else if(!is_object_instance(prim)) {
419 jsdisp_release(jsdisp);
420 *ret = prim;
421 return S_OK;
422 }else {
423 IDispatch_Release(get_object(prim));
427 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? L"valueOf" : L"toString", 0, &id);
428 if(SUCCEEDED(hres)) {
429 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim);
430 if(FAILED(hres)) {
431 WARN("call error - forwarding exception\n");
432 jsdisp_release(jsdisp);
433 return hres;
434 }else if(!is_object_instance(prim)) {
435 jsdisp_release(jsdisp);
436 *ret = prim;
437 return S_OK;
438 }else {
439 IDispatch_Release(get_object(prim));
443 jsdisp_release(jsdisp);
445 WARN("failed\n");
446 return JS_E_TO_PRIMITIVE;
449 return jsval_copy(val, ret);
453 /* ECMA-262 3rd Edition 9.2 */
454 HRESULT to_boolean(jsval_t val, BOOL *ret)
456 switch(jsval_type(val)) {
457 case JSV_UNDEFINED:
458 case JSV_NULL:
459 *ret = FALSE;
460 return S_OK;
461 case JSV_OBJECT:
462 *ret = get_object(val) != NULL;
463 return S_OK;
464 case JSV_STRING:
465 *ret = jsstr_length(get_string(val)) != 0;
466 return S_OK;
467 case JSV_NUMBER:
468 *ret = !isnan(get_number(val)) && get_number(val);
469 return S_OK;
470 case JSV_BOOL:
471 *ret = get_bool(val);
472 return S_OK;
473 case JSV_VARIANT:
474 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
475 return E_NOTIMPL;
478 assert(0);
479 return E_FAIL;
482 static int hex_to_int(WCHAR c)
484 if('0' <= c && c <= '9')
485 return c-'0';
487 if('a' <= c && c <= 'f')
488 return c-'a'+10;
490 if('A' <= c && c <= 'F')
491 return c-'A'+10;
493 return -1;
496 /* ECMA-262 3rd Edition 9.3.1 */
497 static HRESULT str_to_number(jsstr_t *str, double *ret)
499 const WCHAR *ptr;
500 BOOL neg = FALSE;
501 DOUBLE d = 0.0;
503 static const WCHAR infinityW[] = L"Infinity";
505 ptr = jsstr_flatten(str);
506 if(!ptr)
507 return E_OUTOFMEMORY;
509 while(iswspace(*ptr))
510 ptr++;
512 if(*ptr == '-') {
513 neg = TRUE;
514 ptr++;
515 }else if(*ptr == '+') {
516 ptr++;
519 if(!wcsncmp(ptr, infinityW, ARRAY_SIZE(infinityW)-1)) {
520 ptr += ARRAY_SIZE(infinityW) - 1;
521 while(*ptr && iswspace(*ptr))
522 ptr++;
524 if(*ptr)
525 *ret = NAN;
526 else
527 *ret = neg ? -INFINITY : INFINITY;
528 return S_OK;
531 if(*ptr == '0' && ptr[1] == 'x') {
532 DWORD l = 0;
534 ptr += 2;
535 while((l = hex_to_int(*ptr)) != -1) {
536 d = d*16 + l;
537 ptr++;
540 *ret = d;
541 return S_OK;
544 while(is_digit(*ptr))
545 d = d*10 + (*ptr++ - '0');
547 if(*ptr == 'e' || *ptr == 'E') {
548 BOOL eneg = FALSE;
549 LONG l = 0;
551 ptr++;
552 if(*ptr == '-') {
553 ptr++;
554 eneg = TRUE;
555 }else if(*ptr == '+') {
556 ptr++;
559 while(is_digit(*ptr))
560 l = l*10 + (*ptr++ - '0');
561 if(eneg)
562 l = -l;
564 d *= pow(10, l);
565 }else if(*ptr == '.') {
566 DOUBLE dec = 0.1;
568 ptr++;
569 while(is_digit(*ptr)) {
570 d += dec * (*ptr++ - '0');
571 dec *= 0.1;
575 while(iswspace(*ptr))
576 ptr++;
578 if(*ptr) {
579 *ret = NAN;
580 return S_OK;
583 if(neg)
584 d = -d;
586 *ret = d;
587 return S_OK;
590 /* ECMA-262 3rd Edition 9.3 */
591 HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret)
593 switch(jsval_type(val)) {
594 case JSV_UNDEFINED:
595 *ret = NAN;
596 return S_OK;
597 case JSV_NULL:
598 *ret = 0;
599 return S_OK;
600 case JSV_NUMBER:
601 *ret = get_number(val);
602 return S_OK;
603 case JSV_STRING:
604 return str_to_number(get_string(val), ret);
605 case JSV_OBJECT: {
606 jsval_t prim;
607 HRESULT hres;
609 hres = to_primitive(ctx, val, &prim, HINT_NUMBER);
610 if(FAILED(hres))
611 return hres;
613 hres = to_number(ctx, prim, ret);
614 jsval_release(prim);
615 return hres;
617 case JSV_BOOL:
618 *ret = get_bool(val) ? 1 : 0;
619 return S_OK;
620 case JSV_VARIANT: {
621 const VARIANT *v = get_variant(val);
622 switch(V_VT(v)) {
623 case VT_DATE:
624 return variant_date_to_number(V_DATE(v), ret);
625 default:
626 FIXME("unimplemented for variant %s\n", debugstr_variant(v));
627 return E_NOTIMPL;
632 assert(0);
633 return E_FAIL;
636 /* ECMA-262 3rd Edition 9.4 */
637 HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret)
639 double n;
640 HRESULT hres;
642 hres = to_number(ctx, v, &n);
643 if(FAILED(hres))
644 return hres;
646 if(isnan(n))
647 *ret = 0;
648 else
649 *ret = n >= 0.0 ? floor(n) : -floor(-n);
650 return S_OK;
653 static INT32 double_to_int32(double number)
655 INT32 exp, result;
656 union {
657 double d;
658 INT64 n;
659 } bits;
661 bits.d = number;
662 exp = ((INT32)(bits.n >> 52) & 0x7ff) - 0x3ff;
664 /* If exponent < 0 there will be no bits to the left of the decimal point
665 * after rounding; if the exponent is > 83 then no bits of precision can be
666 * left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
667 * of fractional precision).
668 * Note this case handles 0, -0, and all infinite, NaN & denormal values. */
669 if(exp < 0 || exp > 83)
670 return 0;
672 /* Select the appropriate 32-bits from the floating point mantissa. If the
673 * exponent is 52 then the bits we need to select are already aligned to the
674 * lowest bits of the 64-bit integer representation of the number, no need
675 * to shift. If the exponent is greater than 52 we need to shift the value
676 * left by (exp - 52), if the value is less than 52 we need to shift right
677 * accordingly. */
678 result = (exp > 52) ? bits.n << (exp - 52) : bits.n >> (52 - exp);
680 /* IEEE-754 double precision values are stored omitting an implicit 1 before
681 * the decimal point; we need to reinsert this now. We may also the shifted
682 * invalid bits into the result that are not a part of the mantissa (the sign
683 * and exponent bits from the floatingpoint representation); mask these out. */
684 if(exp < 32) {
685 INT32 missing_one = 1 << exp;
686 result &= missing_one - 1;
687 result += missing_one;
690 /* If the input value was negative (we could test either 'number' or 'bits',
691 * but testing 'bits' is likely faster) invert the result appropriately. */
692 return bits.n < 0 ? -result : result;
695 /* ECMA-262 3rd Edition 9.5 */
696 HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret)
698 double n;
699 HRESULT hres;
701 hres = to_number(ctx, v, &n);
702 if(FAILED(hres))
703 return hres;
705 *ret = double_to_int32(n);
706 return S_OK;
709 /* ECMA-262 3rd Edition 9.6 */
710 HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, UINT32 *ret)
712 double n;
713 HRESULT hres;
715 hres = to_number(ctx, val, &n);
716 if(FAILED(hres))
717 return hres;
719 *ret = double_to_int32(n);
720 return S_OK;
723 HRESULT double_to_string(double n, jsstr_t **str)
725 if(isnan(n)) {
726 *str = jsstr_nan();
727 }else if(isinf(n)) {
728 *str = jsstr_alloc(n<0 ? L"-Infinity" : L"Infinity");
729 }else if(is_int32(n)) {
730 WCHAR buf[12];
731 _ltow_s(n, buf, ARRAY_SIZE(buf), 10);
732 *str = jsstr_alloc(buf);
733 }else {
734 VARIANT strv, v;
735 HRESULT hres;
737 /* FIXME: Don't use VariantChangeTypeEx */
738 V_VT(&v) = VT_R8;
739 V_R8(&v) = n;
740 V_VT(&strv) = VT_EMPTY;
741 hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
742 if(FAILED(hres))
743 return hres;
745 *str = jsstr_alloc(V_BSTR(&strv));
746 SysFreeString(V_BSTR(&strv));
749 return *str ? S_OK : E_OUTOFMEMORY;
752 /* ECMA-262 3rd Edition 9.8 */
753 HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
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(L"null");
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;
771 hres = to_primitive(ctx, val, &prim, HINT_STRING);
772 if(FAILED(hres))
773 return hres;
775 hres = to_string(ctx, prim, str);
776 jsval_release(prim);
777 return hres;
779 case JSV_BOOL:
780 *str = jsstr_alloc(get_bool(val) ? L"true" : L"false");
781 break;
782 default: {
783 const VARIANT *v = get_variant(val);
784 switch(V_VT(v))
786 case VT_DATE:
787 return variant_date_to_string(ctx, V_DATE(v), str);
788 default:
789 FIXME("unsupported %s\n", debugstr_variant(v));
790 return E_NOTIMPL;
795 return *str ? S_OK : E_OUTOFMEMORY;
798 HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str)
800 HRESULT hres;
802 hres = to_string(ctx, val, str);
803 if(FAILED(hres))
804 return hres;
806 *ret_str = jsstr_flatten(*str);
807 if(!*ret_str) {
808 jsstr_release(*str);
809 return E_OUTOFMEMORY;
812 return S_OK;
815 /* ECMA-262 3rd Edition 9.9 */
816 HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
818 jsdisp_t *dispex;
819 HRESULT hres;
821 switch(jsval_type(val)) {
822 case JSV_STRING:
823 hres = create_string(ctx, get_string(val), &dispex);
824 if(FAILED(hres))
825 return hres;
827 *disp = to_disp(dispex);
828 break;
829 case JSV_NUMBER:
830 hres = create_number(ctx, get_number(val), &dispex);
831 if(FAILED(hres))
832 return hres;
834 *disp = to_disp(dispex);
835 break;
836 case JSV_OBJECT:
837 if(get_object(val)) {
838 *disp = get_object(val);
839 IDispatch_AddRef(*disp);
840 }else {
841 jsdisp_t *obj;
843 hres = create_object(ctx, NULL, &obj);
844 if(FAILED(hres))
845 return hres;
847 *disp = to_disp(obj);
849 break;
850 case JSV_BOOL:
851 hres = create_bool(ctx, get_bool(val), &dispex);
852 if(FAILED(hres))
853 return hres;
855 *disp = to_disp(dispex);
856 break;
857 case JSV_UNDEFINED:
858 case JSV_NULL:
859 WARN("object expected\n");
860 return JS_E_OBJECT_EXPECTED;
861 case JSV_VARIANT:
862 switch(V_VT(get_variant(val))) {
863 case VT_ARRAY|VT_VARIANT:
864 hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex);
865 if(FAILED(hres))
866 return hres;
868 *disp = to_disp(dispex);
869 break;
871 default:
872 FIXME("Unsupported %s\n", debugstr_variant(get_variant(val)));
873 return E_NOTIMPL;
875 break;
878 return S_OK;
881 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
883 jsexcept_t ei;
884 jsval_t val;
885 HRESULT hres;
887 hres = variant_to_jsval(src, &val);
888 if(FAILED(hres))
889 return hres;
891 enter_script(ctx, &ei);
893 switch(vt) {
894 case VT_I2:
895 case VT_I4: {
896 INT i;
898 hres = to_int32(ctx, val, &i);
899 if(SUCCEEDED(hres)) {
900 if(vt == VT_I4)
901 V_I4(dst) = i;
902 else
903 V_I2(dst) = i;
905 break;
907 case VT_UI2: {
908 UINT32 i;
910 hres = to_uint32(ctx, val, &i);
911 if(SUCCEEDED(hres))
912 V_UI2(dst) = i;
913 break;
915 case VT_R8: {
916 double n;
917 hres = to_number(ctx, val, &n);
918 if(SUCCEEDED(hres))
919 V_R8(dst) = n;
920 break;
922 case VT_R4: {
923 double n;
925 hres = to_number(ctx, val, &n);
926 if(SUCCEEDED(hres))
927 V_R4(dst) = n;
928 break;
930 case VT_BOOL: {
931 BOOL b;
933 hres = to_boolean(val, &b);
934 if(SUCCEEDED(hres))
935 V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE;
936 break;
938 case VT_BSTR: {
939 jsstr_t *str;
941 hres = to_string(ctx, val, &str);
942 if(FAILED(hres))
943 break;
945 hres = jsstr_to_bstr(str, &V_BSTR(dst));
946 break;
948 case VT_EMPTY:
949 hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
950 break;
951 case VT_NULL:
952 hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
953 break;
954 default:
955 FIXME("vt %d not implemented\n", vt);
956 hres = E_NOTIMPL;
959 jsval_release(val);
960 leave_script(ctx, hres);
961 if(FAILED(hres))
962 return hres;
964 V_VT(dst) = vt;
965 return S_OK;
968 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
970 return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
973 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
975 JSCaller *This = impl_from_IServiceProvider(iface);
977 if(IsEqualGUID(&IID_IUnknown, riid)) {
978 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
979 *ppv = &This->IServiceProvider_iface;
980 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
981 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
982 *ppv = &This->IServiceProvider_iface;
983 }else {
984 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
985 *ppv = NULL;
986 return E_NOINTERFACE;
989 IUnknown_AddRef((IUnknown*)*ppv);
990 return S_OK;
993 static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
995 JSCaller *This = impl_from_IServiceProvider(iface);
996 LONG ref = InterlockedIncrement(&This->ref);
998 TRACE("(%p) ref=%d\n", This, ref);
1000 return ref;
1003 static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
1005 JSCaller *This = impl_from_IServiceProvider(iface);
1006 LONG ref = InterlockedIncrement(&This->ref);
1008 TRACE("(%p) ref=%d\n", This, ref);
1010 if(!ref) {
1011 assert(!This->ctx);
1012 heap_free(This);
1015 return ref;
1018 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
1019 REFIID riid, void **ppv)
1021 JSCaller *This = impl_from_IServiceProvider(iface);
1023 if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
1024 TRACE("(%p)->(SID_VariantConversion)\n", This);
1025 return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
1028 FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1030 *ppv = NULL;
1031 return E_NOINTERFACE;
1034 static const IServiceProviderVtbl ServiceProviderVtbl = {
1035 JSCaller_QueryInterface,
1036 JSCaller_AddRef,
1037 JSCaller_Release,
1038 JSCaller_QueryService
1041 HRESULT create_jscaller(script_ctx_t *ctx)
1043 JSCaller *ret;
1045 ret = heap_alloc(sizeof(*ret));
1046 if(!ret)
1047 return E_OUTOFMEMORY;
1049 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1050 ret->ref = 1;
1051 ret->ctx = ctx;
1053 ctx->jscaller = ret;
1054 return S_OK;