[JSCRIPT] Sync with Wine Staging 1.9.4. CORE-10912
[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 JSONW[] = {'J','S','O','N',0};
61 static const WCHAR encodeURIW[] = {'e','n','c','o','d','e','U','R','I',0};
62 static const WCHAR decodeURIW[] = {'d','e','c','o','d','e','U','R','I',0};
63 static const WCHAR encodeURIComponentW[] = {'e','n','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
64 static const WCHAR decodeURIComponentW[] = {'d','e','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
65
66 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
67
68 static int uri_char_table[] = {
69 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */
70 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */
71 0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */
72 2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */
73 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */
74 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */
75 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */
76 2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */
77 };
78
79 /* 1 - reserved */
80 /* 2 - unescaped */
81
82 static inline BOOL is_uri_reserved(WCHAR c)
83 {
84 return c < 128 && uri_char_table[c] == 1;
85 }
86
87 static inline BOOL is_uri_unescaped(WCHAR c)
88 {
89 return c < 128 && uri_char_table[c] == 2;
90 }
91
92 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
93 static inline BOOL is_ecma_nonblank(const WCHAR c)
94 {
95 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
96 c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
97 }
98
99 static WCHAR int_to_char(int i)
100 {
101 if(i < 10)
102 return '0'+i;
103 return 'A'+i-10;
104 }
105
106 static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
107 jsval_t *r)
108 {
109 FIXME("\n");
110 return E_NOTIMPL;
111 }
112
113 static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
114 jsval_t *r)
115 {
116 jsstr_t *ret_str, *str;
117 const WCHAR *ptr, *buf;
118 DWORD len = 0;
119 WCHAR *ret;
120 HRESULT hres;
121
122 TRACE("\n");
123
124 if(!argc) {
125 if(r)
126 *r = jsval_string(jsstr_undefined());
127 return S_OK;
128 }
129
130 hres = to_flat_string(ctx, argv[0], &str, &buf);
131 if(FAILED(hres))
132 return hres;
133
134 for(ptr = buf; *ptr; ptr++) {
135 if(*ptr > 0xff)
136 len += 6;
137 else if(is_ecma_nonblank(*ptr))
138 len++;
139 else
140 len += 3;
141 }
142
143 ret = jsstr_alloc_buf(len, &ret_str);
144 if(!ret) {
145 jsstr_release(str);
146 return E_OUTOFMEMORY;
147 }
148
149 len = 0;
150 for(ptr = buf; *ptr; ptr++) {
151 if(*ptr > 0xff) {
152 ret[len++] = '%';
153 ret[len++] = 'u';
154 ret[len++] = int_to_char(*ptr >> 12);
155 ret[len++] = int_to_char((*ptr >> 8) & 0xf);
156 ret[len++] = int_to_char((*ptr >> 4) & 0xf);
157 ret[len++] = int_to_char(*ptr & 0xf);
158 }
159 else if(is_ecma_nonblank(*ptr))
160 ret[len++] = *ptr;
161 else {
162 ret[len++] = '%';
163 ret[len++] = int_to_char(*ptr >> 4);
164 ret[len++] = int_to_char(*ptr & 0xf);
165 }
166 }
167
168 jsstr_release(str);
169
170 if(r)
171 *r = jsval_string(ret_str);
172 else
173 jsstr_release(ret_str);
174 return S_OK;
175 }
176
177 /* ECMA-262 3rd Edition 15.1.2.1 */
178 static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
179 jsval_t *r)
180 {
181 bytecode_t *code;
182 const WCHAR *src;
183 HRESULT hres;
184
185 TRACE("\n");
186
187 if(!argc) {
188 if(r)
189 *r = jsval_undefined();
190 return S_OK;
191 }
192
193 if(!is_string(argv[0])) {
194 if(r)
195 return jsval_copy(argv[0], r);
196 return S_OK;
197 }
198
199 if(!ctx->exec_ctx) {
200 FIXME("No active exec_ctx\n");
201 return E_UNEXPECTED;
202 }
203
204 src = jsstr_flatten(get_string(argv[0]));
205 if(!src)
206 return E_OUTOFMEMORY;
207
208 TRACE("parsing %s\n", debugstr_jsval(argv[0]));
209 hres = compile_script(ctx, src, NULL, NULL, TRUE, FALSE, &code);
210 if(FAILED(hres)) {
211 WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres);
212 return throw_syntax_error(ctx, hres, NULL);
213 }
214
215 hres = exec_source(ctx->exec_ctx, code, &code->global_code, TRUE, r);
216 release_bytecode(code);
217 return hres;
218 }
219
220 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
221 jsval_t *r)
222 {
223 BOOL ret = TRUE;
224 double n;
225 HRESULT hres;
226
227 TRACE("\n");
228
229 if(argc) {
230 hres = to_number(ctx, argv[0], &n);
231 if(FAILED(hres))
232 return hres;
233
234 if(!isnan(n))
235 ret = FALSE;
236 }
237
238 if(r)
239 *r = jsval_bool(ret);
240 return S_OK;
241 }
242
243 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
244 jsval_t *r)
245 {
246 BOOL ret = FALSE;
247 HRESULT hres;
248
249 TRACE("\n");
250
251 if(argc) {
252 double n;
253
254 hres = to_number(ctx, argv[0], &n);
255 if(FAILED(hres))
256 return hres;
257
258 ret = is_finite(n);
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 if(ctx->version >= 2) {
1102 jsdisp_t *json;
1103
1104 hres = create_json(ctx, &json);
1105 if(FAILED(hres))
1106 return hres;
1107
1108 hres = jsdisp_propput_dontenum(ctx->global, JSONW, jsval_obj(json));
1109 jsdisp_release(json);
1110 if(FAILED(hres))
1111 return hres;
1112 }
1113
1114 hres = create_activex_constr(ctx, &constr);
1115 if(FAILED(hres))
1116 return hres;
1117
1118 hres = jsdisp_propput_dontenum(ctx->global, ActiveXObjectW, jsval_obj(constr));
1119 jsdisp_release(constr);
1120 if(FAILED(hres))
1121 return hres;
1122
1123 hres = jsdisp_propput_dontenum(ctx->global, undefinedW, jsval_undefined());
1124 if(FAILED(hres))
1125 return hres;
1126
1127 hres = jsdisp_propput_dontenum(ctx->global, NaNW, jsval_number(NAN));
1128 if(FAILED(hres))
1129 return hres;
1130
1131 hres = jsdisp_propput_dontenum(ctx->global, InfinityW, jsval_number(INFINITY));
1132 return hres;
1133 }