jsutils.c 25.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright 2008 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

19

20
#include <math.h>
21
#include <assert.h>
22

23
#include "jscript.h"
24
#include "engine.h"
25 26 27 28

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(jscript);
29
WINE_DECLARE_DEBUG_CHANNEL(heap);
30

31 32
const char *debugstr_jsval(const jsval_t v)
{
33
    switch(jsval_type(v)) {
34 35 36 37 38 39 40
    case JSV_UNDEFINED:
        return "undefined";
    case JSV_NULL:
        return "null";
    case JSV_OBJECT:
        return wine_dbg_sprintf("obj(%p)", get_object(v));
    case JSV_STRING:
41
        return wine_dbg_sprintf("str(%s)", debugstr_jsstr(get_string(v)));
42 43 44 45 46 47 48 49 50 51 52 53
    case JSV_NUMBER:
        return wine_dbg_sprintf("%lf", get_number(v));
    case JSV_BOOL:
        return get_bool(v) ? "true" : "false";
    case JSV_VARIANT:
        return debugstr_variant(get_variant(v));
    }

    assert(0);
    return NULL;
}

54
#define MIN_BLOCK_SIZE  128
55
#define ARENA_FREE_FILLER  0xaa
56 57 58 59 60 61

static inline DWORD block_size(DWORD block)
{
    return MIN_BLOCK_SIZE << block;
}

62
void heap_pool_init(heap_pool_t *heap)
63 64 65 66 67
{
    memset(heap, 0, sizeof(*heap));
    list_init(&heap->custom_blocks);
}

68
void *heap_pool_alloc(heap_pool_t *heap, DWORD size)
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
{
    struct list *list;
    void *tmp;

    if(!heap->block_cnt) {
        if(!heap->blocks) {
            heap->blocks = heap_alloc(sizeof(void*));
            if(!heap->blocks)
                return NULL;
        }

        tmp = heap_alloc(block_size(0));
        if(!tmp)
            return NULL;

        heap->blocks[0] = tmp;
        heap->block_cnt = 1;
    }

88
    if(heap->offset + size <= block_size(heap->last_block)) {
89 90 91 92 93
        tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
        heap->offset += size;
        return tmp;
    }

94
    if(size <= block_size(heap->last_block+1)) {
95 96 97 98 99
        if(heap->last_block+1 == heap->block_cnt) {
            tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
            if(!tmp)
                return NULL;

100 101 102 103
            heap->blocks = tmp;
            heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
            if(!heap->blocks[heap->block_cnt])
                return NULL;
104

105 106
            heap->block_cnt++;
        }
107 108 109 110 111 112 113 114 115 116 117 118 119 120

        heap->last_block++;
        heap->offset = size;
        return heap->blocks[heap->last_block];
    }

    list = heap_alloc(size + sizeof(struct list));
    if(!list)
        return NULL;

    list_add_head(&heap->custom_blocks, list);
    return list+1;
}

121
void *heap_pool_grow(heap_pool_t *heap, void *mem, DWORD size, DWORD inc)
122
{
123 124
    void *ret;

125 126 127 128 129 130
    if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
       && heap->offset+inc < block_size(heap->last_block)) {
        heap->offset += inc;
        return mem;
    }

131
    ret = heap_pool_alloc(heap, size+inc);
132
    if(ret) /* FIXME: avoid copying for custom blocks */
133 134
        memcpy(ret, mem, size);
    return ret;
135 136
}

137
void heap_pool_clear(heap_pool_t *heap)
138 139 140
{
    struct list *tmp;

141 142 143
    if(!heap)
        return;

144
    while((tmp = list_head(&heap->custom_blocks))) {
145 146 147
        list_remove(tmp);
        heap_free(tmp);
    }
148

149 150 151 152 153 154 155
    if(WARN_ON(heap)) {
        DWORD i;

        for(i=0; i < heap->block_cnt; i++)
            memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
    }

156
    heap->last_block = heap->offset = 0;
157
    heap->mark = FALSE;
158 159
}

