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