1 /* 2 * Copyright 2008 Jacek 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 <assert.h> 20 21 #include "jscript.h" 22 23 #include "wine/debug.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 26 27 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; 28 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0}; 29 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; 30 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0}; 31 static const WCHAR propertyIsEnumerableW[] = 32 {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0}; 33 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0}; 34 35 static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0}; 36 37 static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 38 jsval_t *r) 39 { 40 jsdisp_t *jsdisp; 41 const WCHAR *str; 42 43 static const WCHAR formatW[] = {'[','o','b','j','e','c','t',' ','%','s',']',0}; 44 45 static const WCHAR arrayW[] = {'A','r','r','a','y',0}; 46 static const WCHAR booleanW[] = {'B','o','o','l','e','a','n',0}; 47 static const WCHAR dateW[] = {'D','a','t','e',0}; 48 static const WCHAR errorW[] = {'E','r','r','o','r',0}; 49 static const WCHAR functionW[] = {'F','u','n','c','t','i','o','n',0}; 50 static const WCHAR mathW[] = {'M','a','t','h',0}; 51 static const WCHAR numberW[] = {'N','u','m','b','e','r',0}; 52 static const WCHAR objectW[] = {'O','b','j','e','c','t',0}; 53 static const WCHAR regexpW[] = {'R','e','g','E','x','p',0}; 54 static const WCHAR stringW[] = {'S','t','r','i','n','g',0}; 55 /* Keep in sync with jsclass_t enum */ 56 static const WCHAR *names[] = {NULL, arrayW, booleanW, dateW, errorW, 57 functionW, NULL, mathW, numberW, objectW, regexpW, stringW, objectW, objectW, objectW}; 58 59 TRACE("\n"); 60 61 jsdisp = get_jsdisp(jsthis); 62 if(!jsdisp) { 63 str = objectW; 64 }else if(names[jsdisp->builtin_info->class]) { 65 str = names[jsdisp->builtin_info->class]; 66 }else { 67 assert(jsdisp->builtin_info->class != JSCLASS_NONE); 68 FIXME("jdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class); 69 return E_FAIL; 70 } 71 72 if(r) { 73 jsstr_t *ret; 74 WCHAR *ptr; 75 76 ret = jsstr_alloc_buf(9+strlenW(str), &ptr); 77 if(!ret) 78 return E_OUTOFMEMORY; 79 80 sprintfW(ptr, formatW, str); 81 *r = jsval_string(ret); 82 } 83 84 return S_OK; 85 } 86 87 static HRESULT Object_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 88 jsval_t *r) 89 { 90 TRACE("\n"); 91 92 if(!is_jsdisp(jsthis)) { 93 FIXME("Host object this\n"); 94 return E_FAIL; 95 } 96 97 return jsdisp_call_name(jsthis->u.jsdisp, toStringW, DISPATCH_METHOD, 0, NULL, r); 98 } 99 100 static HRESULT Object_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 101 jsval_t *r) 102 { 103 TRACE("\n"); 104 105 if(r) { 106 IDispatch_AddRef(jsthis->u.disp); 107 *r = jsval_disp(jsthis->u.disp); 108 } 109 return S_OK; 110 } 111 112 static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 113 jsval_t *r) 114 { 115 jsstr_t *name; 116 DISPID id; 117 BSTR bstr; 118 HRESULT hres; 119 120 TRACE("\n"); 121 122 if(!argc) { 123 if(r) 124 *r = jsval_bool(FALSE); 125 return S_OK; 126 } 127 128 hres = to_string(ctx, argv[0], &name); 129 if(FAILED(hres)) 130 return hres; 131 132 if(is_jsdisp(jsthis)) { 133 const WCHAR *name_str; 134 BOOL result; 135 136 name_str = jsstr_flatten(name); 137 if(name_str) 138 hres = jsdisp_is_own_prop(jsthis->u.jsdisp, name_str, &result); 139 else 140 hres = E_OUTOFMEMORY; 141 jsstr_release(name); 142 if(FAILED(hres)) 143 return hres; 144 145 if(r) 146 *r = jsval_bool(result); 147 return S_OK; 148 } 149 150 151 bstr = SysAllocStringLen(NULL, jsstr_length(name)); 152 if(bstr) 153 jsstr_flush(name, bstr); 154 jsstr_release(name); 155 if(!bstr) 156 return E_OUTOFMEMORY; 157 158 if(is_dispex(jsthis)) 159 hres = IDispatchEx_GetDispID(jsthis->u.dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id); 160 else 161 hres = IDispatch_GetIDsOfNames(jsthis->u.disp, &IID_NULL, &bstr, 1, ctx->lcid, &id); 162 163 SysFreeString(bstr); 164 if(r) 165 *r = jsval_bool(SUCCEEDED(hres)); 166 return S_OK; 167 } 168 169 static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 170 jsval_t *r) 171 { 172 const WCHAR *name; 173 jsstr_t *name_str; 174 BOOL ret; 175 HRESULT hres; 176 177 TRACE("\n"); 178 179 if(argc != 1) { 180 FIXME("argc %d not supported\n", argc); 181 return E_NOTIMPL; 182 } 183 184 if(!is_jsdisp(jsthis)) { 185 FIXME("Host object this\n"); 186 return E_FAIL; 187 } 188 189 hres = to_flat_string(ctx, argv[0], &name_str, &name); 190 if(FAILED(hres)) 191 return hres; 192 193 hres = jsdisp_is_enumerable(jsthis->u.jsdisp, name, &ret); 194 jsstr_release(name_str); 195 if(FAILED(hres)) 196 return hres; 197 198 if(r) 199 *r = jsval_bool(ret); 200 return S_OK; 201 } 202 203 static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 204 jsval_t *r) 205 { 206 FIXME("\n"); 207 return E_NOTIMPL; 208 } 209 210 static HRESULT Object_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) 211 { 212 jsstr_t *ret; 213 214 TRACE("\n"); 215 216 ret = jsstr_alloc(default_valueW); 217 if(!ret) 218 return E_OUTOFMEMORY; 219 220 *r = jsval_string(ret); 221 return S_OK; 222 } 223 224 static void Object_destructor(jsdisp_t *dispex) 225 { 226 heap_free(dispex); 227 } 228 229 static const builtin_prop_t Object_props[] = { 230 {hasOwnPropertyW, Object_hasOwnProperty, PROPF_METHOD|1}, 231 {isPrototypeOfW, Object_isPrototypeOf, PROPF_METHOD|1}, 232 {propertyIsEnumerableW, Object_propertyIsEnumerable, PROPF_METHOD|1}, 233 {toLocaleStringW, Object_toLocaleString, PROPF_METHOD}, 234 {toStringW, Object_toString, PROPF_METHOD}, 235 {valueOfW, Object_valueOf, PROPF_METHOD} 236 }; 237 238 static const builtin_info_t Object_info = { 239 JSCLASS_OBJECT, 240 {NULL, NULL,0, Object_get_value}, 241 sizeof(Object_props)/sizeof(*Object_props), 242 Object_props, 243 Object_destructor, 244 NULL 245 }; 246 247 static const builtin_info_t ObjectInst_info = { 248 JSCLASS_OBJECT, 249 {NULL, NULL,0, Object_get_value}, 250 0, NULL, 251 Object_destructor, 252 NULL 253 }; 254 255 static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 256 jsval_t *r) 257 { 258 HRESULT hres; 259 260 TRACE("\n"); 261 262 switch(flags) { 263 case DISPATCH_METHOD: 264 case DISPATCH_CONSTRUCT: { 265 jsdisp_t *obj; 266 267 if(argc) { 268 if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) { 269 IDispatch *disp; 270 271 hres = to_object(ctx, argv[0], &disp); 272 if(FAILED(hres)) 273 return hres; 274 275 if(r) 276 *r = jsval_disp(disp); 277 else 278 IDispatch_Release(disp); 279 return S_OK; 280 } 281 } 282 283 hres = create_object(ctx, NULL, &obj); 284 if(FAILED(hres)) 285 return hres; 286 287 if(r) 288 *r = jsval_obj(obj); 289 else 290 jsdisp_release(obj); 291 break; 292 } 293 294 default: 295 FIXME("unimplemented flags: %x\n", flags); 296 return E_NOTIMPL; 297 } 298 299 return S_OK; 300 } 301 302 HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) 303 { 304 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0}; 305 306 return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, NULL, PROPF_CONSTR, 307 object_prototype, ret); 308 } 309 310 HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret) 311 { 312 return create_dispex(ctx, &Object_info, NULL, ret); 313 } 314 315 HRESULT create_object(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t **ret) 316 { 317 jsdisp_t *object; 318 HRESULT hres; 319 320 object = heap_alloc_zero(sizeof(jsdisp_t)); 321 if(!object) 322 return E_OUTOFMEMORY; 323 324 hres = init_dispex_from_constr(object, ctx, &ObjectInst_info, constr ? constr : ctx->object_constr); 325 if(FAILED(hres)) { 326 heap_free(object); 327 return hres; 328 } 329 330 *ret = object; 331 return S_OK; 332 } 333