160
void heap_pool_free(heap_pool_t *heap)
161 162 163
{
    DWORD i;

164
    heap_pool_clear(heap);
165 166 167 168 169

    for(i=0; i < heap->block_cnt; i++)
        heap_free(heap->blocks[i]);
    heap_free(heap->blocks);

170
    heap_pool_init(heap);
171
}
172

173
heap_pool_t *heap_pool_mark(heap_pool_t *heap)
174 175 176 177 178 179 180 181
{
    if(heap->mark)
        return NULL;

    heap->mark = TRUE;
    return heap;
}

182 183
void jsval_release(jsval_t val)
{
184
    switch(jsval_type(val)) {
185
    case JSV_OBJECT:
186 187
        if(get_object(val))
            IDispatch_Release(get_object(val));
188 189
        break;
    case JSV_STRING:
190
        jsstr_release(get_string(val));
191 192
        break;
    case JSV_VARIANT:
193 194
        VariantClear(get_variant(val));
        heap_free(get_variant(val));
195 196 197 198 199 200
        break;
    default:
        break;
    }
}

201
static HRESULT jsval_variant(jsval_t *val, VARIANT *var)
202
{
203
    VARIANT *v;
204 205
    HRESULT hres;

206 207
    __JSVAL_TYPE(*val) = JSV_VARIANT;
    __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT));
208 209
    if(!v) {
        *val = jsval_undefined();
210
        return E_OUTOFMEMORY;
211
    }
212

213 214
    V_VT(v) = VT_EMPTY;
    hres = VariantCopy(v, var);
215 216
    if(FAILED(hres)) {
        *val = jsval_undefined();
217
        heap_free(v);
218
    }
219 220 221
    return hres;
}

222 223
HRESULT jsval_copy(jsval_t v, jsval_t *r)
{
224
    switch(jsval_type(v)) {
225 226 227 228 229 230 231
    case JSV_UNDEFINED:
    case JSV_NULL:
    case JSV_NUMBER:
    case JSV_BOOL:
        *r = v;
        return S_OK;
    case JSV_OBJECT:
232 233
        if(get_object(v))
            IDispatch_AddRef(get_object(v));
234 235 236
        *r = v;
        return S_OK;
    case JSV_STRING: {
237 238
        jsstr_addref(get_string(v));
        *r = v;
239 240 241 242 243 244 245 246 247 248
        return S_OK;
    }
    case JSV_VARIANT:
        return jsval_variant(r, get_variant(v));
    }

    assert(0);
    return E_FAIL;
}

249 250
HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
{
251 252 253
    if(V_VT(var) == (VT_VARIANT|VT_BYREF))
        var = V_VARIANTREF(var);

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    switch(V_VT(var)) {
    case VT_EMPTY:
        *r = jsval_undefined();
        return S_OK;
    case VT_NULL:
        *r = jsval_null();
        return S_OK;
    case VT_BOOL:
        *r = jsval_bool(V_BOOL(var));
        return S_OK;
    case VT_I4:
        *r = jsval_number(V_I4(var));
        return S_OK;
    case VT_R8:
        *r = jsval_number(V_R8(var));
        return S_OK;
    case VT_BSTR: {
271 272
        jsstr_t *str;

273 274 275 276 277 278 279
        if(V_BSTR(var)) {
            str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var)));
            if(!str)
                return E_OUTOFMEMORY;
        }else {
            str = jsstr_null_bstr();
        }
280

281 282 283 284
        *r = jsval_string(str);
        return S_OK;
    }
    case VT_DISPATCH: {
285 286
        if(V_DISPATCH(var))
            IDispatch_AddRef(V_DISPATCH(var));
287 288 289
        *r = jsval_disp(V_DISPATCH(var));
        return S_OK;
    }
290 291 292 293 294 295
    case VT_I1:
        *r = jsval_number(V_I1(var));
        return S_OK;
    case VT_UI1:
        *r = jsval_number(V_UI1(var));
        return S_OK;
296
    case VT_I2:
297 298
        *r = jsval_number(V_I2(var));
        return S_OK;
299 300 301
    case VT_UI2:
        *r = jsval_number(V_UI2(var));
        return S_OK;
