mshtml: HTMLWindow_item code clean up.
[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, DISPPARAMS *dp,
48         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
49 {
50     VBArrayInstance *vbarray;
51
52     TRACE("\n");
53
54     vbarray = vbarray_this(vthis);
55     if(!vbarray)
56         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
57
58     if(retv)
59         num_set_int(retv, SafeArrayGetDim(vbarray->safearray));
60     return S_OK;
61 }
62
63 static HRESULT VBArray_getItem(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
64         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
65 {
66     VBArrayInstance *vbarray;
67     int i, *indexes, size;
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, ei, JS_E_VBARRAY_EXPECTED, NULL);
76
77     size = arg_cnt(dp);
78     if(size < SafeArrayGetDim(vbarray->safearray))
79         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
80
81     indexes = heap_alloc(sizeof(int)*size);
82     if(!indexes)
83         return E_OUTOFMEMORY;
84
85     for(i=0; i<size; i++) {
86         hres = to_int32(ctx, get_arg(dp, i), ei, 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, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
97     else if(FAILED(hres))
98         return hres;
99
100     if(retv)
101         hres = VariantCopy(retv, &out);
102
103     return hres;
104 }
105
106 static HRESULT VBArray_lbound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
107         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
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, ei, JS_E_VBARRAY_EXPECTED, NULL);
118
119     if(arg_cnt(dp)) {
120         hres = to_int32(ctx, get_arg(dp, 0), ei, &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, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
129     else if(FAILED(hres))
130         return hres;
131
132     if(retv)
133         num_set_int(retv, dim);
134     return S_OK;
135 }
136
137 static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
138         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
139 {
140     VBArrayInstance *vbarray;
141     jsdisp_t *array;
142     VARIANT *v;
143     int i, size = 1, ubound, lbound;
144     HRESULT hres;
145
146     TRACE("\n");
147
148     vbarray = vbarray_this(vthis);
149     if(!vbarray)
150         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
151
152     for(i=1; i<=SafeArrayGetDim(vbarray->safearray); i++) {
153         SafeArrayGetLBound(vbarray->safearray, i, &lbound);
154         SafeArrayGetUBound(vbarray->safearray, i, &ubound);
155         size *= ubound-lbound+1;
156     }
157
158     hres = SafeArrayAccessData(vbarray->safearray, (void**)&v);
159     if(FAILED(hres))
160         return hres;
161
162     hres = create_array(ctx, 0, &array);
163     if(FAILED(hres)) {
164         SafeArrayUnaccessData(vbarray->safearray);
165         return hres;
166     }
167
168     for(i=0; i<size; i++) {
169         hres = jsdisp_propput_idx(array, i, v, ei, caller);
170         if(FAILED(hres)) {
171             SafeArrayUnaccessData(vbarray->safearray);
172             jsdisp_release(array);
173             return hres;
174         }
175         v++;
176     }
177
178     SafeArrayUnaccessData(vbarray->safearray);
179
180     if(retv)
181         var_set_jsdisp(retv, array);
182     return S_OK;
183 }
184
185 static HRESULT VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
186         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
187 {
188     VBArrayInstance *vbarray;
189     int dim;
190     HRESULT hres;
191
192     TRACE("\n");
193
194     vbarray = vbarray_this(vthis);
195     if(!vbarray)
196         return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
197
198     if(arg_cnt(dp)) {
199         hres = to_int32(ctx, get_arg(dp, 0), ei, &dim);
200         if(FAILED(hres))
201             return hres;
202     } else
203         dim = 1;
204
205     hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim);
206     if(hres == DISP_E_BADINDEX)
207         return throw_range_error(ctx, ei, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL);
208     else if(FAILED(hres))
209         return hres;
210
211     if(retv)
212         num_set_int(retv, dim);
213     return S_OK;
214 }
215
216 static HRESULT VBArray_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp,
217         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
218 {
219     FIXME("\n");
220
221     switch(flags) {
222         default:
223             FIXME("unimplemented flags %x\n", flags);
224             return E_NOTIMPL;
225     }
226
227     return S_OK;
228 }
229
230 static void VBArray_destructor(jsdisp_t *dispex)
231 {
232     VBArrayInstance *vbarray = (VBArrayInstance*)dispex;
233
234     SafeArrayDestroy(vbarray->safearray);
235     heap_free(vbarray);
236 }
237
238 static const builtin_prop_t VBArray_props[] = {
239     {dimensionsW,           VBArray_dimensions,         PROPF_METHOD},
240     {getItemW,              VBArray_getItem,            PROPF_METHOD|1},
241     {lboundW,               VBArray_lbound,             PROPF_METHOD},
242     {toArrayW,              VBArray_toArray,            PROPF_METHOD},
243     {uboundW,               VBArray_ubound,             PROPF_METHOD}
244 };
245
246 static const builtin_info_t VBArray_info = {
247     JSCLASS_VBARRAY,
248     {NULL, VBArray_value, 0},
249     sizeof(VBArray_props)/sizeof(*VBArray_props),
250     VBArray_props,
251     VBArray_destructor,
252     NULL
253 };
254
255 static HRESULT alloc_vbarray(script_ctx_t *ctx, jsdisp_t *object_prototype, VBArrayInstance **ret)
256 {
257     VBArrayInstance *vbarray;
258     HRESULT hres;
259
260     vbarray = heap_alloc_zero(sizeof(VBArrayInstance));
261     if(!vbarray)
262         return E_OUTOFMEMORY;
263
264     if(object_prototype)
265         hres = init_dispex(&vbarray->dispex, ctx, &VBArray_info, object_prototype);
266     else
267         hres = init_dispex_from_constr(&vbarray->dispex, ctx, &VBArray_info, ctx->vbarray_constr);
268
269     if(FAILED(hres)) {
270         heap_free(vbarray);
271         return hres;
272     }
273
274     *ret = vbarray;
275     return S_OK;
276 }
277
278 static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp,
279         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
280 {
281     VARIANT *arg;
282     VBArrayInstance *vbarray;
283     HRESULT hres;
284
285     TRACE("\n");
286
287     switch(flags) {
288     case DISPATCH_METHOD:
289         if(arg_cnt(dp)<1 || V_VT((arg = get_arg(dp, 0)))!=(VT_ARRAY|VT_VARIANT))
290             return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
291
292         hres = VariantCopy(retv, arg);
293         return hres;
294
295     case DISPATCH_CONSTRUCT:
296         if(arg_cnt(dp)<1 || V_VT((arg = get_arg(dp, 0)))!=(VT_ARRAY|VT_VARIANT))
297             return throw_type_error(ctx, ei, JS_E_VBARRAY_EXPECTED, NULL);
298
299         hres = alloc_vbarray(ctx, NULL, &vbarray);
300         if(FAILED(hres))
301             return hres;
302
303         hres = SafeArrayCopy(V_ARRAY(arg), &vbarray->safearray);
304         if(FAILED(hres)) {
305             jsdisp_release(&vbarray->dispex);
306             return hres;
307         }
308
309         var_set_jsdisp(retv, &vbarray->dispex);
310         break;
311
312     default:
313         FIXME("unimplemented flags: %x\n", flags);
314         return E_NOTIMPL;
315     }
316
317     return S_OK;
318 }
319
320 HRESULT create_vbarray_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
321 {
322     VBArrayInstance *vbarray;
323     HRESULT hres;
324
325     static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
326
327     hres = alloc_vbarray(ctx, object_prototype, &vbarray);
328     if(FAILED(hres))
329         return hres;
330
331     hres = create_builtin_function(ctx, VBArrayConstr_value, VBArrayW, NULL, PROPF_CONSTR|1, &vbarray->dispex, ret);
332
333     jsdisp_release(&vbarray->dispex);
334     return hres;
335 }
336
337 HRESULT create_vbarray(script_ctx_t *ctx, SAFEARRAY *sa, jsdisp_t **ret)
338 {
339     VBArrayInstance *vbarray;
340     HRESULT hres;
341
342     hres = alloc_vbarray(ctx, NULL, &vbarray);
343     if(FAILED(hres))
344         return hres;
345
346     hres = SafeArrayCopy(sa, &vbarray->safearray);
347     if(FAILED(hres)) {
348         jsdisp_release(&vbarray->dispex);
349         return hres;
350     }
351
352     *ret = &vbarray->dispex;
353     return S_OK;
354 }