xref: /reactos/dll/win32/jscript/error.c (revision 3e2d6582)
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 */
Error_toString(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
Error_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
alloc_error(script_ctx_t * ctx,jsdisp_t * prototype,jsdisp_t * constr,jsdisp_t ** ret)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 
create_error(script_ctx_t * ctx,jsdisp_t * constr,UINT number,jsstr_t * msg,jsdisp_t ** ret)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 
error_constr(script_ctx_t * ctx,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r,jsdisp_t * constr)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 
ErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
EvalErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
RangeErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
ReferenceErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
RegExpErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
SyntaxErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
TypeErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
URIErrorConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)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 
init_error_constr(script_ctx_t * ctx,jsdisp_t * object_prototype)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 
throw_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str,jsdisp_t * constr)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 
throw_generic_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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 
throw_range_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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 
throw_reference_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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 
throw_regexp_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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 
throw_syntax_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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 
throw_type_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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 
throw_uri_error(script_ctx_t * ctx,HRESULT error,const WCHAR * str)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