302
    case VT_INT:
303 304
        *r = jsval_number(V_INT(var));
        return S_OK;
305 306 307
    case VT_UI4:
        *r = jsval_number(V_UI4(var));
        return S_OK;
308 309 310 311 312 313 314
    case VT_UI8:
        /*
         * Native doesn't support VT_UI8 here, but it's needed for IE9+ APIs
         * (native IE9 doesn't use jscript.dll for JavaScript).
         */
        *r = jsval_number(V_UI8(var));
        return S_OK;
315 316 317
    case VT_R4:
        *r = jsval_number(V_R4(var));
        return S_OK;
318 319 320 321 322 323
    case VT_CY:
        /* FIXME: Native converts VT_CY to a special kind number type, which is
         * never converted to VT_I4 when it's converted back to VARIANT. */
        *r = jsval_number((double)V_CY(var).int64 / 10000.0);
        WARN("VT_CY: %lf\n", get_number(*r));
        return S_OK;
324 325 326 327 328 329 330 331 332 333
    case VT_UNKNOWN:
        if(V_UNKNOWN(var)) {
            IDispatch *disp;
            HRESULT hres;

            hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp);
            if(SUCCEEDED(hres)) {
                *r = jsval_disp(disp);
                return S_OK;
            }
334 335 336
        }else {
            *r = jsval_disp(NULL);
            return S_OK;
337 338
        }
        /* fall through */
339 340 341 342 343 344 345
    default:
        return jsval_variant(r, var);
    }
}

HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
{
346
    switch(jsval_type(val)) {
347 348 349 350 351 352 353 354
    case JSV_UNDEFINED:
        V_VT(retv) = VT_EMPTY;
        return S_OK;
    case JSV_NULL:
        V_VT(retv) = VT_NULL;
        return S_OK;
    case JSV_OBJECT:
        V_VT(retv) = VT_DISPATCH;
355 356 357
        if(get_object(val))
            IDispatch_AddRef(get_object(val));
        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 363 364 365 366 367 368 369 370 371 372
    case JSV_NUMBER: {
        double n = get_number(val);

        if(is_int32(n)) {
            V_VT(retv) = VT_I4;
            V_I4(retv) = n;
        }else {
            V_VT(retv) = VT_R8;
            V_R8(retv) = n;
        }

373
        return S_OK;
374
    }
375 376
    case JSV_BOOL:
        V_VT(retv) = VT_BOOL;
377
        V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE;
378 379
        return S_OK;
    case JSV_VARIANT:
380
        V_VT(retv) = VT_EMPTY;
381
        return VariantCopy(retv, get_variant(val));
382 383 384 385 386 387
    }

    assert(0);
    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)
390
{
391
    if(is_object_instance(val)) {
392
        jsdisp_t *jsdisp;
393
        jsval_t prim;
394 395 396
        DISPID id;
        HRESULT hres;

397 398 399
        if(!get_object(val)) {
            *ret = jsval_null();
            return S_OK;
400 401
        }

402
        jsdisp = iface_to_jsdisp(get_object(val));
403
        if(!jsdisp)
404
            return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
405 406 407 408 409 410

        if(hint == NO_HINT)
            hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;

        /* 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 417
                jsdisp_release(jsdisp);
                return hres;
418
            }else if(!is_object_instance(prim)) {
419
                jsdisp_release(jsdisp);
420
                *ret = prim;
421
                return S_OK;
422 423
            }else {
                IDispatch_Release(get_object(prim));
424 425 426
            }
        }

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 433
                jsdisp_release(jsdisp);
                return hres;
434
            }else if(!is_object_instance(prim)) {
435
                jsdisp_release(jsdisp);
436
                *ret = prim;
437
                return S_OK;
438 439
            }else {
                IDispatch_Release(get_object(prim));
440 441 442 443 444
            }
        }

        jsdisp_release(jsdisp);

445
        WARN("failed\n");
446
        return JS_E_TO_PRIMITIVE;
447
    }
448 449 450 451 452

    return jsval_copy(val, ret);

}

453
/* ECMA-262 3rd Edition    9.2 */
454
HRESULT to_boolean(jsval_t val, BOOL *ret)
455
{
456
    switch(jsval_type(val)) {
457 458
    case JSV_UNDEFINED:
    case JSV_NULL:
459
        *ret = FALSE;
460 461 462 463 464
        return S_OK;
    case JSV_OBJECT:
        *ret = get_object(val) != NULL;
        return S_OK;
    case JSV_STRING:
465
        *ret = jsstr_length(get_string(val)) != 0;
466
        return S_OK;
467 468 469 470 471 472 473 474 475
    case JSV_NUMBER:
        *ret = !isnan(get_number(val)) && get_number(val);
        return S_OK;
    case JSV_BOOL:
        *ret = get_bool(val);
        return S_OK;
    case JSV_VARIANT:
        FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val)));
        return E_NOTIMPL;
476 477
    }

