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