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_jsdisp(jsdisp_t *jsdisp) 38 { 39 return CONTAINING_RECORD(jsdisp, VBArrayInstance, dispex); 40 } 41 42 static inline VBArrayInstance *vbarray_from_vdisp(vdisp_t *vdisp) 43 { 44 return vbarray_from_jsdisp(vdisp->u.jsdisp); 45 } 46 47 static inline VBArrayInstance *vbarray_this(vdisp_t *jsthis) 48 { 49 return is_vclass(jsthis, JSCLASS_VBARRAY) ? vbarray_from_vdisp(jsthis) : NULL; 50 } 51 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 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 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 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 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 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 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 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 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 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 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