478 479
    assert(0);
    return E_FAIL;
480 481
}

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
static int hex_to_int(WCHAR c)
{
    if('0' <= c && c <= '9')
        return c-'0';

    if('a' <= c && c <= 'f')
        return c-'a'+10;

    if('A' <= c && c <= 'F')
        return c-'A'+10;

    return -1;
}

/* ECMA-262 3rd Edition    9.3.1 */
497
static HRESULT str_to_number(jsstr_t *str, double *ret)
498
{
499
    const WCHAR *ptr;
500 501 502
    BOOL neg = FALSE;
    DOUBLE d = 0.0;

503
    static const WCHAR infinityW[] = L"Infinity";
504

505 506 507
    ptr = jsstr_flatten(str);
    if(!ptr)
        return E_OUTOFMEMORY;
508

509
    while(iswspace(*ptr))
510 511
        ptr++;

512 513 514 515 516 517 518
    if(*ptr == '-') {
        neg = TRUE;
        ptr++;
    }else if(*ptr == '+') {
        ptr++;
    }

519 520
    if(!wcsncmp(ptr, infinityW, ARRAY_SIZE(infinityW)-1)) {
        ptr += ARRAY_SIZE(infinityW) - 1;
521
        while(*ptr && iswspace(*ptr))
522 523
            ptr++;

524
        if(*ptr)
525
            *ret = NAN;
526
        else
527
            *ret = neg ? -INFINITY : INFINITY;
528
        return S_OK;
529 530
    }

531
    if(*ptr == '0' && ptr[1] == 'x') {
532 533 534 535 536 537 538 539
        DWORD l = 0;

        ptr += 2;
        while((l = hex_to_int(*ptr)) != -1) {
            d = d*16 + l;
            ptr++;
        }

540
        *ret = d;
541 542 543
        return S_OK;
    }

544
    while(is_digit(*ptr))
545 546 547 548 549 550 551 552 553 554 555 556 557 558
        d = d*10 + (*ptr++ - '0');

    if(*ptr == 'e' || *ptr == 'E') {
        BOOL eneg = FALSE;
        LONG l = 0;

        ptr++;
        if(*ptr == '-') {
            ptr++;
            eneg = TRUE;
        }else if(*ptr == '+') {
            ptr++;
        }

559
        while(is_digit(*ptr))
560 561 562 563 564 565 566 567 568
            l = l*10 + (*ptr++ - '0');
        if(eneg)
            l = -l;

        d *= pow(10, l);
    }else if(*ptr == '.') {
        DOUBLE dec = 0.1;

        ptr++;
569
        while(is_digit(*ptr)) {
570 571 572 573 574
            d += dec * (*ptr++ - '0');
            dec *= 0.1;
        }
    }

575
    while(iswspace(*ptr))
576 577 578
        ptr++;

    if(*ptr) {
579
        *ret = NAN;
580
        return S_OK;
581 582 583 584 585
    }

    if(neg)
        d = -d;

586
    *ret = d;
587 588 589
    return S_OK;
}

