f7caf1117e283314a5c8ba0327a9c1c964ead4f1
[reactos.git] / reactos / dll / win32 / jscript / global.c
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
22 static const WCHAR NaNW[] = {'N','a','N',0};
23 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0};
24 static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
25 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0};
26 static const WCHAR DateW[] = {'D','a','t','e',0};
27 static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
28 static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
29 static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0};
30 static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0};
31 static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0};
32 static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0};
33 static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
34 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
35 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
36 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
37 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
38 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
39 static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0};
40 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
41 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
42 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
43 static const WCHAR escapeW[] = {'e','s','c','a','p','e',0};
44 static const WCHAR evalW[] = {'e','v','a','l',0};
45 static const WCHAR isNaNW[] = {'i','s','N','a','N',0};
46 static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0};
47 static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0};
48 static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0};
49 static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0};
50 static const WCHAR _GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0};
51 static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0};
52 static const WCHAR ScriptEngineMajorVersionW[] =
53 {'S','c','r','i','p','t','E','n','g','i','n','e','M','a','j','o','r','V','e','r','s','i','o','n',0};
54 static const WCHAR ScriptEngineMinorVersionW[] =
55 {'S','c','r','i','p','t','E','n','g','i','n','e','M','i','n','o','r','V','e','r','s','i','o','n',0};
56 static const WCHAR ScriptEngineBuildVersionW[] =
57 {'S','c','r','i','p','t','E','n','g','i','n','e','B','u','i','l','d','V','e','r','s','i','o','n',0};
58 static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0};
59 static const WCHAR MathW[] = {'M','a','t','h',0};
60 static const WCHAR encodeURIW[] = {'e','n','c','o','d','e','U','R','I',0};
61 static const WCHAR decodeURIW[] = {'d','e','c','o','d','e','U','R','I',0};
62 static const WCHAR encodeURIComponentW[] = {'e','n','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
63 static const WCHAR decodeURIComponentW[] = {'d','e','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
64
65 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
66
67 static int uri_char_table[] = {
68 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */
69 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */
70 0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */
71 2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */
72 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */
73 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */
74 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */
75 2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */
76 };
77
78 /* 1 - reserved */
79 /* 2 - unescaped */
80
81 static inline BOOL is_uri_reserved(WCHAR c)
82 {
83 return c < 128 && uri_char_table[c] == 1;
84 }
85
86 static inline BOOL is_uri_unescaped(WCHAR c)
87 {
88 return c < 128 && uri_char_table[c] == 2;
89 }
90
91 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
92 static inline BOOL is_ecma_nonblank(const WCHAR c)
93 {
94 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
95 c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
96 }
97
98 static WCHAR int_to_char(int i)
99 {
100 if(i < 10)
101 return '0'+i;
102 return 'A'+i-10;
103 }
104
105 static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
106 jsval_t *r)
107 {
108 FIXME("\n");
109 return E_NOTIMPL;
110 }
111
112 static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
113 jsval_t *r)
114 {
115 jsstr_t *ret_str, *str;
116 const WCHAR *ptr, *buf;
117 DWORD len = 0;
118 WCHAR *ret;
119 HRESULT hres;
120
121 TRACE("\n");
122
123 if(!argc) {
124 if(r)
125 *r = jsval_string(jsstr_undefined());
126 return S_OK;
127 }
128
129 hres = to_flat_string(ctx, argv[0], &str, &buf);
130 if(FAILED(hres))
131 return hres;
132
133 for(ptr = buf; *ptr; ptr++) {
134 if(*ptr > 0xff)
135 len += 6;
136 else if(is_ecma_nonblank(*ptr))
137 len++;
138 else
139 len += 3;
140 }
141
142 ret = jsstr_alloc_buf(len, &ret_str);
143 if(!ret) {
144 jsstr_release(str);
145 return E_OUTOFMEMORY;
146 }
147
148 len = 0;
149 for(ptr = buf; *ptr; ptr++) {
150 if(*ptr > 0xff) {
151 ret[len++] = '%';
152 ret[len++] = 'u';
153 ret[len++] = int_to_char(*ptr >> 12);
154 ret[len++] = int_to_char((*ptr >> 8) & 0xf);
155 ret[len++] = int_to_char((*ptr >> 4) & 0xf);
156 ret[len++] = int_to_char(*ptr & 0xf);
157 }
158 else if(is_ecma_nonblank(*ptr))
159 ret[len++] = *ptr;
160 else {
161 ret[len++] = '%';
162 ret[len++] = int_to_char(*ptr >> 4);
163 ret[len++] = int_to_char(*ptr & 0xf);
164 }
165 }
166
167 jsstr_release(str);
168
169 if(r)
170 *r = jsval_string(ret_str);
171 else
172 jsstr_release(ret_str);
173 return S_OK;
174 }
175
176 /* ECMA-262 3rd Edition 15.1.2.1 */
177 static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
178 jsval_t *r)
179 {
180 bytecode_t *code;
181 const WCHAR *src;
182 HRESULT hres;
183
184 TRACE("\n");
185
186 if(!argc) {
187 if(r)
188 *r = jsval_undefined();
189 return S_OK;
190 }
191
192 if(!is_string(argv[0])) {
193 if(r)
194 return jsval_copy(argv[0], r);
195 return S_OK;
196 }
197
198 if(!ctx->exec_ctx) {
199 FIXME("No active exec_ctx\n");
200 return E_UNEXPECTED;
201 }
202
203 src = jsstr_flatten(get_string(argv[0]));
204 if(!src)
205 return E_OUTOFMEMORY;
206
207 TRACE("parsing %s\n", debugstr_jsval(argv[0]));
208 hres = compile_script(ctx, src, NULL, NULL, TRUE, FALSE, &code);
209 if(FAILED(hres)) {
210 WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres);
211 return throw_syntax_error(ctx, hres, NULL);
212 }
213
214 hres = exec_source(ctx->exec_ctx, code, &code->global_code, TRUE, r);
215 release_bytecode(code);
216 return hres;
217 }
218
219 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
220 jsval_t *r)
221 {
222 BOOL ret = TRUE;
223 double n;
224 HRESULT hres;
225
226 TRACE("\n");
227
228 if(argc) {
229 hres = to_number(ctx, argv[0], &n);
230 if(FAILED(hres))
231 return hres;
232
233 if(!isnan(n))
234 ret = FALSE;
235 }
236
237 if(r)
238 *r = jsval_bool(ret);
239 return S_OK;
240 }
241
242 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
243 jsval_t *r)
244 {
245 BOOL ret = FALSE;
246 HRESULT hres;
247
248 TRACE("\n");
249
250 if(argc) {
251 double n;
252
253 hres = to_number(ctx, argv[0], &n);
254 if(FAILED(hres))
255 return hres;
256
257 if(!isinf(n) && !isnan(n))
258 ret = TRUE;
259 }
260
261 if(r)
262 *r = jsval_bool(ret);
263 return S_OK;
264 }
265
266 static INT char_to_int(WCHAR c)
267 {
268 if('0' <= c && c <= '9')
269 return c - '0';
270 if('a' <= c && c <= 'z')
271 return c - 'a' + 10;
272 if('A' <= c && c <= 'Z')
273 return c - 'A' + 10;
274 return 100;
275 }
276
277 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
278 jsval_t *r)
279 {
280 BOOL neg = FALSE, empty = TRUE;
281 const WCHAR *ptr;
282 DOUBLE ret = 0.0;
283 INT radix=0, i;
284 jsstr_t *str;
285 HRESULT hres;
286
287 if(!argc) {
288 if(r)
289 *r = jsval_number(NAN);
290 return S_OK;
291 }
292
293 if(argc >= 2) {
294 hres = to_int32(ctx, argv[1], &radix);
295 if(FAILED(hres))
296 return hres;
297
298 if(radix && (radix < 2 || radix > 36)) {
299 WARN("radix %d out of range\n", radix);
300 if(r)
301 *r = jsval_number(NAN);
302 return S_OK;
303 }
304 }
305
306 hres = to_flat_string(ctx, argv[0], &str, &ptr);
307 if(FAILED(hres))
308 return hres;
309
310 while(isspaceW(*ptr))
311 ptr++;
312
313 switch(*ptr) {
314 case '+':
315 ptr++;
316 break;
317 case '-':
318 neg = TRUE;
319 ptr++;
320 break;
321 }
322
323 if(!radix) {
324 if(*ptr == '0') {
325 if(ptr[1] == 'x' || ptr[1] == 'X') {
326 radix = 16;
327 ptr += 2;
328 }else {
329 radix = 8;
330 ptr++;
331 empty = FALSE;
332 }
333 }else {
334 radix = 10;
335 }
336 }
337
338 i = char_to_int(*ptr++);
339 if(i < radix) {
340 do {
341 ret = ret*radix + i;
342 i = char_to_int(*ptr++);
343 }while(i < radix);
344 }else if(empty) {
345 ret = NAN;
346 }
347
348 jsstr_release(str);
349
350 if(neg)
351 ret = -ret;
352
353 if(r)
354 *r = jsval_number(ret);
355 return S_OK;
356 }
357
358 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
359 jsval_t *r)
360 {
361 LONGLONG d = 0, hlp;
362 jsstr_t *val_str;
363 int exp = 0;
364 const WCHAR *str;
365 BOOL ret_nan = TRUE, positive = TRUE;
366 HRESULT hres;
367
368 if(!argc) {
369 if(r)
370 *r = jsval_number(NAN);
371 return S_OK;
372 }
373
374 hres = to_flat_string(ctx, argv[0], &val_str, &str);
375 if(FAILED(hres))
376 return hres;
377
378 while(isspaceW(*str)) str++;
379
380 if(*str == '+')
381 str++;
382 else if(*str == '-') {
383 positive = FALSE;
384 str++;
385 }
386
387 if(isdigitW(*str))
388 ret_nan = FALSE;
389
390 while(isdigitW(*str)) {
391 hlp = d*10 + *(str++) - '0';
392 if(d>MAXLONGLONG/10 || hlp<0) {
393 exp++;
394 break;
395 }
396 else
397 d = hlp;
398 }
399 while(isdigitW(*str)) {
400 exp++;
401 str++;
402 }
403
404 if(*str == '.') str++;
405
406 if(isdigitW(*str))
407 ret_nan = FALSE;
408
409 while(isdigitW(*str)) {
410 hlp = d*10 + *(str++) - '0';
411 if(d>MAXLONGLONG/10 || hlp<0)
412 break;
413
414 d = hlp;
415 exp--;
416 }
417 while(isdigitW(*str))
418 str++;
419
420 if(*str && !ret_nan && (*str=='e' || *str=='E')) {
421 int sign = 1, e = 0;
422
423 str++;
424 if(*str == '+')
425 str++;
426 else if(*str == '-') {
427 sign = -1;
428 str++;
429 }
430
431 while(isdigitW(*str)) {
432 if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0)
433 e = INT_MAX;
434 }
435 e *= sign;
436
437 if(exp<0 && e<0 && exp+e>0) exp = INT_MIN;
438 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
439 else exp += e;
440 }
441
442 jsstr_release(val_str);
443
444 if(ret_nan) {
445 if(r)
446 *r = jsval_number(NAN);
447 return S_OK;
448 }
449
450 if(!positive)
451 d = -d;
452 if(r)
453 *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
454 return S_OK;
455 }
456
457 static inline int hex_to_int(const WCHAR wch) {
458 if(toupperW(wch)>='A' && toupperW(wch)<='F') return toupperW(wch)-'A'+10;
459 if(isdigitW(wch)) return wch-'0';
460 return -1;
461 }
462
463 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
464 jsval_t *r)
465 {
466 jsstr_t *ret_str, *str;
467 const WCHAR *ptr, *buf;
468 DWORD len = 0;
469 WCHAR *ret;
470 HRESULT hres;
471
472 TRACE("\n");
473
474 if(!argc) {
475 if(r)
476 *r = jsval_string(jsstr_undefined());
477 return S_OK;
478 }
479
480 hres = to_flat_string(ctx, argv[0], &str, &buf);
481 if(FAILED(hres))
482 return hres;
483
484 for(ptr = buf; *ptr; ptr++) {
485 if(*ptr == '%') {
486 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
487 ptr += 2;
488 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
489 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1)
490 ptr += 5;
491 }
492
493 len++;
494 }
495
496 ret = jsstr_alloc_buf(len, &ret_str);
497 if(!ret) {
498 jsstr_release(str);
499 return E_OUTOFMEMORY;
500 }
501
502 len = 0;
503 for(ptr = buf; *ptr; ptr++) {
504 if(*ptr == '%') {
505 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
506 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
507 ptr += 2;
508 }
509 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
510 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) {
511 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8)
512 + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5));
513 ptr += 5;
514 }
515 else
516 ret[len] = *ptr;
517 }
518 else
519 ret[len] = *ptr;
520
521 len++;
522 }
523
524 jsstr_release(str);
525
526 if(r)
527 *r = jsval_string(ret_str);
528 else
529 jsstr_release(ret_str);
530 return S_OK;
531 }
532
533 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
534 jsval_t *r)
535 {
536 FIXME("\n");
537 return E_NOTIMPL;
538 }
539
540 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
541 jsval_t *r)
542 {
543 static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0};
544
545 TRACE("\n");
546
547 if(r) {
548 jsstr_t *ret;
549
550 ret = jsstr_alloc(JScriptW);
551 if(!ret)
552 return E_OUTOFMEMORY;
553
554 *r = jsval_string(ret);
555 }
556
557 return S_OK;
558 }
559
560 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
561 jsval_t *r)
562 {
563 TRACE("\n");
564
565 if(r)
566 *r = jsval_number(JSCRIPT_MAJOR_VERSION);
567 return S_OK;
568 }
569
570 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
571 jsval_t *r)
572 {
573 TRACE("\n");
574
575 if(r)
576 *r = jsval_number(JSCRIPT_MINOR_VERSION);
577 return S_OK;
578 }
579
580 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
581 jsval_t *r)
582 {
583 TRACE("\n");
584
585 if(r)
586 *r = jsval_number(JSCRIPT_BUILD_VERSION);
587 return S_OK;
588 }
589
590 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
591 jsval_t *r)
592 {
593 static int once = 0;
594 if (!once++)
595 FIXME(": stub\n");
596 return S_OK;
597 }
598
599 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
600 jsval_t *r)
601 {
602 const WCHAR *ptr, *uri;
603 jsstr_t *str, *ret;
604 DWORD len = 0, i;
605 char buf[4];
606 WCHAR *rptr;
607 HRESULT hres;
608
609 TRACE("\n");
610
611 if(!argc) {
612 if(r)
613 *r = jsval_string(jsstr_undefined());
614 return S_OK;
615 }
616
617 hres = to_flat_string(ctx, argv[0], &str, &uri);
618 if(FAILED(hres))
619 return hres;
620
621 for(ptr = uri; *ptr; ptr++) {
622 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
623 len++;
624 }else {
625 i = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL)*3;
626 if(!i) {
627 jsstr_release(str);
628 return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL);
629 }
630
631 len += i;
632 }
633 }
634
635 rptr = jsstr_alloc_buf(len, &ret);
636 if(!rptr) {
637 jsstr_release(str);
638 return E_OUTOFMEMORY;
639 }
640
641 for(ptr = uri; *ptr; ptr++) {
642 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
643 *rptr++ = *ptr;
644 }else {
645 len = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
646 for(i=0; i<len; i++) {
647 *rptr++ = '%';
648 *rptr++ = int_to_char((BYTE)buf[i] >> 4);
649 *rptr++ = int_to_char(buf[i] & 0x0f);
650 }
651 }
652 }
653
654 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
655 jsstr_release(str);
656
657 if(r)
658 *r = jsval_string(ret);
659 else
660 jsstr_release(ret);
661 return S_OK;
662 }
663
664 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
665 jsval_t *r)
666 {
667 const WCHAR *ptr, *uri;
668 jsstr_t *str, *ret_str;
669 unsigned len = 0;
670 int i, val, res;
671 WCHAR *ret;
672 char buf[4];
673 WCHAR out;
674 HRESULT hres;
675
676 TRACE("\n");
677
678 if(!argc) {
679 if(r)
680 *r = jsval_string(jsstr_undefined());
681 return S_OK;
682 }
683
684 hres = to_flat_string(ctx, argv[0], &str, &uri);
685 if(FAILED(hres))
686 return hres;
687
688 for(ptr = uri; *ptr; ptr++) {
689 if(*ptr != '%') {
690 len++;
691 }else {
692 res = 0;
693 for(i=0; i<4; i++) {
694 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
695 break;
696 val += hex_to_int(ptr[i*3+1])<<4;
697 buf[i] = val;
698
699 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, &out, 1);
700 if(res)
701 break;
702 }
703
704 if(!res) {
705 jsstr_release(str);
706 return throw_uri_error(ctx, JS_E_INVALID_URI_CODING, NULL);
707 }
708
709 ptr += i*3+2;
710 len++;
711 }
712 }
713
714 ret = jsstr_alloc_buf(len, &ret_str);
715 if(!ret) {
716 jsstr_release(str);
717 return E_OUTOFMEMORY;
718 }
719
720 for(ptr = uri; *ptr; ptr++) {
721 if(*ptr != '%') {
722 *ret++ = *ptr;
723 }else {
724 for(i=0; i<4; i++) {
725 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
726 break;
727 val += hex_to_int(ptr[i*3+1])<<4;
728 buf[i] = val;
729
730 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, ret, 1);
731 if(res)
732 break;
733 }
734
735 ptr += i*3+2;
736 ret++;
737 }
738 }
739
740 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret_str));
741 jsstr_release(str);
742
743 if(r)
744 *r = jsval_string(ret_str);
745 else
746 jsstr_release(ret_str);
747 return S_OK;
748 }
749
750 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
751 jsval_t *r)
752 {
753 jsstr_t *str, *ret_str;
754 char buf[4];
755 const WCHAR *ptr, *uri;
756 DWORD len = 0, size, i;
757 WCHAR *ret;
758 HRESULT hres;
759
760 TRACE("\n");
761
762 if(!argc) {
763 if(r)
764 *r = jsval_string(jsstr_undefined());
765 return S_OK;
766 }
767
768 hres = to_flat_string(ctx, argv[0], &str, &uri);
769 if(FAILED(hres))
770 return hres;
771
772 for(ptr = uri; *ptr; ptr++) {
773 if(is_uri_unescaped(*ptr))
774 len++;
775 else {
776 size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL);
777 if(!size) {
778 jsstr_release(str);
779 return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL);
780 }
781 len += size*3;
782 }
783 }
784
785 ret = jsstr_alloc_buf(len, &ret_str);
786 if(!ret) {
787 jsstr_release(str);
788 return E_OUTOFMEMORY;
789 }
790
791 for(ptr = uri; *ptr; ptr++) {
792 if(is_uri_unescaped(*ptr)) {
793 *ret++ = *ptr;
794 }else {
795 size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
796 for(i=0; i<size; i++) {
797 *ret++ = '%';
798 *ret++ = int_to_char((BYTE)buf[i] >> 4);
799 *ret++ = int_to_char(buf[i] & 0x0f);
800 }
801 }
802 }
803
804 jsstr_release(str);
805
806 if(r)
807 *r = jsval_string(ret_str);
808 else
809 jsstr_release(ret_str);
810 return S_OK;
811 }
812
813 /* ECMA-262 3rd Edition 15.1.3.2 */
814 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
815 jsval_t *r)
816 {
817 const WCHAR *ptr, *uri;
818 jsstr_t *str, *ret;
819 WCHAR *out_ptr;
820 DWORD len = 0;
821 HRESULT hres;
822
823 TRACE("\n");
824
825 if(!argc) {
826 if(r)
827 *r = jsval_string(jsstr_undefined());
828 return S_OK;
829 }
830
831 hres = to_flat_string(ctx, argv[0], &str, &uri);
832 if(FAILED(hres))
833 return hres;
834
835 ptr = uri;
836 while(*ptr) {
837 if(*ptr == '%') {
838 char octets[4];
839 unsigned char mask = 0x80;
840 int i, size, num_bytes = 0;
841 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
842 FIXME("Throw URIError: Invalid hex sequence\n");
843 jsstr_release(str);
844 return E_FAIL;
845 }
846 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
847 ptr += 3;
848 while(octets[0] & mask) {
849 mask = mask >> 1;
850 ++num_bytes;
851 }
852 if(num_bytes == 1 || num_bytes > 4) {
853 FIXME("Throw URIError: Invalid initial UTF character\n");
854 jsstr_release(str);
855 return E_FAIL;
856 }
857 for(i = 1; i < num_bytes; ++i) {
858 if(*ptr != '%'){
859 FIXME("Throw URIError: Incomplete UTF sequence\n");
860 jsstr_release(str);
861 return E_FAIL;
862 }
863 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
864 FIXME("Throw URIError: Invalid hex sequence\n");
865 jsstr_release(str);
866 return E_FAIL;
867 }
868 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
869 ptr += 3;
870 }
871 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
872 num_bytes ? num_bytes : 1, NULL, 0);
873 if(size == 0) {
874 FIXME("Throw URIError: Invalid UTF sequence\n");
875 jsstr_release(str);
876 return E_FAIL;
877 }
878 len += size;
879 }else {
880 ++ptr;
881 ++len;
882 }
883 }
884
885 out_ptr = jsstr_alloc_buf(len, &ret);
886 if(!ret) {
887 jsstr_release(str);
888 return E_OUTOFMEMORY;
889 }
890
891 ptr = uri;
892 while(*ptr) {
893 if(*ptr == '%') {
894 char octets[4];
895 unsigned char mask = 0x80;
896 int i, size, num_bytes = 0;
897 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
898 ptr += 3;
899 while(octets[0] & mask) {
900 mask = mask >> 1;
901 ++num_bytes;
902 }
903 for(i = 1; i < num_bytes; ++i) {
904 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
905 ptr += 3;
906 }
907 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
908 num_bytes ? num_bytes : 1, out_ptr, len);
909 len -= size;
910 out_ptr += size;
911 }else {
912 *out_ptr++ = *ptr++;
913 --len;
914 }
915 }
916
917 jsstr_release(str);
918
919 if(r)
920 *r = jsval_string(ret);
921 else
922 jsstr_release(ret);
923 return S_OK;
924 }
925
926 static const builtin_prop_t JSGlobal_props[] = {
927 {CollectGarbageW, JSGlobal_CollectGarbage, PROPF_METHOD},
928 {EnumeratorW, JSGlobal_Enumerator, PROPF_METHOD|7},
929 {_GetObjectW, JSGlobal_GetObject, PROPF_METHOD|2},
930 {ScriptEngineW, JSGlobal_ScriptEngine, PROPF_METHOD},
931 {ScriptEngineBuildVersionW, JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD},
932 {ScriptEngineMajorVersionW, JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD},
933 {ScriptEngineMinorVersionW, JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD},
934 {decodeURIW, JSGlobal_decodeURI, PROPF_METHOD|1},
935 {decodeURIComponentW, JSGlobal_decodeURIComponent, PROPF_METHOD|1},
936 {encodeURIW, JSGlobal_encodeURI, PROPF_METHOD|1},
937 {encodeURIComponentW, JSGlobal_encodeURIComponent, PROPF_METHOD|1},
938 {escapeW, JSGlobal_escape, PROPF_METHOD|1},
939 {evalW, JSGlobal_eval, PROPF_METHOD|1},
940 {isFiniteW, JSGlobal_isFinite, PROPF_METHOD|1},
941 {isNaNW, JSGlobal_isNaN, PROPF_METHOD|1},
942 {parseFloatW, JSGlobal_parseFloat, PROPF_METHOD|1},
943 {parseIntW, JSGlobal_parseInt, PROPF_METHOD|2},
944 {unescapeW, JSGlobal_unescape, PROPF_METHOD|1}
945 };
946
947 static const builtin_info_t JSGlobal_info = {
948 JSCLASS_GLOBAL,
949 {NULL, NULL, 0},
950 sizeof(JSGlobal_props)/sizeof(*JSGlobal_props),
951 JSGlobal_props,
952 NULL,
953 NULL
954 };
955
956 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
957 {
958 HRESULT hres;
959
960 hres = init_function_constr(ctx, object_prototype);
961 if(FAILED(hres))
962 return hres;
963
964 hres = jsdisp_propput_dontenum(ctx->global, FunctionW, jsval_obj(ctx->function_constr));
965 if(FAILED(hres))
966 return hres;
967
968 hres = create_object_constr(ctx, object_prototype, &ctx->object_constr);
969 if(FAILED(hres))
970 return hres;
971
972 hres = jsdisp_propput_dontenum(ctx->global, ObjectW, jsval_obj(ctx->object_constr));
973 if(FAILED(hres))
974 return hres;
975
976 hres = create_array_constr(ctx, object_prototype, &ctx->array_constr);
977 if(FAILED(hres))
978 return hres;
979
980 hres = jsdisp_propput_dontenum(ctx->global, ArrayW, jsval_obj(ctx->array_constr));
981 if(FAILED(hres))
982 return hres;
983
984 hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr);
985 if(FAILED(hres))
986 return hres;
987
988 hres = jsdisp_propput_dontenum(ctx->global, BooleanW, jsval_obj(ctx->bool_constr));
989 if(FAILED(hres))
990 return hres;
991
992 hres = create_date_constr(ctx, object_prototype, &ctx->date_constr);
993 if(FAILED(hres))
994 return hres;
995
996 hres = jsdisp_propput_dontenum(ctx->global, DateW, jsval_obj(ctx->date_constr));
997 if(FAILED(hres))
998 return hres;
999
1000 hres = init_error_constr(ctx, object_prototype);
1001 if(FAILED(hres))
1002 return hres;
1003
1004 hres = jsdisp_propput_dontenum(ctx->global, ErrorW, jsval_obj(ctx->error_constr));
1005 if(FAILED(hres))
1006 return hres;
1007
1008 hres = jsdisp_propput_dontenum(ctx->global, EvalErrorW, jsval_obj(ctx->eval_error_constr));
1009 if(FAILED(hres))
1010 return hres;
1011
1012 hres = jsdisp_propput_dontenum(ctx->global, RangeErrorW, jsval_obj(ctx->range_error_constr));
1013 if(FAILED(hres))
1014 return hres;
1015
1016 hres = jsdisp_propput_dontenum(ctx->global, ReferenceErrorW, jsval_obj(ctx->reference_error_constr));
1017 if(FAILED(hres))
1018 return hres;
1019
1020 hres = jsdisp_propput_dontenum(ctx->global, RegExpErrorW, jsval_obj(ctx->regexp_error_constr));
1021 if(FAILED(hres))
1022 return hres;
1023
1024 hres = jsdisp_propput_dontenum(ctx->global, SyntaxErrorW, jsval_obj(ctx->syntax_error_constr));
1025 if(FAILED(hres))
1026 return hres;
1027
1028 hres = jsdisp_propput_dontenum(ctx->global, TypeErrorW, jsval_obj(ctx->type_error_constr));
1029 if(FAILED(hres))
1030 return hres;
1031
1032 hres = jsdisp_propput_dontenum(ctx->global, URIErrorW, jsval_obj(ctx->uri_error_constr));
1033 if(FAILED(hres))
1034 return hres;
1035
1036 hres = create_number_constr(ctx, object_prototype, &ctx->number_constr);
1037 if(FAILED(hres))
1038 return hres;
1039
1040 hres = jsdisp_propput_dontenum(ctx->global, NumberW, jsval_obj(ctx->number_constr));
1041 if(FAILED(hres))
1042 return hres;
1043
1044 hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr);
1045 if(FAILED(hres))
1046 return hres;
1047
1048 hres = jsdisp_propput_dontenum(ctx->global, RegExpW, jsval_obj(ctx->regexp_constr));
1049 if(FAILED(hres))
1050 return hres;
1051
1052 hres = create_string_constr(ctx, object_prototype, &ctx->string_constr);
1053 if(FAILED(hres))
1054 return hres;
1055
1056 hres = jsdisp_propput_dontenum(ctx->global, StringW, jsval_obj(ctx->string_constr));
1057 if(FAILED(hres))
1058 return hres;
1059
1060 hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr);
1061 if(FAILED(hres))
1062 return hres;
1063
1064 hres = jsdisp_propput_dontenum(ctx->global, VBArrayW, jsval_obj(ctx->vbarray_constr));
1065 if(FAILED(hres))
1066 return hres;
1067
1068 return S_OK;
1069 }
1070
1071 HRESULT init_global(script_ctx_t *ctx)
1072 {
1073 jsdisp_t *math, *object_prototype, *constr;
1074 HRESULT hres;
1075
1076 if(ctx->global)
1077 return S_OK;
1078
1079 hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
1080 if(FAILED(hres))
1081 return hres;
1082
1083 hres = create_object_prototype(ctx, &object_prototype);
1084 if(FAILED(hres))
1085 return hres;
1086
1087 hres = init_constructors(ctx, object_prototype);
1088 jsdisp_release(object_prototype);
1089 if(FAILED(hres))
1090 return hres;
1091
1092 hres = create_math(ctx, &math);
1093 if(FAILED(hres))
1094 return hres;
1095
1096 hres = jsdisp_propput_dontenum(ctx->global, MathW, jsval_obj(math));
1097 jsdisp_release(math);
1098 if(FAILED(hres))
1099 return hres;
1100
1101 hres = create_activex_constr(ctx, &constr);
1102 if(FAILED(hres))
1103 return hres;
1104
1105 hres = jsdisp_propput_dontenum(ctx->global, ActiveXObjectW, jsval_obj(constr));
1106 jsdisp_release(constr);
1107 if(FAILED(hres))
1108 return hres;
1109
1110 hres = jsdisp_propput_dontenum(ctx->global, undefinedW, jsval_undefined());
1111 if(FAILED(hres))
1112 return hres;
1113
1114 hres = jsdisp_propput_dontenum(ctx->global, NaNW, jsval_number(NAN));
1115 if(FAILED(hres))
1116 return hres;
1117
1118 hres = jsdisp_propput_dontenum(ctx->global, InfinityW, jsval_number(INFINITY));
1119 return hres;
1120 }