ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / jscript / jsutils.c
blob3251abfddbf3b8a6b9c3bdbb18ab3c35472c71db
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 IDispatch_Release(get_object(val));
187 break;
188 case JSV_STRING:
189 jsstr_release(get_string(val));
190 break;
191 case JSV_VARIANT:
192 VariantClear(get_variant(val));
193 heap_free(get_variant(val));
194 break;
195 default:
196 break;
200 static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
202 VARIANT *v;
203 HRESULT hres;
205 __JSVAL_TYPE(*val) = JSV_VARIANT;
206 __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
207 if(!v) {
208 *val = jsval_undefined();
209 return E_OUTOFMEMORY;
212 V_VT(v) = VT_EMPTY;
213 hres = VariantCopy(v, var);
214 if(FAILED(hres)) {
215 *val = jsval_undefined();
216 heap_free(v);
218 return hres;
221 HRESULT jsval_copy(jsval_t v, jsval_t *r)
223 switch(jsval_type(v)) {
224 case JSV_UNDEFINED:
225 case JSV_NULL:
226 case JSV_NUMBER:
227 case JSV_BOOL:
228 *r = v;
229 return S_OK;
230 case JSV_OBJECT:
231 IDispatch_AddRef(get_object(v));
232 *r = v;
233 return S_OK;
234 case JSV_STRING: {
235 jsstr_addref(get_string(v));
236 *r = v;
237 return S_OK;
239 case JSV_VARIANT:
240 return jsval_variant(r, get_variant(v));
243 assert(0);
244 return E_FAIL;
247 HRESULT variant_to_jsval(script_ctx_t *ctx, VARIANT *var, jsval_t *r)
249 if(V_VT(var) == (VT_VARIANT|VT_BYREF))
250 var = V_VARIANTREF(var);
252 switch(V_VT(var)) {
253 case VT_EMPTY:
254 *r = jsval_undefined();
255 return S_OK;
256 case VT_NULL:
257 *r = jsval_null();
258 return S_OK;
259 case VT_BOOL:
260 *r = jsval_bool(V_BOOL(var));
261 return S_OK;
262 case VT_I4:
263 *r = jsval_number(V_I4(var));
264 return S_OK;
265 case VT_R8:
266 *r = jsval_number(V_R8(var));
267 return S_OK;
268 case VT_BSTR: {
269 jsstr_t *str;
271 if(V_BSTR(var)) {
272 str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var)));
273 if(!str)
274 return E_OUTOFMEMORY;
275 }else {
276 str = jsstr_null_bstr();
279 *r = jsval_string(str);
280 return S_OK;
282 case VT_DISPATCH: {
283 if(!V_DISPATCH(var)) {
284 *r = ctx->html_mode ? jsval_null() : jsval_null_disp();
285 return S_OK;
287 IDispatch_AddRef(V_DISPATCH(var));
288 *r = jsval_disp(V_DISPATCH(var));
289 return S_OK;
291 case VT_I1:
292 *r = jsval_number(V_I1(var));
293 return S_OK;
294 case VT_UI1:
295 *r = jsval_number(V_UI1(var));
296 return S_OK;
297 case VT_I2:
298 *r = jsval_number(V_I2(var));
299 return S_OK;
300 case VT_UI2:
301 *r = jsval_number(V_UI2(var));
302 return S_OK;
303 case VT_INT:
304 *r = jsval_number(V_INT(var));
305 return S_OK;
306 case VT_UI4:
307 *r = jsval_number(V_UI4(var));
308 return S_OK;
309 case VT_UI8:
311 * Native doesn't support VT_UI8 here, but it's needed for IE9+ APIs
312 * (native IE9 doesn't use jscript.dll for JavaScript).
314 *r = jsval_number(V_UI8(var));
315 return S_OK;
316 case VT_R4:
317 *r = jsval_number(V_R4(var));
318 return S_OK;
319 case VT_CY:
320 /* FIXME: Native converts VT_CY to a special kind number type, which is
321 * never converted to VT_I4 when it's converted back to VARIANT. */
322 *r = jsval_number((double)V_CY(var).int64 / 10000.0);
323 WARN("VT_CY: %lf\n", get_number(*r));
324 return S_OK;
325 case VT_UNKNOWN:
326 if(V_UNKNOWN(var)) {
327 IDispatch *disp;
328 HRESULT hres;
330 hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp);
331 if(SUCCEEDED(hres)) {
332 *r = jsval_disp(disp);
333 return S_OK;
335 }else {
336 *r = ctx->html_mode ? jsval_null() : jsval_null_disp();
337 return S_OK;
339 /* fall through */
340 default:
341 return jsval_variant(r, var);
345 HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
347 switch(jsval_type(val)) {
348 case JSV_UNDEFINED:
349 V_VT(retv) = VT_EMPTY;
350 return S_OK;
351 case JSV_NULL:
352 if(get_bool(val)) {
353 V_VT(retv) = VT_DISPATCH;
354 V_DISPATCH(retv) = NULL;
355 return S_OK;
357 V_VT(retv) = VT_NULL;
358 return S_OK;
359 case JSV_OBJECT:
360 V_VT(retv) = VT_DISPATCH;
361 V_DISPATCH(retv) = get_object(val);
362 IDispatch_AddRef(get_object(val));
363 return S_OK;
364 case JSV_STRING:
365 V_VT(retv) = VT_BSTR;
366 return jsstr_to_bstr(get_string(val), &V_BSTR(retv));
367 case JSV_NUMBER: {
368 double n = get_number(val);
370 if(is_int32(n)) {
371 V_VT(retv) = VT_I4;
372 V_I4(retv) = n;
373 }else {
374 V_VT(retv) = VT_R8;
375 V_R8(retv) = n;
378 return S_OK;
380 case JSV_BOOL:
381 V_VT(retv) = VT_BOOL;
382 V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE;
383 return S_OK;
384 case JSV_VARIANT:
385 V_VT(retv) = VT_EMPTY;
386 return VariantCopy(retv, get_variant(val));
389 assert(0);
390 return E_FAIL;
393 /* ECMA-262 3rd Edition 9.1 */
394 HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
396 if(is_object_instance(val)) {
397 jsdisp_t *jsdisp;
398 jsval_t prim;
399 DISPID id;
400 HRESULT hres;
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 = TRUE;
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 HRESULT to_long(script_ctx_t *ctx, jsval_t v, LONG *ret)
711 return to_int32(ctx, v, (INT*)ret);
714 /* ECMA-262 3rd Edition 9.6 */
715 HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, UINT32 *ret)
717 double n;
718 HRESULT hres;
720 hres = to_number(ctx, val, &n);
721 if(FAILED(hres))
722 return hres;
724 *ret = double_to_int32(n);
725 return S_OK;
728 HRESULT double_to_string(double n, jsstr_t **str)
730 if(isnan(n)) {
731 *str = jsstr_nan();
732 }else if(isinf(n)) {
733 *str = jsstr_alloc(n<0 ? L"-Infinity" : L"Infinity");
734 }else if(is_int32(n)) {
735 WCHAR buf[12];
736 _ltow_s(n, buf, ARRAY_SIZE(buf), 10);
737 *str = jsstr_alloc(buf);
738 }else {
739 VARIANT strv, v;
740 HRESULT hres;
742 /* FIXME: Don't use VariantChangeTypeEx */
743 V_VT(&v) = VT_R8;
744 V_R8(&v) = n;
745 V_VT(&strv) = VT_EMPTY;
746 hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
747 if(FAILED(hres))
748 return hres;
750 *str = jsstr_alloc(V_BSTR(&strv));
751 SysFreeString(V_BSTR(&strv));
754 return *str ? S_OK : E_OUTOFMEMORY;
757 /* ECMA-262 3rd Edition 9.8 */
758 HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
760 switch(jsval_type(val)) {
761 case JSV_UNDEFINED:
762 *str = jsstr_undefined();
763 return S_OK;
764 case JSV_NULL:
765 *str = jsstr_alloc(L"null");
766 break;
767 case JSV_NUMBER:
768 return double_to_string(get_number(val), str);
769 case JSV_STRING:
770 *str = jsstr_addref(get_string(val));
771 break;
772 case JSV_OBJECT: {
773 jsval_t prim;
774 HRESULT hres;
776 hres = to_primitive(ctx, val, &prim, HINT_STRING);
777 if(FAILED(hres))
778 return hres;
780 hres = to_string(ctx, prim, str);
781 jsval_release(prim);
782 return hres;
784 case JSV_BOOL:
785 *str = jsstr_alloc(get_bool(val) ? L"true" : L"false");
786 break;
787 default: {
788 const VARIANT *v = get_variant(val);
789 switch(V_VT(v))
791 case VT_DATE:
792 return variant_date_to_string(ctx, V_DATE(v), str);
793 default:
794 FIXME("unsupported %s\n", debugstr_variant(v));
795 return E_NOTIMPL;
800 return *str ? S_OK : E_OUTOFMEMORY;
803 HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str)
805 HRESULT hres;
807 hres = to_string(ctx, val, str);
808 if(FAILED(hres))
809 return hres;
811 *ret_str = jsstr_flatten(*str);
812 if(!*ret_str) {
813 jsstr_release(*str);
814 return E_OUTOFMEMORY;
817 return S_OK;
820 /* ECMA-262 3rd Edition 9.9 */
821 HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
823 jsdisp_t *dispex;
824 HRESULT hres;
826 switch(jsval_type(val)) {
827 case JSV_STRING:
828 hres = create_string(ctx, get_string(val), &dispex);
829 if(FAILED(hres))
830 return hres;
832 *disp = to_disp(dispex);
833 break;
834 case JSV_NUMBER:
835 hres = create_number(ctx, get_number(val), &dispex);
836 if(FAILED(hres))
837 return hres;
839 *disp = to_disp(dispex);
840 break;
841 case JSV_OBJECT:
842 *disp = get_object(val);
843 IDispatch_AddRef(*disp);
844 break;
845 case JSV_BOOL:
846 hres = create_bool(ctx, get_bool(val), &dispex);
847 if(FAILED(hres))
848 return hres;
850 *disp = to_disp(dispex);
851 break;
852 case JSV_NULL:
853 if(is_null_disp(val))
854 return JS_E_OBJECT_REQUIRED;
855 /* fall through */
856 case JSV_UNDEFINED:
857 WARN("object expected\n");
858 return JS_E_OBJECT_EXPECTED;
859 case JSV_VARIANT:
860 switch(V_VT(get_variant(val))) {
861 case VT_ARRAY|VT_VARIANT:
862 hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex);
863 if(FAILED(hres))
864 return hres;
866 *disp = to_disp(dispex);
867 break;
869 default:
870 FIXME("Unsupported %s\n", debugstr_variant(get_variant(val)));
871 return E_NOTIMPL;
873 break;
876 return S_OK;
879 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
881 jsexcept_t ei;
882 jsval_t val;
883 HRESULT hres;
885 hres = variant_to_jsval(ctx, src, &val);
886 if(FAILED(hres))
887 return hres;
889 enter_script(ctx, &ei);
891 switch(vt) {
892 case VT_I2:
893 case VT_I4: {
894 INT i;
896 hres = to_int32(ctx, val, &i);
897 if(SUCCEEDED(hres)) {
898 if(vt == VT_I4)
899 V_I4(dst) = i;
900 else
901 V_I2(dst) = i;
903 break;
905 case VT_UI2: {
906 UINT32 i;
908 hres = to_uint32(ctx, val, &i);
909 if(SUCCEEDED(hres))
910 V_UI2(dst) = i;
911 break;
913 case VT_R8: {
914 double n;
915 hres = to_number(ctx, val, &n);
916 if(SUCCEEDED(hres))
917 V_R8(dst) = n;
918 break;
920 case VT_R4: {
921 double n;
923 hres = to_number(ctx, val, &n);
924 if(SUCCEEDED(hres))
925 V_R4(dst) = n;
926 break;
928 case VT_BOOL: {
929 BOOL b;
931 hres = to_boolean(val, &b);
932 if(SUCCEEDED(hres))
933 V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE;
934 break;
936 case VT_BSTR: {
937 jsstr_t *str;
939 hres = to_string(ctx, val, &str);
940 if(FAILED(hres))
941 break;
943 hres = jsstr_to_bstr(str, &V_BSTR(dst));
944 break;
946 case VT_EMPTY:
947 hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
948 break;
949 case VT_NULL:
950 hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
951 break;
952 default:
953 FIXME("vt %d not implemented\n", vt);
954 hres = E_NOTIMPL;
957 jsval_release(val);
958 leave_script(ctx, hres);
959 if(FAILED(hres))
960 return hres;
962 V_VT(dst) = vt;
963 return S_OK;
966 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
968 return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
971 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
973 JSCaller *This = impl_from_IServiceProvider(iface);
975 if(IsEqualGUID(&IID_IUnknown, riid)) {
976 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
977 *ppv = &This->IServiceProvider_iface;
978 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
979 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
980 *ppv = &This->IServiceProvider_iface;
981 }else {
982 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
983 *ppv = NULL;
984 return E_NOINTERFACE;
987 IUnknown_AddRef((IUnknown*)*ppv);
988 return S_OK;
991 static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
993 JSCaller *This = impl_from_IServiceProvider(iface);
994 LONG ref = InterlockedIncrement(&This->ref);
996 TRACE("(%p) ref=%ld\n", This, ref);
998 return ref;
1001 static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
1003 JSCaller *This = impl_from_IServiceProvider(iface);
1004 LONG ref = InterlockedIncrement(&This->ref);
1006 TRACE("(%p) ref=%ld\n", This, ref);
1008 if(!ref) {
1009 assert(!This->ctx);
1010 heap_free(This);
1013 return ref;
1016 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
1017 REFIID riid, void **ppv)
1019 JSCaller *This = impl_from_IServiceProvider(iface);
1021 if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
1022 TRACE("(%p)->(SID_VariantConversion)\n", This);
1023 return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
1026 FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1028 *ppv = NULL;
1029 return E_NOINTERFACE;
1032 static const IServiceProviderVtbl ServiceProviderVtbl = {
1033 JSCaller_QueryInterface,
1034 JSCaller_AddRef,
1035 JSCaller_Release,
1036 JSCaller_QueryService
1039 HRESULT create_jscaller(script_ctx_t *ctx)
1041 JSCaller *ret;
1043 ret = heap_alloc(sizeof(*ret));
1044 if(!ret)
1045 return E_OUTOFMEMORY;
1047 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1048 ret->ref = 1;
1049 ret->ctx = ctx;
1051 ctx->jscaller = ret;
1052 return S_OK;