590
/* ECMA-262 3rd Edition    9.3 */
591
HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret)
592
{
593
    switch(jsval_type(val)) {
594
    case JSV_UNDEFINED:
595
        *ret = NAN;
596 597
        return S_OK;
    case JSV_NULL:
598
        *ret = 0;
599 600 601 602 603 604 605
        return S_OK;
    case JSV_NUMBER:
        *ret = get_number(val);
        return S_OK;
    case JSV_STRING:
        return str_to_number(get_string(val), ret);
    case JSV_OBJECT: {
606
        jsval_t prim;
607 608
        HRESULT hres;

609
        hres = to_primitive(ctx, val, &prim, HINT_NUMBER);
610 611 612
        if(FAILED(hres))
            return hres;

613
        hres = to_number(ctx, prim, ret);
614
        jsval_release(prim);
615 616
        return hres;
    }
617 618
    case JSV_BOOL:
        *ret = get_bool(val) ? 1 : 0;
619
        return S_OK;
620 621 622 623 624 625 626 627 628 629
    case JSV_VARIANT: {
        const VARIANT *v = get_variant(val);
        switch(V_VT(v)) {
        case VT_DATE:
            return variant_date_to_number(V_DATE(v), ret);
        default:
            FIXME("unimplemented for variant %s\n", debugstr_variant(v));
            return E_NOTIMPL;
        }
    }
630
    };
631

632 633
    assert(0);
    return E_FAIL;
634 635
}

636
/* ECMA-262 3rd Edition    9.4 */
637
HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret)
638
{
639
    double n;
640 641
    HRESULT hres;

642
    hres = to_number(ctx, v, &n);
643 644 645
    if(FAILED(hres))
        return hres;

646 647 648 649
    if(isnan(n))
        *ret = 0;
    else
        *ret = n >= 0.0 ? floor(n) : -floor(-n);
650 651 652
    return S_OK;
}

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
static INT32 double_to_int32(double number)
{
    INT32 exp, result;
    union {
        double d;
        INT64 n;
    } bits;

    bits.d = number;
    exp = ((INT32)(bits.n >> 52) & 0x7ff) - 0x3ff;

    /* If exponent < 0 there will be no bits to the left of the decimal point
     * after rounding; if the exponent is > 83 then no bits of precision can be
     * left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
     * of fractional precision).
668
     * Note this case handles 0, -0, and all infinite, NaN & denormal values. */
669 670 671 672 673
    if(exp < 0 || exp > 83)
        return 0;

    /* Select the appropriate 32-bits from the floating point mantissa.  If the
     * 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 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
     * to shift.  If the exponent is greater than 52 we need to shift the value
     * left by (exp - 52), if the value is less than 52 we need to shift right
     * accordingly. */
    result = (exp > 52) ? bits.n << (exp - 52) : bits.n >> (52 - exp);

    /* IEEE-754 double precision values are stored omitting an implicit 1 before
     * the decimal point; we need to reinsert this now.  We may also the shifted
     * invalid bits into the result that are not a part of the mantissa (the sign
     * and exponent bits from the floatingpoint representation); mask these out. */
    if(exp < 32) {
        INT32 missing_one = 1 << exp;
        result &= missing_one - 1;
        result += missing_one;
    }

    /* If the input value was negative (we could test either 'number' or 'bits',
     * but testing 'bits' is likely faster) invert the result appropriately. */
    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)
697 698 699 700
{
    double n;
    HRESULT hres;

701
    hres = to_number(ctx, v, &n);
702 703 704
    if(FAILED(hres))
        return hres;

705
    *ret = double_to_int32(n);
706 707 708
    return S_OK;
}

709 710 711 712 713
HRESULT to_long(script_ctx_t *ctx, jsval_t v, LONG *ret)
{
    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)
716
{
717
    double n;
718 719
    HRESULT hres;

720 721 722 723 724 725
    hres = to_number(ctx, val, &n);
    if(FAILED(hres))
        return hres;

    *ret = double_to_int32(n);
    return S_OK;
726 727
}

728
HRESULT double_to_string(double n, jsstr_t **str)
729 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 736 737
        WCHAR buf[12];
        _ltow_s(n, buf, ARRAY_SIZE(buf), 10);
        *str = jsstr_alloc(buf);
