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