mf/session: Implement support for sinks that provide sample allocators.
[wine.git] / dlls / jscript / global.c
blob64f7bbda959fc979dfbfbe53c8db433f0dfe3505
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
20 #include <math.h>
21 #include <limits.h>
23 #include "jscript.h"
24 #include "engine.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
30 static const WCHAR NaNW[] = {'N','a','N',0};
31 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0};
32 static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
33 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0};
34 static const WCHAR DateW[] = {'D','a','t','e',0};
35 static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
36 static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
37 static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0};
38 static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0};
39 static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0};
40 static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0};
41 static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
42 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
43 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
44 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
45 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
46 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
47 static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0};
48 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
49 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
50 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
51 static const WCHAR MathW[] = {'M','a','t','h',0};
52 static const WCHAR JSONW[] = {'J','S','O','N',0};
54 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
56 static int uri_char_table[] = {
57 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */
58 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */
59 0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */
60 2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */
61 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */
62 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */
63 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */
64 2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */
67 /* 1 - reserved */
68 /* 2 - unescaped */
70 static inline BOOL is_uri_reserved(WCHAR c)
72 return c < 128 && uri_char_table[c] == 1;
75 static inline BOOL is_uri_unescaped(WCHAR c)
77 return c < 128 && uri_char_table[c] == 2;
80 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
81 static inline BOOL is_ecma_nonblank(const WCHAR c)
83 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
84 c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
87 static WCHAR int_to_char(int i)
89 if(i < 10)
90 return '0'+i;
91 return 'A'+i-10;
94 static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
95 jsval_t *r)
97 jsstr_t *ret_str, *str;
98 const WCHAR *ptr, *buf;
99 DWORD len = 0;
100 WCHAR *ret;
101 HRESULT hres;
103 TRACE("\n");
105 if(!argc) {
106 if(r)
107 *r = jsval_string(jsstr_undefined());
108 return S_OK;
111 hres = to_flat_string(ctx, argv[0], &str, &buf);
112 if(FAILED(hres))
113 return hres;
115 for(ptr = buf; *ptr; ptr++) {
116 if(*ptr > 0xff)
117 len += 6;
118 else if(is_ecma_nonblank(*ptr))
119 len++;
120 else
121 len += 3;
124 ret_str = jsstr_alloc_buf(len, &ret);
125 if(!ret_str) {
126 jsstr_release(str);
127 return E_OUTOFMEMORY;
130 len = 0;
131 for(ptr = buf; *ptr; ptr++) {
132 if(*ptr > 0xff) {
133 ret[len++] = '%';
134 ret[len++] = 'u';
135 ret[len++] = int_to_char(*ptr >> 12);
136 ret[len++] = int_to_char((*ptr >> 8) & 0xf);
137 ret[len++] = int_to_char((*ptr >> 4) & 0xf);
138 ret[len++] = int_to_char(*ptr & 0xf);
140 else if(is_ecma_nonblank(*ptr))
141 ret[len++] = *ptr;
142 else {
143 ret[len++] = '%';
144 ret[len++] = int_to_char(*ptr >> 4);
145 ret[len++] = int_to_char(*ptr & 0xf);
149 jsstr_release(str);
151 if(r)
152 *r = jsval_string(ret_str);
153 else
154 jsstr_release(ret_str);
155 return S_OK;
158 /* ECMA-262 3rd Edition 15.1.2.1 */
159 HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
160 jsval_t *r)
162 call_frame_t *frame = ctx->call_ctx;
163 DWORD exec_flags = EXEC_EVAL;
164 bytecode_t *code;
165 const WCHAR *src;
166 HRESULT hres;
168 TRACE("\n");
170 if(!argc) {
171 if(r)
172 *r = jsval_undefined();
173 return S_OK;
176 if(!is_string(argv[0])) {
177 if(r)
178 return jsval_copy(argv[0], r);
179 return S_OK;
182 src = jsstr_flatten(get_string(argv[0]));
183 if(!src)
184 return E_OUTOFMEMORY;
186 TRACE("parsing %s\n", debugstr_jsval(argv[0]));
187 hres = compile_script(ctx, src, 0, 0, NULL, NULL, TRUE, FALSE, frame ? frame->bytecode->named_item : NULL, &code);
188 if(FAILED(hres)) {
189 WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres);
190 return hres;
193 if(!frame || (frame->flags & EXEC_GLOBAL))
194 exec_flags |= EXEC_GLOBAL;
195 if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
196 exec_flags |= EXEC_RETURN_TO_INTERP;
197 hres = exec_source(ctx, exec_flags, code, &code->global_code, frame ? frame->scope : NULL,
198 frame ? frame->this_obj : NULL, NULL, 0, NULL, r);
199 release_bytecode(code);
200 return hres;
203 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
204 jsval_t *r)
206 BOOL ret = TRUE;
207 double n;
208 HRESULT hres;
210 TRACE("\n");
212 if(argc) {
213 hres = to_number(ctx, argv[0], &n);
214 if(FAILED(hres))
215 return hres;
217 if(!isnan(n))
218 ret = FALSE;
221 if(r)
222 *r = jsval_bool(ret);
223 return S_OK;
226 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
227 jsval_t *r)
229 BOOL ret = FALSE;
230 HRESULT hres;
232 TRACE("\n");
234 if(argc) {
235 double n;
237 hres = to_number(ctx, argv[0], &n);
238 if(FAILED(hres))
239 return hres;
241 ret = is_finite(n);
244 if(r)
245 *r = jsval_bool(ret);
246 return S_OK;
249 static INT char_to_int(WCHAR c)
251 if('0' <= c && c <= '9')
252 return c - '0';
253 if('a' <= c && c <= 'z')
254 return c - 'a' + 10;
255 if('A' <= c && c <= 'Z')
256 return c - 'A' + 10;
257 return 100;
260 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
261 jsval_t *r)
263 BOOL neg = FALSE, empty = TRUE;
264 const WCHAR *ptr;
265 DOUBLE ret = 0.0;
266 INT radix=0, i;
267 jsstr_t *str;
268 HRESULT hres;
270 if(!argc) {
271 if(r)
272 *r = jsval_number(NAN);
273 return S_OK;
276 if(argc >= 2) {
277 hres = to_int32(ctx, argv[1], &radix);
278 if(FAILED(hres))
279 return hres;
281 if(radix && (radix < 2 || radix > 36)) {
282 WARN("radix %d out of range\n", radix);
283 if(r)
284 *r = jsval_number(NAN);
285 return S_OK;
289 hres = to_flat_string(ctx, argv[0], &str, &ptr);
290 if(FAILED(hres))
291 return hres;
293 while(iswspace(*ptr))
294 ptr++;
296 switch(*ptr) {
297 case '+':
298 ptr++;
299 break;
300 case '-':
301 neg = TRUE;
302 ptr++;
303 break;
306 if(!radix) {
307 if(*ptr == '0') {
308 if(ptr[1] == 'x' || ptr[1] == 'X') {
309 radix = 16;
310 ptr += 2;
311 }else {
312 radix = 8;
313 ptr++;
314 empty = FALSE;
316 }else {
317 radix = 10;
319 }else if(radix == 16 && *ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
320 ptr += 2;
323 i = char_to_int(*ptr++);
324 if(i < radix) {
325 do {
326 ret = ret*radix + i;
327 i = char_to_int(*ptr++);
328 }while(i < radix);
329 }else if(empty) {
330 ret = NAN;
333 jsstr_release(str);
335 if(neg)
336 ret = -ret;
338 if(r)
339 *r = jsval_number(ret);
340 return S_OK;
343 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
344 jsval_t *r)
346 LONGLONG d = 0, hlp;
347 jsstr_t *val_str;
348 int exp = 0;
349 const WCHAR *str;
350 BOOL ret_nan = TRUE, positive = TRUE;
351 HRESULT hres;
353 if(!argc) {
354 if(r)
355 *r = jsval_number(NAN);
356 return S_OK;
359 TRACE("%s\n", debugstr_jsval(argv[0]));
361 hres = to_flat_string(ctx, argv[0], &val_str, &str);
362 if(FAILED(hres))
363 return hres;
365 while(iswspace(*str)) str++;
367 if(*str == '+')
368 str++;
369 else if(*str == '-') {
370 positive = FALSE;
371 str++;
374 if(is_digit(*str))
375 ret_nan = FALSE;
377 while(is_digit(*str)) {
378 hlp = d*10 + *(str++) - '0';
379 if(d>MAXLONGLONG/10 || hlp<0) {
380 exp++;
381 break;
383 else
384 d = hlp;
386 while(is_digit(*str)) {
387 exp++;
388 str++;
391 if(*str == '.') str++;
393 if(is_digit(*str))
394 ret_nan = FALSE;
396 while(is_digit(*str)) {
397 hlp = d*10 + *(str++) - '0';
398 if(d>MAXLONGLONG/10 || hlp<0)
399 break;
401 d = hlp;
402 exp--;
404 while(is_digit(*str))
405 str++;
407 if(*str && !ret_nan && (*str=='e' || *str=='E')) {
408 int sign = 1, e = 0;
410 str++;
411 if(*str == '+')
412 str++;
413 else if(*str == '-') {
414 sign = -1;
415 str++;
418 while(is_digit(*str)) {
419 if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0)
420 e = INT_MAX;
422 e *= sign;
424 if(exp<0 && e<0 && exp+e>0) exp = INT_MIN;
425 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
426 else exp += e;
429 jsstr_release(val_str);
431 if(ret_nan) {
432 if(r)
433 *r = jsval_number(NAN);
434 return S_OK;
437 if(!positive)
438 d = -d;
439 if(r)
440 *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
441 return S_OK;
444 static inline int hex_to_int(const WCHAR wch) {
445 if(towupper(wch)>='A' && towupper(wch)<='F') return towupper(wch)-'A'+10;
446 if(is_digit(wch)) return wch-'0';
447 return -1;
450 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
451 jsval_t *r)
453 jsstr_t *ret_str, *str;
454 const WCHAR *ptr, *buf;
455 DWORD len = 0;
456 WCHAR *ret;
457 HRESULT hres;
459 TRACE("\n");
461 if(!argc) {
462 if(r)
463 *r = jsval_string(jsstr_undefined());
464 return S_OK;
467 hres = to_flat_string(ctx, argv[0], &str, &buf);
468 if(FAILED(hres))
469 return hres;
471 for(ptr = buf; *ptr; ptr++) {
472 if(*ptr == '%') {
473 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
474 ptr += 2;
475 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
476 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1)
477 ptr += 5;
480 len++;
483 ret_str = jsstr_alloc_buf(len, &ret);
484 if(!ret_str) {
485 jsstr_release(str);
486 return E_OUTOFMEMORY;
489 len = 0;
490 for(ptr = buf; *ptr; ptr++) {
491 if(*ptr == '%') {
492 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
493 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
494 ptr += 2;
496 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
497 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) {
498 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8)
499 + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5));
500 ptr += 5;
502 else
503 ret[len] = *ptr;
505 else
506 ret[len] = *ptr;
508 len++;
511 jsstr_release(str);
513 if(r)
514 *r = jsval_string(ret_str);
515 else
516 jsstr_release(ret_str);
517 return S_OK;
520 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
521 jsval_t *r)
523 FIXME("\n");
524 return E_NOTIMPL;
527 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
528 jsval_t *r)
530 static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0};
532 TRACE("\n");
534 if(r) {
535 jsstr_t *ret;
537 ret = jsstr_alloc(JScriptW);
538 if(!ret)
539 return E_OUTOFMEMORY;
541 *r = jsval_string(ret);
544 return S_OK;
547 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
548 jsval_t *r)
550 TRACE("\n");
552 if(r)
553 *r = jsval_number(JSCRIPT_MAJOR_VERSION);
554 return S_OK;
557 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
558 jsval_t *r)
560 TRACE("\n");
562 if(r)
563 *r = jsval_number(JSCRIPT_MINOR_VERSION);
564 return S_OK;
567 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
568 jsval_t *r)
570 TRACE("\n");
572 if(r)
573 *r = jsval_number(JSCRIPT_BUILD_VERSION);
574 return S_OK;
577 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
578 jsval_t *r)
580 static int once = 0;
581 if (!once++)
582 FIXME(": stub\n");
583 return S_OK;
586 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
587 jsval_t *r)
589 const WCHAR *ptr, *uri;
590 jsstr_t *str, *ret;
591 DWORD len = 0, i;
592 char buf[4];
593 WCHAR *rptr;
594 HRESULT hres;
596 TRACE("\n");
598 if(!argc) {
599 if(r)
600 *r = jsval_string(jsstr_undefined());
601 return S_OK;
604 hres = to_flat_string(ctx, argv[0], &str, &uri);
605 if(FAILED(hres))
606 return hres;
608 for(ptr = uri; *ptr; ptr++) {
609 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
610 len++;
611 }else {
612 i = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL)*3;
613 if(!i) {
614 jsstr_release(str);
615 return JS_E_INVALID_URI_CHAR;
618 len += i;
622 ret = jsstr_alloc_buf(len, &rptr);
623 if(!ret) {
624 jsstr_release(str);
625 return E_OUTOFMEMORY;
628 for(ptr = uri; *ptr; ptr++) {
629 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
630 *rptr++ = *ptr;
631 }else {
632 len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL);
633 for(i=0; i<len; i++) {
634 *rptr++ = '%';
635 *rptr++ = int_to_char((BYTE)buf[i] >> 4);
636 *rptr++ = int_to_char(buf[i] & 0x0f);
641 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
642 jsstr_release(str);
644 if(r)
645 *r = jsval_string(ret);
646 else
647 jsstr_release(ret);
648 return S_OK;
651 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
652 jsval_t *r)
654 const WCHAR *ptr, *uri;
655 jsstr_t *str, *ret_str;
656 unsigned len = 0;
657 int i, val, res;
658 WCHAR *ret;
659 char buf[4];
660 WCHAR out;
661 HRESULT hres;
663 TRACE("\n");
665 if(!argc) {
666 if(r)
667 *r = jsval_string(jsstr_undefined());
668 return S_OK;
671 hres = to_flat_string(ctx, argv[0], &str, &uri);
672 if(FAILED(hres))
673 return hres;
675 for(ptr = uri; *ptr; ptr++) {
676 if(*ptr != '%') {
677 len++;
678 }else {
679 res = 0;
680 for(i=0; i<4; i++) {
681 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
682 break;
683 val += hex_to_int(ptr[i*3+1])<<4;
684 buf[i] = val;
686 res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, &out, 1);
687 if(res)
688 break;
691 if(!res) {
692 jsstr_release(str);
693 return JS_E_INVALID_URI_CODING;
696 ptr += i*3+2;
697 len++;
701 ret_str = jsstr_alloc_buf(len, &ret);
702 if(!ret_str) {
703 jsstr_release(str);
704 return E_OUTOFMEMORY;
707 for(ptr = uri; *ptr; ptr++) {
708 if(*ptr != '%') {
709 *ret++ = *ptr;
710 }else {
711 for(i=0; i<4; i++) {
712 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
713 break;
714 val += hex_to_int(ptr[i*3+1])<<4;
715 buf[i] = val;
717 res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, ret, 1);
718 if(res)
719 break;
722 ptr += i*3+2;
723 ret++;
727 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret_str));
728 jsstr_release(str);
730 if(r)
731 *r = jsval_string(ret_str);
732 else
733 jsstr_release(ret_str);
734 return S_OK;
737 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
738 jsval_t *r)
740 jsstr_t *str, *ret_str;
741 char buf[4];
742 const WCHAR *ptr, *uri;
743 DWORD len = 0, size, i;
744 WCHAR *ret;
745 HRESULT hres;
747 TRACE("\n");
749 if(!argc) {
750 if(r)
751 *r = jsval_string(jsstr_undefined());
752 return S_OK;
755 hres = to_flat_string(ctx, argv[0], &str, &uri);
756 if(FAILED(hres))
757 return hres;
759 for(ptr = uri; *ptr; ptr++) {
760 if(is_uri_unescaped(*ptr))
761 len++;
762 else {
763 size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL);
764 if(!size) {
765 jsstr_release(str);
766 return JS_E_INVALID_URI_CHAR;
768 len += size*3;
772 ret_str = jsstr_alloc_buf(len, &ret);
773 if(!ret_str) {
774 jsstr_release(str);
775 return E_OUTOFMEMORY;
778 for(ptr = uri; *ptr; ptr++) {
779 if(is_uri_unescaped(*ptr)) {
780 *ret++ = *ptr;
781 }else {
782 size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL);
783 for(i=0; i<size; i++) {
784 *ret++ = '%';
785 *ret++ = int_to_char((BYTE)buf[i] >> 4);
786 *ret++ = int_to_char(buf[i] & 0x0f);
791 jsstr_release(str);
793 if(r)
794 *r = jsval_string(ret_str);
795 else
796 jsstr_release(ret_str);
797 return S_OK;
800 /* ECMA-262 3rd Edition 15.1.3.2 */
801 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
802 jsval_t *r)
804 const WCHAR *ptr, *uri;
805 jsstr_t *str, *ret;
806 WCHAR *out_ptr;
807 DWORD len = 0;
808 HRESULT hres;
810 TRACE("\n");
812 if(!argc) {
813 if(r)
814 *r = jsval_string(jsstr_undefined());
815 return S_OK;
818 hres = to_flat_string(ctx, argv[0], &str, &uri);
819 if(FAILED(hres))
820 return hres;
822 ptr = uri;
823 while(*ptr) {
824 if(*ptr == '%') {
825 char octets[4];
826 unsigned char mask = 0x80;
827 int i, size, num_bytes = 0;
828 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
829 FIXME("Throw URIError: Invalid hex sequence\n");
830 jsstr_release(str);
831 return E_FAIL;
833 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
834 ptr += 3;
835 while(octets[0] & mask) {
836 mask = mask >> 1;
837 ++num_bytes;
839 if(num_bytes == 1 || num_bytes > 4) {
840 FIXME("Throw URIError: Invalid initial UTF character\n");
841 jsstr_release(str);
842 return E_FAIL;
844 for(i = 1; i < num_bytes; ++i) {
845 if(*ptr != '%'){
846 FIXME("Throw URIError: Incomplete UTF sequence\n");
847 jsstr_release(str);
848 return E_FAIL;
850 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
851 FIXME("Throw URIError: Invalid hex sequence\n");
852 jsstr_release(str);
853 return E_FAIL;
855 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
856 ptr += 3;
858 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
859 num_bytes ? num_bytes : 1, NULL, 0);
860 if(size == 0) {
861 FIXME("Throw URIError: Invalid UTF sequence\n");
862 jsstr_release(str);
863 return E_FAIL;
865 len += size;
866 }else {
867 ++ptr;
868 ++len;
872 ret = jsstr_alloc_buf(len, &out_ptr);
873 if(!ret) {
874 jsstr_release(str);
875 return E_OUTOFMEMORY;
878 ptr = uri;
879 while(*ptr) {
880 if(*ptr == '%') {
881 char octets[4];
882 unsigned char mask = 0x80;
883 int i, size, num_bytes = 0;
884 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
885 ptr += 3;
886 while(octets[0] & mask) {
887 mask = mask >> 1;
888 ++num_bytes;
890 for(i = 1; i < num_bytes; ++i) {
891 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
892 ptr += 3;
894 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
895 num_bytes ? num_bytes : 1, out_ptr, len);
896 len -= size;
897 out_ptr += size;
898 }else {
899 *out_ptr++ = *ptr++;
900 --len;
904 jsstr_release(str);
906 if(r)
907 *r = jsval_string(ret);
908 else
909 jsstr_release(ret);
910 return S_OK;
913 static const builtin_prop_t JSGlobal_props[] = {
914 {L"CollectGarbage", JSGlobal_CollectGarbage, PROPF_METHOD},
915 {L"GetObject", JSGlobal_GetObject, PROPF_METHOD|2},
916 {L"ScriptEngine", JSGlobal_ScriptEngine, PROPF_METHOD},
917 {L"ScriptEngineBuildVersion", JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD},
918 {L"ScriptEngineMajorVersion", JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD},
919 {L"ScriptEngineMinorVersion", JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD},
920 {L"decodeURI", JSGlobal_decodeURI, PROPF_METHOD|1},
921 {L"decodeURIComponent", JSGlobal_decodeURIComponent, PROPF_METHOD|1},
922 {L"encodeURI", JSGlobal_encodeURI, PROPF_METHOD|1},
923 {L"encodeURIComponent", JSGlobal_encodeURIComponent, PROPF_METHOD|1},
924 {L"escape", JSGlobal_escape, PROPF_METHOD|1},
925 {L"eval", JSGlobal_eval, PROPF_METHOD|1},
926 {L"isFinite", JSGlobal_isFinite, PROPF_METHOD|1},
927 {L"isNaN", JSGlobal_isNaN, PROPF_METHOD|1},
928 {L"parseFloat", JSGlobal_parseFloat, PROPF_METHOD|1},
929 {L"parseInt", JSGlobal_parseInt, PROPF_METHOD|2},
930 {L"unescape", JSGlobal_unescape, PROPF_METHOD|1}
933 static const builtin_info_t JSGlobal_info = {
934 JSCLASS_GLOBAL,
935 {NULL, NULL, 0},
936 ARRAY_SIZE(JSGlobal_props),
937 JSGlobal_props,
938 NULL,
939 NULL
942 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
944 HRESULT hres;
946 hres = init_function_constr(ctx, object_prototype);
947 if(FAILED(hres))
948 return hres;
950 hres = jsdisp_define_data_property(ctx->global, FunctionW, PROPF_WRITABLE,
951 jsval_obj(ctx->function_constr));
952 if(FAILED(hres))
953 return hres;
955 hres = create_object_constr(ctx, object_prototype, &ctx->object_constr);
956 if(FAILED(hres))
957 return hres;
959 hres = jsdisp_define_data_property(ctx->global, ObjectW, PROPF_WRITABLE,
960 jsval_obj(ctx->object_constr));
961 if(FAILED(hres))
962 return hres;
964 hres = create_array_constr(ctx, object_prototype, &ctx->array_constr);
965 if(FAILED(hres))
966 return hres;
968 hres = jsdisp_define_data_property(ctx->global, ArrayW, PROPF_WRITABLE,
969 jsval_obj(ctx->array_constr));
970 if(FAILED(hres))
971 return hres;
973 hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr);
974 if(FAILED(hres))
975 return hres;
977 hres = jsdisp_define_data_property(ctx->global, BooleanW, PROPF_WRITABLE,
978 jsval_obj(ctx->bool_constr));
979 if(FAILED(hres))
980 return hres;
982 hres = create_date_constr(ctx, object_prototype, &ctx->date_constr);
983 if(FAILED(hres))
984 return hres;
986 hres = jsdisp_define_data_property(ctx->global, DateW, PROPF_WRITABLE,
987 jsval_obj(ctx->date_constr));
988 if(FAILED(hres))
989 return hres;
991 hres = create_enumerator_constr(ctx, object_prototype, &ctx->enumerator_constr);
992 if(FAILED(hres))
993 return hres;
995 hres = jsdisp_define_data_property(ctx->global, EnumeratorW, PROPF_WRITABLE,
996 jsval_obj(ctx->enumerator_constr));
997 if(FAILED(hres))
998 return hres;
1000 hres = init_error_constr(ctx, object_prototype);
1001 if(FAILED(hres))
1002 return hres;
1004 hres = jsdisp_define_data_property(ctx->global, ErrorW, PROPF_WRITABLE,
1005 jsval_obj(ctx->error_constr));
1006 if(FAILED(hres))
1007 return hres;
1009 hres = jsdisp_define_data_property(ctx->global, EvalErrorW, PROPF_WRITABLE,
1010 jsval_obj(ctx->eval_error_constr));
1011 if(FAILED(hres))
1012 return hres;
1014 hres = jsdisp_define_data_property(ctx->global, RangeErrorW, PROPF_WRITABLE,
1015 jsval_obj(ctx->range_error_constr));
1016 if(FAILED(hres))
1017 return hres;
1019 hres = jsdisp_define_data_property(ctx->global, ReferenceErrorW, PROPF_WRITABLE,
1020 jsval_obj(ctx->reference_error_constr));
1021 if(FAILED(hres))
1022 return hres;
1024 hres = jsdisp_define_data_property(ctx->global, RegExpErrorW, PROPF_WRITABLE,
1025 jsval_obj(ctx->regexp_error_constr));
1026 if(FAILED(hres))
1027 return hres;
1029 hres = jsdisp_define_data_property(ctx->global, SyntaxErrorW, PROPF_WRITABLE,
1030 jsval_obj(ctx->syntax_error_constr));
1031 if(FAILED(hres))
1032 return hres;
1034 hres = jsdisp_define_data_property(ctx->global, TypeErrorW, PROPF_WRITABLE,
1035 jsval_obj(ctx->type_error_constr));
1036 if(FAILED(hres))
1037 return hres;
1039 hres = jsdisp_define_data_property(ctx->global, URIErrorW, PROPF_WRITABLE,
1040 jsval_obj(ctx->uri_error_constr));
1041 if(FAILED(hres))
1042 return hres;
1044 hres = create_number_constr(ctx, object_prototype, &ctx->number_constr);
1045 if(FAILED(hres))
1046 return hres;
1048 hres = jsdisp_define_data_property(ctx->global, NumberW, PROPF_WRITABLE,
1049 jsval_obj(ctx->number_constr));
1050 if(FAILED(hres))
1051 return hres;
1053 hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr);
1054 if(FAILED(hres))
1055 return hres;
1057 hres = jsdisp_define_data_property(ctx->global, RegExpW, PROPF_WRITABLE,
1058 jsval_obj(ctx->regexp_constr));
1059 if(FAILED(hres))
1060 return hres;
1062 hres = create_string_constr(ctx, object_prototype, &ctx->string_constr);
1063 if(FAILED(hres))
1064 return hres;
1066 hres = jsdisp_define_data_property(ctx->global, StringW, PROPF_WRITABLE,
1067 jsval_obj(ctx->string_constr));
1068 if(FAILED(hres))
1069 return hres;
1071 hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr);
1072 if(FAILED(hres))
1073 return hres;
1075 hres = jsdisp_define_data_property(ctx->global, VBArrayW, PROPF_WRITABLE,
1076 jsval_obj(ctx->vbarray_constr));
1077 if(FAILED(hres))
1078 return hres;
1080 return S_OK;
1083 HRESULT init_global(script_ctx_t *ctx)
1085 unsigned const_flags = ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? 0 : PROPF_WRITABLE;
1086 jsdisp_t *math, *object_prototype, *constr;
1087 HRESULT hres;
1089 if(ctx->global)
1090 return S_OK;
1092 hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
1093 if(FAILED(hres))
1094 return hres;
1096 hres = create_object_prototype(ctx, &object_prototype);
1097 if(FAILED(hres))
1098 return hres;
1100 hres = init_constructors(ctx, object_prototype);
1101 jsdisp_release(object_prototype);
1102 if(FAILED(hres))
1103 return hres;
1105 hres = create_math(ctx, &math);
1106 if(FAILED(hres))
1107 return hres;
1109 hres = jsdisp_define_data_property(ctx->global, MathW, PROPF_WRITABLE, jsval_obj(math));
1110 jsdisp_release(math);
1111 if(FAILED(hres))
1112 return hres;
1114 if(ctx->version >= 2) {
1115 jsdisp_t *json;
1117 hres = create_json(ctx, &json);
1118 if(FAILED(hres))
1119 return hres;
1121 hres = jsdisp_define_data_property(ctx->global, JSONW, PROPF_WRITABLE, jsval_obj(json));
1122 jsdisp_release(json);
1123 if(FAILED(hres))
1124 return hres;
1127 hres = create_activex_constr(ctx, &constr);
1128 if(FAILED(hres))
1129 return hres;
1131 hres = jsdisp_define_data_property(ctx->global, ActiveXObjectW, PROPF_WRITABLE,
1132 jsval_obj(constr));
1133 jsdisp_release(constr);
1134 if(FAILED(hres))
1135 return hres;
1137 hres = jsdisp_define_data_property(ctx->global, undefinedW, const_flags, jsval_undefined());
1138 if(FAILED(hres))
1139 return hres;
1141 hres = jsdisp_define_data_property(ctx->global, NaNW, const_flags, jsval_number(NAN));
1142 if(FAILED(hres))
1143 return hres;
1145 hres = jsdisp_define_data_property(ctx->global, InfinityW, const_flags, jsval_number(INFINITY));
1146 return hres;