kernel32/tests: Fix failures with virtual Drives (AppVirt Client).
[wine] / dlls / 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 #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
37 static inline VBArrayInstance *vbarray_from_vdisp(vdisp_t *vdisp)
38 {
39     return (VBArrayInstance*)vdisp->u.jsdisp;
40 }
41
42 static inline VBArrayInstance *vbarray_this(vdisp_t *jsthis)
43 {
44     return is_vclass(jsthis, JSCLASS_VBARRAY) ? vbarray_from_vdisp(jsthis) : NULL;
45 }
46
47 static HRESULT VBArray_dimensions(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
48         jsval_t *r)
49 {
50     VBArrayInstance *vbarray;
51
52     TRACE("\n");
53
54     vbarray = vbarray_this(vthis);
55     if(!vbarray)
56         return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
57
58     if(r)
59         *r = jsval_number(SafeArrayGetDim(vbarray->safearray));
60     return S_OK;
61 }
62
63 static HRESULT VBArray_getItem(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
64         jsval_t *r)
65 {
66     VBArrayInstance *vbarray;
67     int i, *indexes;
68     VARIANT out;
69     HRESULT hres;
70
71     TRACE("\n");
72
73     vbarray = vbarray_this(vthis);
74     if(!vbarray)
75         return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
76
77     if(argc < SafeArrayGetDim(vbarray->safearray))
78         return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
79
80     indexes = heap_alloc(sizeof(int)*argc);
81     if(!indexes)
82         return E_OUTOFMEMORY;
83
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;
89         }
90     }
91
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;
98
99     if(r) {
100         hres = variant_to_jsval(&out, r);
101         VariantClear(&out);
102     }
103     return hres;
104 }
105
106 static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
107         jsval_t *r)
108 {
109     VBArrayInstance *vbarray;
110     int dim;
111     HRESULT hres;
112
113     TRACE("\n");
114
115     vbarray = vbarray_this(vthis);
116     if(!vbarray)
117         return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
118
119     if(argc) {
120         hres = to_int32(ctx, argv[0], &dim);
121         if(FAILED(hres))
122             return hres;
123     } else
124         dim = 1;
125
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;
131
132     if(r)
133         *r = jsval_number(dim);
134     return S_OK;
135 }
136
137 static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
138         jsval_t *r)
139 {
140     VBArrayInstance *vbarray;
141     jsdisp_t *array;
142     jsval_t val;
143     VARIANT *v;
144     int i, size = 1, ubound, lbound;
145     HRESULT hres;
146
147     TRACE("\n");
148
149     vbarray = vbarray_this(vthis);
150     if(!vbarray)
151         return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
152
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;
157     }
158
159     hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
160     if(FAILED(hres))
161         return hres;
162
163     hres = create_array(ctx, 0, &array);
164     if(FAILED(hres)) {
165         SafeArrayUnaccessData(vbarray->safearray);
166         return hres;
167     }
168
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);
174         }
175         if(FAILED(hres)) {
176             SafeArrayUnaccessData(vbarray->safearray);
177             jsdisp_release(array);
178             return hres;
179         }
180         v++;
181     }
182
183     SafeArrayUnaccessData(vbarray->safearray);
184
185     if(r)
186         *r = jsval_obj(array);
187     else
188         jsdisp_release(array);
189     return S_OK;
190 }
191
192 static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
193         jsval_t *r)
194 {
195     VBArrayInstance *vbarray;
196     int dim;
197     HRESULT hres;
198
199     TRACE("\n");
200
201     vbarray = vbarray_this(vthis);
202     if(!vbarray)
203         return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL);
204
205     if(argc) {
206         hres = to_int32(ctx, argv[0], &dim);
207         if(FAILED(hres))
208             return hres;
209     } else
210         dim = 1;
211
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;
217
218     if(r)
219         *r = jsval_number(dim);
220     return S_OK;
221 }
222
223 static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
224         jsval_t *r)
225 {
226     FIXME("\n");
227
228     switch(flags) {
229         default:
230             FIXME("unimplemented flags %x\n", flags);
231             return E_NOTIMPL;
232     }
233
234     return S_OK;
235 }
236
237 static void VBArray_destructor(jsdisp_t *dispex)
238 {
239     VBArrayInstance *vbarray = (VBArrayInstance*)dispex;
240
241     SafeArrayDestroy(vbarray->safearray);
242     heap_free(vbarray);
243 }
244
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}
251 };
252
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
260 };
261
262 static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
263 {
264     VBArrayInstance *vbarray;
265     HRESULT hres;
266
267     vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
268     if(!vbarray)
269         return E_OUTOFMEMORY;
270
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);
275
276     if(FAILED(hres)) {
277         heap_free(vbarray);
278         return hres;
279     }
280
281     *ret = vbarray;
282     return S_OK;
283 }
284
285 static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
286         jsval_t *r)
287 {
288     VBArrayInstance *vbarray;
289     HRESULT hres;
290
291     TRACE("\n");
292
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);
297
298         return jsval_copy(argv[0], r);
299
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);
303
304         hres = alloc_vbarray(ctx, NULL, &vbarray);
305         if(FAILED(hres))
306             return hres;
307
308         hres = SafeArrayCopy(V_ARRAY(get_variant(argv[0])), &vbarray->safearray);
309         if(FAILED(hres)) {
310             jsdisp_release(&vbarray->dispex);
311             return hres;
312         }
313
314         *r = jsval_obj(&vbarray->dispex);
315         break;
316
317     default:
318         FIXME("unimplemented flags: %x\n", flags);
319         return E_NOTIMPL;
320     }
321
322     return S_OK;
323 }
324
325 HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
326 {
327     VBArrayInstance *vbarray;
328     HRESULT hres;
329
330     static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
331
332     hres = alloc_vbarray(ctx, object_prototype, &vbarray);
333     if(FAILED(hres))
334         return hres;
335
336     hres = create_builtin_constructor(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
337
338     jsdisp_release(&vbarray->dispex);
339     return hres;
340 }
341
342 HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
343 {
344     VBArrayInstance *vbarray;
345     HRESULT hres;
346
347     hres = alloc_vbarray(ctx, NULL, &vbarray);
348     if(FAILED(hres))
349         return hres;
350
351     hres = SafeArrayCopy(sa, &vbarray->safearray);
352     if(FAILED(hres)) {
353         jsdisp_release(&vbarray->dispex);
354         return hres;
355     }
356
357     *ret = &vbarray->dispex;
358     return S_OK;
359 }