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 } 356