738 739 740 741
    }else {
        VARIANT strv, v;
        HRESULT hres;

742
        /* FIXME: Don't use VariantChangeTypeEx */
743 744 745 746 747 748 749
        V_VT(&v) = VT_R8;
        V_R8(&v) = n;
        V_VT(&strv) = VT_EMPTY;
        hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
        if(FAILED(hres))
            return hres;

750 751
        *str = jsstr_alloc(V_BSTR(&strv));
        SysFreeString(V_BSTR(&strv));
752 753 754 755 756
    }

    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)
759
{
760
    switch(jsval_type(val)) {
761
    case JSV_UNDEFINED:
762 763
        *str = jsstr_undefined();
        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;
775

776
        hres = to_primitive(ctx, val, &prim, HINT_STRING);
777 778 779
        if(FAILED(hres))
            return hres;

780
        hres = to_string(ctx, prim, str);
781
        jsval_release(prim);
782 783
        return hres;
    }
784
    case JSV_BOOL:
785
        *str = jsstr_alloc(get_bool(val) ? L"true" : L"false");
786
        break;
787 788 789 790 791 792 793 794 795 796 797
    default: {
        const VARIANT *v = get_variant(val);
        switch(V_VT(v))
        {
        case VT_DATE:
            return variant_date_to_string(ctx, V_DATE(v), str);
        default:
            FIXME("unsupported %s\n", debugstr_variant(v));
            return E_NOTIMPL;
        }
    }
798 799
    }

800
    return *str ? S_OK : E_OUTOFMEMORY;
801 802
}

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str)
{
    HRESULT hres;

    hres = to_string(ctx, val, str);
    if(FAILED(hres))
        return hres;

    *ret_str = jsstr_flatten(*str);
    if(!*ret_str) {
        jsstr_release(*str);
        return E_OUTOFMEMORY;
    }

    return S_OK;
}

820
/* ECMA-262 3rd Edition    9.9 */
821
HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
822
{
823
    jsdisp_t *dispex;
824 825
    HRESULT hres;

826
    switch(jsval_type(val)) {
827
    case JSV_STRING:
828
        hres = create_string(ctx, get_string(val), &dispex);
829 830 831
        if(FAILED(hres))
            return hres;

832
        *disp = to_disp(dispex);
833
        break;
834 835
    case JSV_NUMBER:
        hres = create_number(ctx, get_number(val), &dispex);
836 837 838
        if(FAILED(hres))
            return hres;

839
        *disp = to_disp(dispex);
840
        break;
841 842 843 844
    case JSV_OBJECT:
        if(get_object(val)) {
            *disp = get_object(val);
            IDispatch_AddRef(*disp);
845
        }else {
846
            jsdisp_t *obj;
847 848 849 850 851

            hres = create_object(ctx, NULL, &obj);
            if(FAILED(hres))
                return hres;

852
            *disp = to_disp(obj);
853
        }
854
        break;
855 856
    case JSV_BOOL:
        hres = create_bool(ctx, get_bool(val), &dispex);
857 858 859
        if(FAILED(hres))
            return hres;

860 861
        *disp = to_disp(dispex);
        break;
862 863 864
    case JSV_UNDEFINED:
    case JSV_NULL:
        WARN("object expected\n");
865
        return JS_E_OBJECT_EXPECTED;
866 867 868 869 870 871
    case JSV_VARIANT:
        switch(V_VT(get_variant(val))) {
        case VT_ARRAY|VT_VARIANT:
            hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex);
            if(FAILED(hres))
                return hres;
872

873 874 875 876 877 878 879
            *disp = to_disp(dispex);
            break;

        default:
            FIXME("Unsupported %s\n", debugstr_variant(get_variant(val)));
            return E_NOTIMPL;
        }
880
        break;
881 882 883 884
    }

    return S_OK;
}
885

