vbarray.c 9.23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*
 * Copyright 2010 Piotr 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
 */

#include "jscript.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(jscript);

typedef struct {
    jsdisp_t dispex;

    SAFEARRAY *safearray;
} VBArrayInstance;

static const WCHAR dimensionsW[] = {'d','i','m','e','n','s','i','o','n','s',0};
static const WCHAR getItemW[] = {'g','e','t','I','t','e','m',0};
static const WCHAR lboundW[] = {'l','b','o','u','n','d',0};
static const WCHAR toArrayW[] = {'t','o','A','r','r','a','y',0};
static const WCHAR uboundW[] = {'u','b','o','u','n','d',0};

37 38 39 40 41
static inline VBArrayInstance *vbarray_from_jsdisp(jsdisp_t *jsdisp)
{
    return CONTAINING_RECORD(jsdisp, VBArrayInstance, dispex);
}

42 43
static inline VBArrayInstance *vbarray_from_vdisp(vdisp_t *vdisp)
{
44
    return vbarray_from_jsdisp(vdisp->u.jsdisp);
45 46 47 48 49 50 51
}

static inline VBArrayInstance *vbarray_this(vdisp_t *jsthis)
{
    return is_vclass(jsthis, JSCLASS_VBARRAY) ? vbarray_from_vdisp(jsthis) : NULL;
}

52
static HRESULT VBArray_dimensions(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
53
        jsval_t *r)
54
{
55 56 57 58 59 60
    VBArrayInstance *vbarray;

    TRACE("\n");

    vbarray = vbarray_this(vthis);
    if(!vbarray)
61
        return JS_E_VBARRAY_EXPECTED;
62

63 64
    if(r)
        *r = jsval_number(SafeArrayGetDim(vbarray->safearray));
65
    return S_OK;
66 67
}

68
static HRESULT VBArray_getItem(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
69
        jsval_t *r)
70
{
71
    VBArrayInstance *vbarray;
72
    int i, *indexes;
73 74 75 76 77 78 79
    VARIANT out;
    HRESULT hres;

    TRACE("\n");

    vbarray = vbarray_this(vthis);
    if(!vbarray)
80
        return JS_E_VBARRAY_EXPECTED;
81

82
    if(argc < SafeArrayGetDim(vbarray->safearray))
83
        return JS_E_SUBSCRIPT_OUT_OF_RANGE;
84

85
    indexes = heap_alloc(sizeof(int)*argc);
86 87 88
    if(!indexes)
        return E_OUTOFMEMORY;

89
    for(i=0; i<argc; i++) {
90
        hres = to_int32(ctx, argv[i], indexes+i);
91 92 93 94 95 96 97 98 99
        if(FAILED(hres)) {
            heap_free(indexes);
            return hres;
        }
    }

    hres = SafeArrayGetElement(vbarray->safearray, indexes, (void*)&out);
    heap_free(indexes);
    if(hres == DISP_E_BADINDEX)
100
        return JS_E_SUBSCRIPT_OUT_OF_RANGE;
101 102 103
    else if(FAILED(hres))
        return hres;

104 105 106 107
    if(r) {
        hres = variant_to_jsval(&out, r);
        VariantClear(&out);
    }
108
    return hres;
109 110
}

111
static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
112
        jsval_t *r)
113
{
114 115 116 117 118 119 120 121
    VBArrayInstance *vbarray;
    int dim;
    HRESULT hres;

    TRACE("\n");

    vbarray = vbarray_this(vthis);
    if(!vbarray)
122
        return JS_E_VBARRAY_EXPECTED;
123

124
    if(argc) {
125
        hres = to_int32(ctx, argv[0], &dim);
126 127 128 129 130 131 132
        if(FAILED(hres))
            return hres;
    } else
        dim = 1;

    hres = SafeArrayGetLBound(vbarray->safearray, dim, &dim);
    if(hres == DISP_E_BADINDEX)
133
        return JS_E_SUBSCRIPT_OUT_OF_RANGE;
134 135 136
    else if(FAILED(hres))
        return hres;

137 138
    if(r)
        *r = jsval_number(dim);
139
    return S_OK;
140 141
}

142
static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
143
        jsval_t *r)
144
{
145 146
    VBArrayInstance *vbarray;
    jsdisp_t *array;
147
    jsval_t val;
148 149 150 151 152 153 154 155
    VARIANT *v;
    int i, size = 1, ubound, lbound;
    HRESULT hres;

    TRACE("\n");

    vbarray = vbarray_this(vthis);
    if(!vbarray)
156
        return JS_E_VBARRAY_EXPECTED;
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

    for(i=1; i<=SafeArrayGetDim(vbarray->safearray); i++) {
        SafeArrayGetLBound(vbarray->safearray, i, &lbound);
        SafeArrayGetUBound(vbarray->safearray, i, &ubound);
        size *= ubound-lbound+1;
    }

    hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
    if(FAILED(hres))
        return hres;

    hres = create_array(ctx, 0, &array);
    if(FAILED(hres)) {
        SafeArrayUnaccessData(vbarray->safearray);
        return hres;
    }

    for(i=0; i<size; i++) {
175 176
        hres = variant_to_jsval(v, &val);
        if(SUCCEEDED(hres)) {
177
            hres = jsdisp_propput_idx(array, i, val);
178 179
            jsval_release(val);
        }
180 181 182 183 184 185 186 187 188 189
        if(FAILED(hres)) {
            SafeArrayUnaccessData(vbarray->safearray);
            jsdisp_release(array);
            return hres;
        }
        v++;
    }

    SafeArrayUnaccessData(vbarray->safearray);

190 191
    if(r)
        *r = jsval_obj(array);
192 193
    else
        jsdisp_release(array);
194
    return S_OK;
195 196
}

