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