886 887
HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
{
888
    jsexcept_t ei;
889
    jsval_t val;
890 891
    HRESULT hres;

892 893 894 895
    hres = variant_to_jsval(src, &val);
    if(FAILED(hres))
        return hres;

896 897
    enter_script(ctx, &ei);

898 899 900 901 902
    switch(vt) {
    case VT_I2:
    case VT_I4: {
        INT i;

903
        hres = to_int32(ctx, val, &i);
904 905 906 907 908 909 910 911
        if(SUCCEEDED(hres)) {
            if(vt == VT_I4)
                V_I4(dst) = i;
            else
                V_I2(dst) = i;
        }
        break;
    }
912 913 914 915 916 917 918 919
    case VT_UI2: {
        UINT32 i;

        hres = to_uint32(ctx, val, &i);
        if(SUCCEEDED(hres))
            V_UI2(dst) = i;
        break;
    }
920 921
    case VT_R8: {
        double n;
922
        hres = to_number(ctx, val, &n);
923 924
        if(SUCCEEDED(hres))
            V_R8(dst) = n;
925
        break;
926
    }
927
    case VT_R4: {
928
        double n;
929

930
        hres = to_number(ctx, val, &n);
931
        if(SUCCEEDED(hres))
932
            V_R4(dst) = n;
933 934 935
        break;
    }
    case VT_BOOL: {
936 937 938
        BOOL b;

        hres = to_boolean(val, &b);
939
        if(SUCCEEDED(hres))
940
            V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE;
941 942 943
        break;
    }
    case VT_BSTR: {
944
        jsstr_t *str;
945

946
        hres = to_string(ctx, val, &str);
947 948 949
        if(FAILED(hres))
            break;

950
        hres = jsstr_to_bstr(str, &V_BSTR(dst));
951 952 953 954 955 956 957 958 959 960 961 962 963
        break;
    }
    case VT_EMPTY:
        hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
        break;
    case VT_NULL:
        hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
        break;
    default:
        FIXME("vt %d not implemented\n", vt);
        hres = E_NOTIMPL;
    }

964
    jsval_release(val);
965
    leave_script(ctx, hres);
966
    if(FAILED(hres))
967 968 969 970 971 972
        return hres;

    V_VT(dst) = vt;
    return S_OK;
}

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
{
    return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
}

static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
{
    JSCaller *This = impl_from_IServiceProvider(iface);

    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
        *ppv = &This->IServiceProvider_iface;
    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
        TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
        *ppv = &This->IServiceProvider_iface;
    }else {
        WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    IUnknown_AddRef((IUnknown*)*ppv);
    return S_OK;
}

static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
{
    JSCaller *This = impl_from_IServiceProvider(iface);
    LONG ref = InterlockedIncrement(&This->ref);

1003
    TRACE("(%p) ref=%ld\n", This, ref);
1004 1005 1006 1007 1008 1009 1010 1011 1012

    return ref;
}

static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
{
    JSCaller *This = impl_from_IServiceProvider(iface);
    LONG ref = InterlockedIncrement(&This->ref);

1013
    TRACE("(%p) ref=%ld\n", This, ref);
1014

1015 1016
    if(!ref) {
        assert(!This->ctx);
1017
        heap_free(This);
1018
    }
1019 1020 1021 1022 1023 1024 1025 1026 1027

    return ref;
}

static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
        REFIID riid, void **ppv)
{
    JSCaller *This = impl_from_IServiceProvider(iface);

1028 1029 1030 1031 1032
    if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
        TRACE("(%p)->(SID_VariantConversion)\n", This);
        return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
    }

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
    FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);

    *ppv = NULL;
    return E_NOINTERFACE;
}

static const IServiceProviderVtbl ServiceProviderVtbl = {
    JSCaller_QueryInterface,
    JSCaller_AddRef,
    JSCaller_Release,
    JSCaller_QueryService
};

HRESULT create_jscaller(script_ctx_t *ctx)
{
    JSCaller *ret;

    ret = heap_alloc(sizeof(*ret));
    if(!ret)
        return E_OUTOFMEMORY;

    ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
    ret->ref = 1;
1056
    ret->ctx = ctx;
1057 1058 1059 1060

    ctx->jscaller = ret;
    return S_OK;
}