jscript: Store Boolean object's value as BOOL instead of VARIANT_BOOL.
[wine] / dlls / jscript / vbarray.c
1 /*
2  * Copyright 2010 Piotr Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "jscript.h"
20
21 #include "wine/debug.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
24
25 typedef struct {
26     jsdisp_t dispex;
27
28     SAFEARRAY *safearray;
29 } VBArrayInstance;
30
31 static const WCHAR dimensionsW[] = {'d','i','m','e','n','s','i','o','n','s',0};
32 static const WCHAR getItemW[] = {'g','e','t','I','t','e','m',0};
33 static const WCHAR lboundW[] = {'l','b','o','u','n','d',0};
34 static const WCHAR toArrayW[] = {'t','o','A','r','r','a','y',0};
35 static const WCHAR uboundW[] = {'u','b','o','u','n','d',0};
36
37 static inline VBArrayInstance *vbarray_from_vdisp(vdisp_t *vdisp)
38 {
39     return (VBArrayInstance*)vdisp->u.jsdisp;
40 }
41
42 static inline VBArrayInstance *vbarray_this(vdisp_t *jsthis)
43 {
44     return is_vclass(jsthis, JSCLASS_VBARRAY) ? vbarray_from_vdisp(jsthis) : NULL;
45 }
46
47 static HRESULT VBArray_dimensions(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
48         jsval_t *r, jsexcept_t *ei)
49 {
50     VBArrayInstance *vbarray;
51
52     TRACE("\n");
53
54     vbarray = vbarray_this(vthis);
55     if(!vbarray)
56         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
57
58     if(r)
59         *r = jsval_number(SafeArrayGetDim(vbarray->safearray));
60     return S_OK;
61 }
62
63 static HRESULT VBArray_getItem(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
64         jsval_t *r, jsexcept_t *ei)
65 {
66     VBArrayInstance *vbarray;
67     int i, *indexes;
68     VARIANT out;
69     HRESULT hres;
70
71     TRACE("\n");
72
73     vbarray = vbarray_this(vthis);
74     if(!vbarray)
75         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
76
77     if(argc < SafeArrayGetDim(vbarray->safearray))
78         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
79
80     indexes = heap_alloc(sizeof(int)*argc);
81     if(!indexes)
82         return E_OUTOFMEMORY;
83
84     for(i=0; i<argc; i++) {
85         hres = to_int32(ctx, argv[i], ei, indexes+i);
86         if(FAILED(hres)) {
87             heap_free(indexes);
88             return hres;
89         }
90     }
91
92     hres = SafeArrayGetElement(vbarray->safearray, indexes, (void*)&out);
93     heap_free(indexes);
94     if(hres == DISP_E_BADINDEX)
95         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
96     else if(FAILED(hres))
97         return hres;
98
99     if(r) {
100         hres = variant_to_jsval(&out, r);
101         VariantClear(&out);
102     }
103     return hres;
104 }
105
106 static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
107         jsval_t *r, jsexcept_t *ei)
108 {
109     VBArrayInstance *vbarray;
110     int dim;
111     HRESULT hres;
112
113     TRACE("\n");
114
115     vbarray = vbarray_this(vthis);
116     if(!vbarray)
117         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
118
119     if(argc) {
120         hres = to_int32(ctx, argv[0], ei, &dim);
121         if(FAILED(hres))
122             return hres;
123     } else
124         dim = 1;
125
126     hres = SafeArrayGetLBound(vbarray->safearray, dim, &dim);
127     if(hres == DISP_E_BADINDEX)
128         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
129     else if(FAILED(hres))
130         return hres;
131
132     if(r)
133         *r = jsval_number(dim);
134     return S_OK;
135 }
136
137 static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
138         jsval_t *r, jsexcept_t *ei)
139 {
140     VBArrayInstance *vbarray;
141     jsdisp_t *array;
142     jsval_t val;
143     VARIANT *v;
144     int i, size = 1, ubound, lbound;
145     HRESULT hres;
146
147     TRACE("\n");
148
149     vbarray = vbarray_this(vthis);
150     if(!vbarray)
151         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
152
153     for(i=1; i<=SafeArrayGetDim(vbarray->safearray); i++) {
154         SafeArrayGetLBound(vbarray->safearray, i, &lbound);
155         SafeArrayGetUBound(vbarray->safearray, i, &ubound);
156         size *= ubound-lbound+1;
157     }
158
159     hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
160     if(FAILED(hres))
161         return hres;
162
163     hres = create_array(ctx, 0, &array);
164     if(FAILED(hres)) {
165         SafeArrayUnaccessData(vbarray->safearray);
166         return hres;
167     }
168
169     for(i=0; i<size; i++) {
170         hres = variant_to_jsval(v, &val);
171         if(SUCCEEDED(hres)) {
172             hres = jsdisp_propput_idx(array, i, val, ei);
173             jsval_release(val);
174         }
175         if(FAILED(hres)) {
176             SafeArrayUnaccessData(vbarray->safearray);
177             jsdisp_release(array);
178             return hres;
179         }
180         v++;
181     }
182
183     SafeArrayUnaccessData(vbarray->safearray);
184
185     if(r)
186         *r = jsval_obj(array);
187     return S_OK;
188 }
189
190 static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
191         jsval_t *r, jsexcept_t *ei)
192 {
193     VBArrayInstance *vbarray;
194     int dim;
195     HRESULT hres;
196
197     TRACE("\n");
198
199     vbarray = vbarray_this(vthis);
200     if(!vbarray)
201         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
202
203     if(argc) {
204         hres = to_int32(ctx, argv[0], ei, &dim);
205         if(FAILED(hres))
206             return hres;
207     } else
208         dim = 1;
209
210     hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim);
211     if(hres == DISP_E_BADINDEX)
212         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
213     else if(FAILED(hres))
214         return hres;
215
216     if(r)
217         *r = jsval_number(dim);
218     return S_OK;
219 }
220
221 static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
222         jsval_t *r, jsexcept_t *ei)
223 {
224     FIXME("\n");
225
226     switch(flags) {
227         default:
228             FIXME("unimplemented flags %x\n", flags);
229             return E_NOTIMPL;
230     }
231
232     return S_OK;
233 }
234
235 static void VBArray_destructor(jsdisp_t *dispex)
236 {
237     VBArrayInstance *vbarray = (VBArrayInstance*)dispex;
238
239     SafeArrayDestroy(vbarray->safearray);
240     heap_free(vbarray);
241 }
242
243 static const builtin_prop_t VBArray_props[] = {
244     {dimensionsW,           VBArray_dimensions,         PROPF_METHOD},
245     {getItemW,              VBArray_getItem,            PROPF_METHOD|1},
246     {lboundW,               VBArray_lbound,             PROPF_METHOD},
247     {toArrayW,              VBArray_toArray,            PROPF_METHOD},
248     {uboundW,               VBArray_ubound,             PROPF_METHOD}
249 };
250
251 static const builtin_info_t VBArray_info = {
252     JSCLASS_VBARRAY,
253     {NULL, VBArray_value, 0},
254     sizeof(VBArray_props)/sizeof(*VBArray_props),
255     VBArray_props,
256     VBArray_destructor,
257     NULL
258 };
259
260 static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
261 {
262     VBArrayInstance *vbarray;
263     HRESULT hres;
264
265     vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
266     if(!vbarray)
267         return E_OUTOFMEMORY;
268
269     if(object_prototype)
270         hres = init_dispex(&vbarray->dispex, ctx, &VBArray_info, object_prototype);
271     else
272         hres = init_dispex_from_constr(&vbarray->dispex, ctx, &VBArray_info, ctx->vbarray_constr);
273
274     if(FAILED(hres)) {
275         heap_free(vbarray);
276         return hres;
277     }
278
279     *ret = vbarray;
280     return S_OK;
281 }
282
283 static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
284         jsval_t *r, jsexcept_t *ei)
285 {
286     VBArrayInstance *vbarray;
287     HRESULT hres;
288
289     TRACE("\n");
290
291     switch(flags) {
292     case DISPATCH_METHOD:
293         if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
294             return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
295
296         return jsval_copy(argv[0], r);
297
298     case DISPATCH_CONSTRUCT:
299         if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
300             return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
301
302         hres = alloc_vbarray(ctx, NULL, &vbarray);
303         if(FAILED(hres))
304             return hres;
305
306         hres = SafeArrayCopy(V_ARRAY(get_variant(argv[0])), &vbarray->safearray);
307         if(FAILED(hres)) {
308             jsdisp_release(&vbarray->dispex);
309             return hres;
310         }
311
312         *r = jsval_obj(&vbarray->dispex);
313         break;
314
315     default:
316         FIXME("unimplemented flags: %x\n", flags);
317         return E_NOTIMPL;
318     }
319
320     return S_OK;
321 }
322
323 HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
324 {
325     VBArrayInstance *vbarray;
326     HRESULT hres;
327
328     static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
329
330     hres = alloc_vbarray(ctx, object_prototype, &vbarray);
331     if(FAILED(hres))
332         return hres;
333
334     hres = create_builtin_constructor(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
335
336     jsdisp_release(&vbarray->dispex);
337     return hres;
338 }
339
340 HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
341 {
342     VBArrayInstance *vbarray;
343     HRESULT hres;
344
345     hres = alloc_vbarray(ctx, NULL, &vbarray);
346     if(FAILED(hres))
347         return hres;
348
349     hres = SafeArrayCopy(sa, &vbarray->safearray);
350     if(FAILED(hres)) {
351         jsdisp_release(&vbarray->dispex);
352         return hres;
353     }
354
355     *ret = &vbarray->dispex;
356     return S_OK;
357 }