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