[JSCRIPT]
[reactos.git] / reactos / 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_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 }