xref: /reactos/dll/win32/jscript/error.c (revision 8c2e9189)
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_propput_dontenum(err, numberW, jsval_number((INT)number));
197     if(FAILED(hres)) {
198         jsdisp_release(err);
199         return hres;
200     }
201 
202     hres = jsdisp_propput_name(err, messageW, jsval_string(msg));
203     if(SUCCEEDED(hres))
204         hres = jsdisp_propput_dontenum(err, descriptionW, jsval_string(msg));
205     if(FAILED(hres)) {
206         jsdisp_release(err);
207         return hres;
208     }
209 
210     *ret = err;
211     return S_OK;
212 }
213 
214 static HRESULT error_constr(script_ctx_t *ctx, WORD flags, unsigned argc, jsval_t *argv,
215         jsval_t *r, jsdisp_t *constr) {
216     jsdisp_t *err;
217     UINT num = 0;
218     jsstr_t *msg = NULL;
219     HRESULT hres;
220 
221     if(argc) {
222         double n;
223 
224         hres = to_number(ctx, argv[0], &n);
225         if(FAILED(hres)) /* FIXME: really? */
226             n = NAN;
227         if(isnan(n))
228             hres = to_string(ctx, argv[0], &msg);
229         if(FAILED(hres))
230             return hres;
231         num = n;
232     }
233 
234     if(!msg) {
235         if(argc > 1) {
236             hres = to_string(ctx, argv[1], &msg);
237             if(FAILED(hres))
238                 return hres;
239         }else {
240             msg = jsstr_empty();
241         }
242     }
243 
244     switch(flags) {
245     case INVOKE_FUNC:
246     case DISPATCH_CONSTRUCT:
247         hres = create_error(ctx, constr, num, msg, &err);
248         jsstr_release(msg);
249         if(FAILED(hres))
250             return hres;
251 
252         if(r)
253             *r = jsval_obj(err);
254         else
255             jsdisp_release(err);
256         return S_OK;
257 
258     default:
259         if(msg)
260             jsstr_release(msg);
261         FIXME("unimplemented flags %x\n", flags);
262         return E_NOTIMPL;
263     }
264 }
265 
266 static HRESULT ErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
267         unsigned argc, jsval_t *argv, jsval_t *r)
268 {
269     TRACE("\n");
270     return error_constr(ctx, flags, argc, argv, r, ctx->error_constr);
271 }
272 
273 static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
274         unsigned argc, jsval_t *argv, jsval_t *r)
275 {
276     TRACE("\n");
277     return error_constr(ctx, flags, argc, argv, r, ctx->eval_error_constr);
278 }
279 
280 static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
281         unsigned argc, jsval_t *argv, jsval_t *r)
282 {
283     TRACE("\n");
284     return error_constr(ctx, flags, argc, argv, r, ctx->range_error_constr);
285 }
286 
287 static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
288         unsigned argc, jsval_t *argv, jsval_t *r)
289 {
290     TRACE("\n");
291     return error_constr(ctx, flags, argc, argv, r, ctx->reference_error_constr);
292 }
293 
294 static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
295         unsigned argc, jsval_t *argv, jsval_t *r)
296 {
297     TRACE("\n");
298     return error_constr(ctx, flags, argc, argv, r, ctx->regexp_error_constr);
299 }
300 
301 static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
302         unsigned argc, jsval_t *argv, jsval_t *r)
303 {
304     TRACE("\n");
305     return error_constr(ctx, flags, argc, argv, r, ctx->syntax_error_constr);
306 }
307 
308 static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
309         unsigned argc, jsval_t *argv, jsval_t *r)
310 {
311     TRACE("\n");
312     return error_constr(ctx, flags, argc, argv, r, ctx->type_error_constr);
313 }
314 
315 static HRESULT URIErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
316         unsigned argc, jsval_t *argv, jsval_t *r)
317 {
318     TRACE("\n");
319     return error_constr(ctx, flags, argc, argv, r, ctx->uri_error_constr);
320 }
321 
322 HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype)
323 {
324     static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
325     static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
326     static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0};
327     static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0};
328     static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0};
329     static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0};
330     static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0};
331     static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
332     static const WCHAR *names[] = {ErrorW, EvalErrorW, RangeErrorW,
333         ReferenceErrorW, RegExpErrorW, SyntaxErrorW, TypeErrorW, URIErrorW};
334     jsdisp_t **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr,
335         &ctx->range_error_constr, &ctx->reference_error_constr, &ctx->regexp_error_constr,
336         &ctx->syntax_error_constr, &ctx->type_error_constr,
337         &ctx->uri_error_constr};
338     static builtin_invoke_t constr_val[] = {ErrorConstr_value, EvalErrorConstr_value,
339         RangeErrorConstr_value, ReferenceErrorConstr_value, RegExpErrorConstr_value,
340         SyntaxErrorConstr_value, TypeErrorConstr_value, URIErrorConstr_value};
341 
342     jsdisp_t *err;
343     unsigned int i;
344     jsstr_t *str;
345     HRESULT hres;
346 
347     for(i=0; i < sizeof(names)/sizeof(names[0]); i++) {
348         hres = alloc_error(ctx, i==0 ? object_prototype : NULL, NULL, &err);
349         if(FAILED(hres))
350             return hres;
351 
352         str = jsstr_alloc(names[i]);
353         if(!str) {
354             jsdisp_release(err);
355             return E_OUTOFMEMORY;
356         }
357 
358         hres = jsdisp_propput_dontenum(err, nameW, jsval_string(str));
359         jsstr_release(str);
360         if(SUCCEEDED(hres))
361             hres = create_builtin_constructor(ctx, constr_val[i], names[i], NULL,
362                     PROPF_CONSTR|1, err, constr_addr[i]);
363 
364         jsdisp_release(err);
365         if(FAILED(hres))
366             return hres;
367     }
368 
369     return S_OK;
370 }
371 
372 static HRESULT throw_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str, jsdisp_t *constr)
373 {
374     WCHAR buf[1024], *pos = NULL;
375     jsdisp_t *err;
376     jsstr_t *msg;
377     HRESULT hres;
378 
379     if(!is_jscript_error(error))
380         return error;
381 
382     buf[0] = '\0';
383     LoadStringW(jscript_hinstance, HRESULT_CODE(error),  buf, sizeof(buf)/sizeof(WCHAR));
384 
385     if(str) pos = strchrW(buf, '|');
386     if(pos) {
387         int len = strlenW(str);
388         memmove(pos+len, pos+1, (strlenW(pos+1)+1)*sizeof(WCHAR));
389         memcpy(pos, str, len*sizeof(WCHAR));
390     }
391 
392     WARN("%s\n", debugstr_w(buf));
393 
394     msg = jsstr_alloc(buf);
395     if(!msg)
396         return E_OUTOFMEMORY;
397 
398     hres = create_error(ctx, constr, error, msg, &err);
399     jsstr_release(msg);
400     if(FAILED(hres))
401         return hres;
402 
403     jsval_release(ctx->ei.val);
404     ctx->ei.val = jsval_obj(err);
405     return error;
406 }
407 
408 HRESULT throw_generic_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
409 {
410     return throw_error(ctx, error, str, ctx->error_constr);
411 }
412 
413 HRESULT throw_range_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
414 {
415     return throw_error(ctx, error, str, ctx->range_error_constr);
416 }
417 
418 HRESULT throw_reference_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
419 {
420     return throw_error(ctx, error, str, ctx->reference_error_constr);
421 }
422 
423 HRESULT throw_regexp_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
424 {
425     return throw_error(ctx, error, str, ctx->regexp_error_constr);
426 }
427 
428 HRESULT throw_syntax_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
429 {
430     return throw_error(ctx, error, str, ctx->syntax_error_constr);
431 }
432 
433 HRESULT throw_type_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
434 {
435     return throw_error(ctx, error, str, ctx->type_error_constr);
436 }
437 
438 HRESULT throw_uri_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str)
439 {
440     return throw_error(ctx, error, str, ctx->uri_error_constr);
441 }
442