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