1 /* 2 * Copyright 2009 Piotr Caban 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 #ifdef __REACTOS__ 20 #include <wine/config.h> 21 #include <wine/port.h> 22 #endif 23 24 #include <math.h> 25 26 #include "jscript.h" 27 28 #include "wine/debug.h" 29 30 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 31 32 static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0}; 33 static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0}; 34 static const WCHAR nameW[] = {'n','a','m','e',0}; 35 static const WCHAR numberW[] = {'n','u','m','b','e','r',0}; 36 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; 37 38 /* ECMA-262 3rd Edition 15.11.4.4 */ 39 static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, 40 unsigned argc, jsval_t *argv, jsval_t *r) 41 { 42 jsdisp_t *jsthis; 43 jsstr_t *name = NULL, *msg = NULL, *ret = NULL; 44 jsval_t v; 45 HRESULT hres; 46 47 static const WCHAR object_errorW[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0}; 48 49 TRACE("\n"); 50 51 jsthis = get_jsdisp(vthis); 52 if(!jsthis || ctx->version < 2) { 53 if(r) { 54 jsstr_t *str; 55 56 str = jsstr_alloc(object_errorW); 57 if(!str) 58 return E_OUTOFMEMORY; 59 *r = jsval_string(str); 60 } 61 return S_OK; 62 } 63 64 hres = jsdisp_propget_name(jsthis, nameW, &v); 65 if(FAILED(hres)) 66 return hres; 67 68 if(!is_undefined(v)) { 69 hres = to_string(ctx, v, &name); 70 jsval_release(v); 71 if(FAILED(hres)) 72 return hres; 73 } 74 75 hres = jsdisp_propget_name(jsthis, messageW, &v); 76 if(SUCCEEDED(hres)) { 77 if(!is_undefined(v)) { 78 hres = to_string(ctx, v, &msg); 79 jsval_release(v); 80 } 81 } 82 83 if(SUCCEEDED(hres)) { 84 unsigned name_len = name ? jsstr_length(name) : 0; 85 unsigned msg_len = msg ? jsstr_length(msg) : 0; 86 87 if(name_len && msg_len) { 88 WCHAR *ptr; 89 90 ret = jsstr_alloc_buf(name_len + msg_len + 2, &ptr); 91 if(ret) { 92 jsstr_flush(name, ptr); 93 ptr[name_len] = ':'; 94 ptr[name_len+1] = ' '; 95 jsstr_flush(msg, ptr+name_len+2); 96 }else { 97 hres = E_OUTOFMEMORY; 98 } 99 }else if(name_len) { 100 ret = name; 101 name = NULL; 102 }else if(msg_len) { 103 ret = msg; 104 msg = NULL; 105 }else { 106 ret = jsstr_alloc(object_errorW); 107 } 108 } 109 110 if(msg) 111 jsstr_release(msg); 112 if(name) 113 jsstr_release(name); 114 if(FAILED(hres)) 115 return hres; 116 if(!ret) 117 return E_OUTOFMEMORY; 118 119 if(r) 120 *r = jsval_string(ret); 121 else 122 jsstr_release(ret); 123 return S_OK; 124 } 125 126 static HRESULT Error_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 127 unsigned argc, jsval_t *argv, jsval_t *r) 128 { 129 TRACE("\n"); 130 131 switch(flags) { 132 case INVOKE_FUNC: 133 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); 134 default: 135 FIXME("unimplemented flags %x\n", flags); 136 return E_NOTIMPL; 137 } 138 139 return S_OK; 140 } 141 142 static const builtin_prop_t Error_props[] = { 143 {toStringW, Error_toString, PROPF_METHOD} 144 }; 145 146 static const builtin_info_t Error_info = { 147 JSCLASS_ERROR, 148 {NULL, Error_value, 0}, 149 ARRAY_SIZE(Error_props), 150 Error_props, 151 NULL, 152 NULL 153 }; 154 155 static const builtin_info_t ErrorInst_info = { 156 JSCLASS_ERROR, 157 {NULL, Error_value, 0}, 158 0, 159 NULL, 160 NULL, 161 NULL 162 }; 163 164 static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype, 165 jsdisp_t *constr, jsdisp_t **ret) 166 { 167 jsdisp_t *err; 168 HRESULT hres; 169 170 err = heap_alloc_zero(sizeof(*err)); 171 if(!err) 172 return E_OUTOFMEMORY; 173 174 if(prototype) 175 hres = init_dispex(err, ctx, &Error_info, prototype); 176 else 177 hres = init_dispex_from_constr(err, ctx, &ErrorInst_info, 178 constr ? constr : ctx->error_constr); 179 if(FAILED(hres)) { 180 heap_free(err); 181 return hres; 182 } 183 184 *ret = err; 185 return S_OK; 186 } 187 188 static HRESULT create_error(script_ctx_t *ctx, jsdisp_t *constr, 189 UINT number, jsstr_t *msg, jsdisp_t **ret) 190 { 191 jsdisp_t *err; 192 HRESULT hres; 193 194 hres = alloc_error(ctx, NULL, constr, &err); 195 if(FAILED(hres)) 196 return hres; 197 198 hres = jsdisp_define_data_property(err, numberW, PROPF_WRITABLE | PROPF_CONFIGURABLE, 199 jsval_number((INT)number)); 200 if(FAILED(hres)) { 201 jsdisp_release(err); 202 return hres; 203 } 204 205 hres = jsdisp_define_data_property(err, messageW, 206 PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, 207 jsval_string(msg)); 208 if(SUCCEEDED(hres)) 209 hres = jsdisp_define_data_property(err, descriptionW, PROPF_WRITABLE | PROPF_CONFIGURABLE, 210 jsval_string(msg)); 211 if(FAILED(hres)) { 212 jsdisp_release(err); 213 return hres; 214 } 215 216 *ret = err; 217 return S_OK; 218 } 219 220 static HRESULT error_constr(script_ctx_t *ctx, WORD flags, unsigned argc, jsval_t *argv, 221 jsval_t *r, jsdisp_t *constr) { 222 jsdisp_t *err; 223 UINT num = 0; 224 jsstr_t *msg = NULL; 225 HRESULT hres; 226 227 if(argc) { 228 double n; 229 230 hres = to_number(ctx, argv[0], &n); 231 if(FAILED(hres)) /* FIXME: really? */ 232 n = NAN; 233 if(isnan(n)) 234 hres = to_string(ctx, argv[0], &msg); 235 if(FAILED(hres)) 236 return hres; 237 num = n; 238 } 239 240 if(!msg) { 241 if(argc > 1) { 242 hres = to_string(ctx, argv[1], &msg); 243 if(FAILED(hres)) 244 return hres; 245 }else { 246 msg = jsstr_empty(); 247 } 248 } 249 250 switch(flags) { 251 case INVOKE_FUNC: 252 case DISPATCH_CONSTRUCT: 253 hres = create_error(ctx, constr, num, msg, &err); 254 jsstr_release(msg); 255 if(FAILED(hres)) 256 return hres; 257 258 if(r) 259 *r = jsval_obj(err); 260 else 261 jsdisp_release(err); 262 return S_OK; 263 264 default: 265 if(msg) 266 jsstr_release(msg); 267 FIXME("unimplemented flags %x\n", flags); 268 return E_NOTIMPL; 269 } 270 } 271 272 static HRESULT ErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 273 unsigned argc, jsval_t *argv, jsval_t *r) 274 { 275 TRACE("\n"); 276 return error_constr(ctx, flags, argc, argv, r, ctx->error_constr); 277 } 278 279 static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 280 unsigned argc, jsval_t *argv, jsval_t *r) 281 { 282 TRACE("\n"); 283 return error_constr(ctx, flags, argc, argv, r, ctx->eval_error_constr); 284 } 285 286 static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 287 unsigned argc, jsval_t *argv, jsval_t *r) 288 { 289 TRACE("\n"); 290 return error_constr(ctx, flags, argc, argv, r, ctx->range_error_constr); 291 } 292 293 static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 294 unsigned argc, jsval_t *argv, jsval_t *r) 295 { 296 TRACE("\n"); 297 return error_constr(ctx, flags, argc, argv, r, ctx->reference_error_constr); 298 } 299 300 static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 301 unsigned argc, jsval_t *argv, jsval_t *r) 302 { 303 TRACE("\n"); 304 return error_constr(ctx, flags, argc, argv, r, ctx->regexp_error_constr); 305 } 306 307 static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 308 unsigned argc, jsval_t *argv, jsval_t *r) 309 { 310 TRACE("\n"); 311 return error_constr(ctx, flags, argc, argv, r, ctx->syntax_error_constr); 312 } 313 314 static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 315 unsigned argc, jsval_t *argv, jsval_t *r) 316 { 317 TRACE("\n"); 318 return error_constr(ctx, flags, argc, argv, r, ctx->type_error_constr); 319 } 320 321 static HRESULT URIErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, 322 unsigned argc, jsval_t *argv, jsval_t *r) 323 { 324 TRACE("\n"); 325 return error_constr(ctx, flags, argc, argv, r, ctx->uri_error_constr); 326 } 327 328 HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) 329 { 330 static const WCHAR ErrorW[] = {'E','r','r','o','r',0}; 331 static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0}; 332 static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0}; 333 static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0}; 334 static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0}; 335 static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0}; 336 static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0}; 337 static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0}; 338 static const WCHAR *names[] = {ErrorW, EvalErrorW, RangeErrorW, 339 ReferenceErrorW, RegExpErrorW, SyntaxErrorW, TypeErrorW, URIErrorW}; 340 jsdisp_t **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr, 341 &ctx->range_error_constr, &ctx->reference_error_constr, &ctx->regexp_error_constr, 342 &ctx->syntax_error_constr, &ctx->type_error_constr, 343 &ctx->uri_error_constr}; 344 static builtin_invoke_t constr_val[] = {ErrorConstr_value, EvalErrorConstr_value, 345 RangeErrorConstr_value, ReferenceErrorConstr_value, RegExpErrorConstr_value, 346 SyntaxErrorConstr_value, TypeErrorConstr_value, URIErrorConstr_value}; 347 348 jsdisp_t *err; 349 unsigned int i; 350 jsstr_t *str; 351 HRESULT hres; 352 353 for(i=0; i < ARRAY_SIZE(names); i++) { 354 hres = alloc_error(ctx, i==0 ? object_prototype : NULL, NULL, &err); 355 if(FAILED(hres)) 356 return hres; 357 358 str = jsstr_alloc(names[i]); 359 if(!str) { 360 jsdisp_release(err); 361 return E_OUTOFMEMORY; 362 } 363 364 hres = jsdisp_define_data_property(err, nameW, PROPF_WRITABLE | PROPF_CONFIGURABLE, 365 jsval_string(str)); 366 jsstr_release(str); 367 if(SUCCEEDED(hres)) 368 hres = create_builtin_constructor(ctx, constr_val[i], names[i], NULL, 369 PROPF_CONSTR|1, err, constr_addr[i]); 370 371 jsdisp_release(err); 372 if(FAILED(hres)) 373 return hres; 374 } 375 376 return S_OK; 377 } 378 379 static HRESULT throw_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str, jsdisp_t *constr) 380 { 381 WCHAR buf[1024], *pos = NULL; 382 jsdisp_t *err; 383 jsstr_t *msg; 384 HRESULT hres; 385 386 if(!is_jscript_error(error)) 387 return error; 388 389 buf[0] = '\0'; 390 LoadStringW(jscript_hinstance, HRESULT_CODE(error), buf, ARRAY_SIZE(buf)); 391 392 if(str) pos = wcschr(buf, '|'); 393 if(pos) { 394 int len = lstrlenW(str); 395 memmove(pos+len, pos+1, (lstrlenW(pos+1)+1)*sizeof(WCHAR)); 396 memcpy(pos, str, len*sizeof(WCHAR)); 397 } 398 399 WARN("%s\n", debugstr_w(buf)); 400 401 msg = jsstr_alloc(buf); 402 if(!msg) 403 return E_OUTOFMEMORY; 404 405 hres = create_error(ctx, constr, error, msg, &err); 406 jsstr_release(msg); 407 if(FAILED(hres)) 408 return hres; 409 410 jsval_release(ctx->ei.val); 411 ctx->ei.val = jsval_obj(err); 412 return error; 413 } 414 415 HRESULT throw_generic_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 416 { 417 return throw_error(ctx, error, str, ctx->error_constr); 418 } 419 420 HRESULT throw_range_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 421 { 422 return throw_error(ctx, error, str, ctx->range_error_constr); 423 } 424 425 HRESULT throw_reference_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 426 { 427 return throw_error(ctx, error, str, ctx->reference_error_constr); 428 } 429 430 HRESULT throw_regexp_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 431 { 432 return throw_error(ctx, error, str, ctx->regexp_error_constr); 433 } 434 435 HRESULT throw_syntax_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 436 { 437 return throw_error(ctx, error, str, ctx->syntax_error_constr); 438 } 439 440 HRESULT throw_type_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 441 { 442 return throw_error(ctx, error, str, ctx->type_error_constr); 443 } 444 445 HRESULT throw_uri_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) 446 { 447 return throw_error(ctx, error, str, ctx->uri_error_constr); 448 } 449