197
static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
198
        jsval_t *r)
199
{
200 201 202 203 204 205 206 207
    VBArrayInstance *vbarray;
    int dim;
    HRESULT hres;

    TRACE("\n");

    vbarray = vbarray_this(vthis);
    if(!vbarray)
208
        return JS_E_VBARRAY_EXPECTED;
209

210
    if(argc) {
211
        hres = to_int32(ctx, argv[0], &dim);
212 213 214 215 216 217 218
        if(FAILED(hres))
            return hres;
    } else
        dim = 1;

    hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim);
    if(hres == DISP_E_BADINDEX)
219
        return JS_E_SUBSCRIPT_OUT_OF_RANGE;
220 221 222
    else if(FAILED(hres))
        return hres;

223 224
    if(r)
        *r = jsval_number(dim);
225
    return S_OK;
226 227
}

228
static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
229
        jsval_t *r)
230 231 232 233 234 235 236 237 238 239 240 241 242 243
{
    FIXME("\n");

    switch(flags) {
        default:
            FIXME("unimplemented flags %x\n", flags);
            return E_NOTIMPL;
    }

    return S_OK;
}

static void VBArray_destructor(jsdisp_t *dispex)
{
244
    VBArrayInstance *vbarray = vbarray_from_jsdisp(dispex);
245 246 247

    SafeArrayDestroy(vbarray->safearray);
    heap_free(vbarray);
248 249 250 251 252 253 254 255 256 257 258 259 260
}

static const builtin_prop_t VBArray_props[] = {
    {dimensionsW,           VBArray_dimensions,         PROPF_METHOD},
    {getItemW,              VBArray_getItem,            PROPF_METHOD|1},
    {lboundW,               VBArray_lbound,             PROPF_METHOD},
    {toArrayW,              VBArray_toArray,            PROPF_METHOD},
    {uboundW,               VBArray_ubound,             PROPF_METHOD}
};

static const builtin_info_t VBArray_info = {
    JSCLASS_VBARRAY,
    {NULL, VBArray_value, 0},
261
    ARRAY_SIZE(VBArray_props),
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    VBArray_props,
    VBArray_destructor,
    NULL
};

static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
{
    VBArrayInstance *vbarray;
    HRESULT hres;

    vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
    if(!vbarray)
        return E_OUTOFMEMORY;

    if(object_prototype)
        hres = init_dispex(&vbarray->dispex, ctx, &VBArray_info, object_prototype);
    else
        hres = init_dispex_from_constr(&vbarray->dispex, ctx, &VBArray_info, ctx->vbarray_constr);

    if(FAILED(hres)) {
        heap_free(vbarray);
        return hres;
    }

    *ret = vbarray;
    return S_OK;
}

290
static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
291
        jsval_t *r)
292
{
293 294 295 296
    VBArrayInstance *vbarray;
    HRESULT hres;

    TRACE("\n");
297 298

    switch(flags) {
299
    case DISPATCH_METHOD:
300
        if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
301
            return JS_E_VBARRAY_EXPECTED;
302

303
        return jsval_copy(argv[0], r);
304 305

    case DISPATCH_CONSTRUCT:
306
        if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
307
            return JS_E_VBARRAY_EXPECTED;
308 309 310 311

        hres = alloc_vbarray(ctx, NULL, &vbarray);
        if(FAILED(hres))
            return hres;
312

313
        hres = SafeArrayCopy(V_ARRAY(get_variant(argv[0])), &vbarray->safearray);
314 315 316 317
        if(FAILED(hres)) {
            jsdisp_release(&vbarray->dispex);
            return hres;
        }
318

319
        *r = jsval_obj(&vbarray->dispex);
320 321
        break;

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    default:
        FIXME("unimplemented flags: %x\n", flags);
        return E_NOTIMPL;
    }

    return S_OK;
}

HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
{
    VBArrayInstance *vbarray;
    HRESULT hres;

    static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};

    hres = alloc_vbarray(ctx, object_prototype, &vbarray);
    if(FAILED(hres))
        return hres;

341
    hres = create_builtin_constructor(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
342 343 344 345

    jsdisp_release(&vbarray->dispex);
    return hres;
}
346 347 348 349 350 351 352 353 354 355

HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
{
    VBArrayInstance *vbarray;
    HRESULT hres;

    hres = alloc_vbarray(ctx, NULL, &vbarray);
    if(FAILED(hres))
        return hres;

356 357 358 359 360
    hres = SafeArrayCopy(sa, &vbarray->safearray);
    if(FAILED(hres)) {
        jsdisp_release(&vbarray->dispex);
        return hres;
    }
361 362 363 364

    *ret = &vbarray->dispex;
    return S_OK;
}