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