jscript: Added more tests.
[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, VARIANT *argv,
48         VARIANT *retv, 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(retv)
59         num_set_int(retv, 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, VARIANT *argv,
64         VARIANT *retv, 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(retv)
100         hres = VariantCopy(retv, &out);
101
102     return hres;
103 }
104
105 static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, VARIANT *argv,
106         VARIANT *retv, jsexcept_t *ei)
107 {
108     VBArrayInstance *vbarray;
109     int dim;
110     HRESULT hres;
111
112     TRACE("\n");
113
114     vbarray = vbarray_this(vthis);
115     if(!vbarray)
116         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
117
118     if(argc) {
119         hres = to_int32(ctx, argv, ei, &dim);
120         if(FAILED(hres))
121             return hres;
122     } else
123         dim = 1;
124
125     hres = SafeArrayGetLBound(vbarray->safearray, dim, &dim);
126     if(hres == DISP_E_BADINDEX)
127         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
128     else if(FAILED(hres))
129         return hres;
130
131     if(retv)
132         num_set_int(retv, dim);
133     return S_OK;
134 }
135
136 static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, VARIANT *argv,
137         VARIANT *retv, jsexcept_t *ei)
138 {
139     VBArrayInstance *vbarray;
140     jsdisp_t *array;
141     VARIANT *v;
142     int i, size = 1, ubound, lbound;
143     HRESULT hres;
144
145     TRACE("\n");
146
147     vbarray = vbarray_this(vthis);
148     if(!vbarray)
149         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
150
151     for(i=1; i<=SafeArrayGetDim(vbarray->safearray); i++) {
152         SafeArrayGetLBound(vbarray->safearray, i, &lbound);
153         SafeArrayGetUBound(vbarray->safearray, i, &ubound);
154         size *= ubound-lbound+1;
155     }
156
157     hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
158     if(FAILED(hres))
159         return hres;
160
161     hres = create_array(ctx, 0, &array);
162     if(FAILED(hres)) {
163         SafeArrayUnaccessData(vbarray->safearray);
164         return hres;
165     }
166
167     for(i=0; i<size; i++) {
168         hres = jsdisp_propput_idx(array, i, v, ei);
169         if(FAILED(hres)) {
170             SafeArrayUnaccessData(vbarray->safearray);
171             jsdisp_release(array);
172             return hres;
173         }
174         v++;
175     }
176
177     SafeArrayUnaccessData(vbarray->safearray);
178
179     if(retv)
180         var_set_jsdisp(retv, array);
181     return S_OK;
182 }
183
184 static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, VARIANT *argv,
185         VARIANT *retv, jsexcept_t *ei)
186 {
187     VBArrayInstance *vbarray;
188     int dim;
189     HRESULT hres;
190
191     TRACE("\n");
192
193     vbarray = vbarray_this(vthis);
194     if(!vbarray)
195         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
196
197     if(argc) {
198         hres = to_int32(ctx, argv, ei, &dim);
199         if(FAILED(hres))
200             return hres;
201     } else
202         dim = 1;
203
204     hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim);
205     if(hres == DISP_E_BADINDEX)
206         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
207     else if(FAILED(hres))
208         return hres;
209
210     if(retv)
211         num_set_int(retv, dim);
212     return S_OK;
213 }
214
215 static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
216         VARIANT *retv, jsexcept_t *ei)
217 {
218     FIXME("\n");
219
220     switch(flags) {
221         default:
222             FIXME("unimplemented flags %x\n", flags);
223             return E_NOTIMPL;
224     }
225
226     return S_OK;
227 }
228
229 static void VBArray_destructor(jsdisp_t *dispex)
230 {
231     VBArrayInstance *vbarray = (VBArrayInstance*)dispex;
232
233     SafeArrayDestroy(vbarray->safearray);
234     heap_free(vbarray);
235 }
236
237 static const builtin_prop_t VBArray_props[] = {
238     {dimensionsW,           VBArray_dimensions,         PROPF_METHOD},
239     {getItemW,              VBArray_getItem,            PROPF_METHOD|1},
240     {lboundW,               VBArray_lbound,             PROPF_METHOD},
241     {toArrayW,              VBArray_toArray,            PROPF_METHOD},
242     {uboundW,               VBArray_ubound,             PROPF_METHOD}
243 };
244
245 static const builtin_info_t VBArray_info = {
246     JSCLASS_VBARRAY,
247     {NULL, VBArray_value, 0},
248     sizeof(VBArray_props)/sizeof(*VBArray_props),
249     VBArray_props,
250     VBArray_destructor,
251     NULL
252 };
253
254 static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
255 {
256     VBArrayInstance *vbarray;
257     HRESULT hres;
258
259     vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
260     if(!vbarray)
261         return E_OUTOFMEMORY;
262
263     if(object_prototype)
264         hres = init_dispex(&vbarray->dispex, ctx, &VBArray_info, object_prototype);
265     else
266         hres = init_dispex_from_constr(&vbarray->dispex, ctx, &VBArray_info, ctx->vbarray_constr);
267
268     if(FAILED(hres)) {
269         heap_free(vbarray);
270         return hres;
271     }
272
273     *ret = vbarray;
274     return S_OK;
275 }
276
277 static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, VARIANT *argv,
278         VARIANT *retv, jsexcept_t *ei)
279 {
280     VBArrayInstance *vbarray;
281     HRESULT hres;
282
283     TRACE("\n");
284
285     switch(flags) {
286     case DISPATCH_METHOD:
287         if(argc<1 || V_VT(argv) != (VT_ARRAY|VT_VARIANT))
288             return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
289
290         hres = VariantCopy(retv, argv);
291         return hres;
292
293     case DISPATCH_CONSTRUCT:
294         if(argc<1 || V_VT(argv) != (VT_ARRAY|VT_VARIANT))
295             return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
296
297         hres = alloc_vbarray(ctx, NULL, &vbarray);
298         if(FAILED(hres))
299             return hres;
300
301         hres = SafeArrayCopy(V_ARRAY(argv), &vbarray->safearray);
302         if(FAILED(hres)) {
303             jsdisp_release(&vbarray->dispex);
304             return hres;
305         }
306
307         var_set_jsdisp(retv, &vbarray->dispex);
308         break;
309
310     default:
311         FIXME("unimplemented flags: %x\n", flags);
312         return E_NOTIMPL;
313     }
314
315     return S_OK;
316 }
317
318 HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
319 {
320     VBArrayInstance *vbarray;
321     HRESULT hres;
322
323     static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
324
325     hres = alloc_vbarray(ctx, object_prototype, &vbarray);
326     if(FAILED(hres))
327         return hres;
328
329     hres = create_builtin_constructor(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
330
331     jsdisp_release(&vbarray->dispex);
332     return hres;
333 }
334
335 HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
336 {
337     VBArrayInstance *vbarray;
338     HRESULT hres;
339
340     hres = alloc_vbarray(ctx, NULL, &vbarray);
341     if(FAILED(hres))
342         return hres;
343
344     hres = SafeArrayCopy(sa, &vbarray->safearray);
345     if(FAILED(hres)) {
346         jsdisp_release(&vbarray->dispex);
347         return hres;
348     }
349
350     *ret = &vbarray->dispex;
351     return S_OK;
352 }