winejoystick: Fix a crash on accessing a CFArray past its end due to an off-by-one...
[wine/multimedia.git] / dlls / jscript / vbarray.c
blob7b9993b338256ba558fae74ea4272e03bbe2861c
1 /*
2 * Copyright 2010 Piotr Caban for CodeWeavers
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.
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.
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
19 #include "jscript.h"
21 #include "wine/debug.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
25 typedef struct {
26 jsdisp_t dispex;
28 SAFEARRAY *safearray;
29 } VBArrayInstance;
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};
37 static inline VBArrayInstance *vbarray_from_vdisp(vdisp_t *vdisp)
39 return (VBArrayInstance*)vdisp->u.jsdisp;
42 static inline VBArrayInstance *vbarray_this(vdisp_t *jsthis)
44 return is_vclass(jsthis, JSCLASS_VBARRAY) ? vbarray_from_vdisp(jsthis) : NULL;
47 static HRESULT VBArray_dimensions(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
48 jsval_t *r)
50 VBArrayInstance *vbarray;
52 TRACE("\n");
54 vbarray = vbarray_this(vthis);
55 if(!vbarray)
56 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
58 if(r)
59 *r = jsval_number(SafeArrayGetDim(vbarray->safearray));
60 return S_OK;
63 static HRESULT VBArray_getItem(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
64 jsval_t *r)
66 VBArrayInstance *vbarray;
67 int i, *indexes;
68 VARIANT out;
69 HRESULT hres;
71 TRACE("\n");
73 vbarray = vbarray_this(vthis);
74 if(!vbarray)
75 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
77 if(argc < SafeArrayGetDim(vbarray->safearray))
78 return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
80 indexes = heap_alloc(sizeof(int)*argc);
81 if(!indexes)
82 return E_OUTOFMEMORY;
84 for(i=0; i<argc; i++) {
85 hres = to_int32(ctx, argv[i], indexes+i);
86 if(FAILED(hres)) {
87 heap_free(indexes);
88 return hres;
92 hres = SafeArrayGetElement(vbarray->safearray, indexes, (void*)&out);
93 heap_free(indexes);
94 if(hres == DISP_E_BADINDEX)
95 return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
96 else if(FAILED(hres))
97 return hres;
99 if(r) {
100 hres = variant_to_jsval(&out, r);
101 VariantClear(&out);
103 return hres;
106 static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
107 jsval_t *r)
109 VBArrayInstance *vbarray;
110 int dim;
111 HRESULT hres;
113 TRACE("\n");
115 vbarray = vbarray_this(vthis);
116 if(!vbarray)
117 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
119 if(argc) {
120 hres = to_int32(ctx, argv[0], &dim);
121 if(FAILED(hres))
122 return hres;
123 } else
124 dim = 1;
126 hres = SafeArrayGetLBound(vbarray->safearray, dim, &dim);
127 if(hres == DISP_E_BADINDEX)
128 return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
129 else if(FAILED(hres))
130 return hres;
132 if(r)
133 *r = jsval_number(dim);
134 return S_OK;
137 static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
138 jsval_t *r)
140 VBArrayInstance *vbarray;
141 jsdisp_t *array;
142 jsval_t val;
143 VARIANT *v;
144 int i, size = 1, ubound, lbound;
145 HRESULT hres;
147 TRACE("\n");
149 vbarray = vbarray_this(vthis);
150 if(!vbarray)
151 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
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;
159 hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
160 if(FAILED(hres))
161 return hres;
163 hres = create_array(ctx, 0, &array);
164 if(FAILED(hres)) {
165 SafeArrayUnaccessData(vbarray->safearray);
166 return hres;
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);
173 jsval_release(val);
175 if(FAILED(hres)) {
176 SafeArrayUnaccessData(vbarray->safearray);
177 jsdisp_release(array);
178 return hres;
180 v++;
183 SafeArrayUnaccessData(vbarray->safearray);
185 if(r)
186 *r = jsval_obj(array);
187 else
188 jsdisp_release(array);
189 return S_OK;
192 static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
193 jsval_t *r)
195 VBArrayInstance *vbarray;
196 int dim;
197 HRESULT hres;
199 TRACE("\n");
201 vbarray = vbarray_this(vthis);
202 if(!vbarray)
203 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
205 if(argc) {
206 hres = to_int32(ctx, argv[0], &dim);
207 if(FAILED(hres))
208 return hres;
209 } else
210 dim = 1;
212 hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim);
213 if(hres == DISP_E_BADINDEX)
214 return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
215 else if(FAILED(hres))
216 return hres;
218 if(r)
219 *r = jsval_number(dim);
220 return S_OK;
223 static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
224 jsval_t *r)
226 FIXME("\n");
228 switch(flags) {
229 default:
230 FIXME("unimplemented flags %x\n", flags);
231 return E_NOTIMPL;
234 return S_OK;
237 static void VBArray_destructor(jsdisp_t *dispex)
239 VBArrayInstance *vbarray = (VBArrayInstance*)dispex;
241 SafeArrayDestroy(vbarray->safearray);
242 heap_free(vbarray);
245 static const builtin_prop_t VBArray_props[] = {
246 {dimensionsW, VBArray_dimensions, PROPF_METHOD},
247 {getItemW, VBArray_getItem, PROPF_METHOD|1},
248 {lboundW, VBArray_lbound, PROPF_METHOD},
249 {toArrayW, VBArray_toArray, PROPF_METHOD},
250 {uboundW, VBArray_ubound, PROPF_METHOD}
253 static const builtin_info_t VBArray_info = {
254 JSCLASS_VBARRAY,
255 {NULL, VBArray_value, 0},
256 sizeof(VBArray_props)/sizeof(*VBArray_props),
257 VBArray_props,
258 VBArray_destructor,
259 NULL
262 static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
264 VBArrayInstance *vbarray;
265 HRESULT hres;
267 vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
268 if(!vbarray)
269 return E_OUTOFMEMORY;
271 if(object_prototype)
272 hres = init_dispex(&vbarray->dispex, ctx, &VBArray_info, object_prototype);
273 else
274 hres = init_dispex_from_constr(&vbarray->dispex, ctx, &VBArray_info, ctx->vbarray_constr);
276 if(FAILED(hres)) {
277 heap_free(vbarray);
278 return hres;
281 *ret = vbarray;
282 return S_OK;
285 static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
286 jsval_t *r)
288 VBArrayInstance *vbarray;
289 HRESULT hres;
291 TRACE("\n");
293 switch(flags) {
294 case DISPATCH_METHOD:
295 if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
296 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
298 return jsval_copy(argv[0], r);
300 case DISPATCH_CONSTRUCT:
301 if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT))
302 return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
304 hres = alloc_vbarray(ctx, NULL, &vbarray);
305 if(FAILED(hres))
306 return hres;
308 hres = SafeArrayCopy(V_ARRAY(get_variant(argv[0])), &vbarray->safearray);
309 if(FAILED(hres)) {
310 jsdisp_release(&vbarray->dispex);
311 return hres;
314 *r = jsval_obj(&vbarray->dispex);
315 break;
317 default:
318 FIXME("unimplemented flags: %x\n", flags);
319 return E_NOTIMPL;
322 return S_OK;
325 HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
327 VBArrayInstance *vbarray;
328 HRESULT hres;
330 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
332 hres = alloc_vbarray(ctx, object_prototype, &vbarray);
333 if(FAILED(hres))
334 return hres;
336 hres = create_builtin_constructor(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
338 jsdisp_release(&vbarray->dispex);
339 return hres;
342 HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
344 VBArrayInstance *vbarray;
345 HRESULT hres;
347 hres = alloc_vbarray(ctx, NULL, &vbarray);
348 if(FAILED(hres))
349 return hres;
351 hres = SafeArrayCopy(sa, &vbarray->safearray);
352 if(FAILED(hres)) {
353 jsdisp_release(&vbarray->dispex);
354 return hres;
357 *ret = &vbarray->dispex;
358 return S_OK;