windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / jscript / global.c
blob997b2542a9e04dbf7ad1eea2d660909883a839eb
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 int uri_char_table[] = {
31 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */
32 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */
33 0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */
34 2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */
35 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */
36 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */
37 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */
38 2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */
41 /* 1 - reserved */
42 /* 2 - unescaped */
44 static inline BOOL is_uri_reserved(WCHAR c)
46 return c < 128 && uri_char_table[c] == 1;
49 static inline BOOL is_uri_unescaped(WCHAR c)
51 return c < 128 && uri_char_table[c] == 2;
54 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
55 static inline BOOL is_ecma_nonblank(const WCHAR c)
57 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
58 c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
61 static WCHAR int_to_char(int i)
63 if(i < 10)
64 return '0'+i;
65 return 'A'+i-10;
68 static HRESULT JSGlobal_escape(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
69 jsval_t *r)
71 jsstr_t *ret_str, *str;
72 const WCHAR *ptr, *buf;
73 DWORD len = 0;
74 WCHAR *ret;
75 HRESULT hres;
77 TRACE("\n");
79 if(!argc) {
80 if(r)
81 *r = jsval_string(jsstr_undefined());
82 return S_OK;
85 hres = to_flat_string(ctx, argv[0], &str, &buf);
86 if(FAILED(hres))
87 return hres;
89 for(ptr = buf; *ptr; ptr++) {
90 if(*ptr > 0xff)
91 len += 6;
92 else if(is_ecma_nonblank(*ptr))
93 len++;
94 else
95 len += 3;
98 ret_str = jsstr_alloc_buf(len, &ret);
99 if(!ret_str) {
100 jsstr_release(str);
101 return E_OUTOFMEMORY;
104 len = 0;
105 for(ptr = buf; *ptr; ptr++) {
106 if(*ptr > 0xff) {
107 ret[len++] = '%';
108 ret[len++] = 'u';
109 ret[len++] = int_to_char(*ptr >> 12);
110 ret[len++] = int_to_char((*ptr >> 8) & 0xf);
111 ret[len++] = int_to_char((*ptr >> 4) & 0xf);
112 ret[len++] = int_to_char(*ptr & 0xf);
114 else if(is_ecma_nonblank(*ptr))
115 ret[len++] = *ptr;
116 else {
117 ret[len++] = '%';
118 ret[len++] = int_to_char(*ptr >> 4);
119 ret[len++] = int_to_char(*ptr & 0xf);
123 jsstr_release(str);
125 if(r)
126 *r = jsval_string(ret_str);
127 else
128 jsstr_release(ret_str);
129 return S_OK;
132 /* ECMA-262 3rd Edition 15.1.2.1 */
133 HRESULT builtin_eval(script_ctx_t *ctx, call_frame_t *frame, WORD flags, unsigned argc, jsval_t *argv,
134 jsval_t *r)
136 DWORD exec_flags = EXEC_EVAL;
137 bytecode_t *code;
138 const WCHAR *src;
139 HRESULT hres;
141 TRACE("\n");
143 if(!argc) {
144 if(r)
145 *r = jsval_undefined();
146 return S_OK;
149 if(!is_string(argv[0])) {
150 if(r)
151 return jsval_copy(argv[0], r);
152 return S_OK;
155 src = jsstr_flatten(get_string(argv[0]));
156 if(!src)
157 return E_OUTOFMEMORY;
159 TRACE("parsing %s\n", debugstr_jsval(argv[0]));
160 hres = compile_script(ctx, src, 0, 0, NULL, NULL, TRUE, FALSE, frame ? frame->bytecode->named_item : NULL, &code);
161 if(FAILED(hres)) {
162 WARN("parse (%s) failed: %08lx\n", debugstr_jsval(argv[0]), hres);
163 return hres;
166 if(!frame || (frame->flags & EXEC_GLOBAL))
167 exec_flags |= EXEC_GLOBAL;
168 if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
169 exec_flags |= EXEC_RETURN_TO_INTERP;
170 hres = exec_source(ctx, exec_flags, code, &code->global_code, frame ? frame->scope : NULL,
171 frame ? frame->this_obj : NULL, NULL, 0, NULL, r);
172 release_bytecode(code);
173 return hres;
176 HRESULT JSGlobal_eval(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
177 jsval_t *r)
179 return builtin_eval(ctx, ctx->version < SCRIPTLANGUAGEVERSION_ES5 ? ctx->call_ctx : NULL, flags, argc, argv, r);
182 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
183 jsval_t *r)
185 BOOL ret = TRUE;
186 double n;
187 HRESULT hres;
189 TRACE("\n");
191 if(argc) {
192 hres = to_number(ctx, argv[0], &n);
193 if(FAILED(hres))
194 return hres;
196 if(!isnan(n))
197 ret = FALSE;
200 if(r)
201 *r = jsval_bool(ret);
202 return S_OK;
205 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
206 jsval_t *r)
208 BOOL ret = FALSE;
209 HRESULT hres;
211 TRACE("\n");
213 if(argc) {
214 double n;
216 hres = to_number(ctx, argv[0], &n);
217 if(FAILED(hres))
218 return hres;
220 ret = isfinite(n);
223 if(r)
224 *r = jsval_bool(ret);
225 return S_OK;
228 static INT char_to_int(WCHAR c)
230 if('0' <= c && c <= '9')
231 return c - '0';
232 if('a' <= c && c <= 'z')
233 return c - 'a' + 10;
234 if('A' <= c && c <= 'Z')
235 return c - 'A' + 10;
236 return 100;
239 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
240 jsval_t *r)
242 BOOL neg = FALSE, empty = TRUE;
243 const WCHAR *ptr;
244 DOUBLE ret = 0.0;
245 INT radix=0, i;
246 jsstr_t *str;
247 HRESULT hres;
249 if(!argc) {
250 if(r)
251 *r = jsval_number(NAN);
252 return S_OK;
255 if(argc >= 2) {
256 hres = to_int32(ctx, argv[1], &radix);
257 if(FAILED(hres))
258 return hres;
260 if(radix && (radix < 2 || radix > 36)) {
261 WARN("radix %d out of range\n", radix);
262 if(r)
263 *r = jsval_number(NAN);
264 return S_OK;
268 hres = to_flat_string(ctx, argv[0], &str, &ptr);
269 if(FAILED(hres))
270 return hres;
272 while(iswspace(*ptr))
273 ptr++;
275 switch(*ptr) {
276 case '+':
277 ptr++;
278 break;
279 case '-':
280 neg = TRUE;
281 ptr++;
282 break;
285 if(!radix) {
286 if(*ptr == '0') {
287 if(ptr[1] == 'x' || ptr[1] == 'X') {
288 radix = 16;
289 ptr += 2;
290 }else {
291 radix = 8;
292 ptr++;
293 empty = FALSE;
295 }else {
296 radix = 10;
298 }else if(radix == 16 && *ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
299 ptr += 2;
302 i = char_to_int(*ptr++);
303 if(i < radix) {
304 do {
305 ret = ret*radix + i;
306 i = char_to_int(*ptr++);
307 }while(i < radix);
308 }else if(empty) {
309 ret = NAN;
312 jsstr_release(str);
314 if(neg)
315 ret = -ret;
317 if(r)
318 *r = jsval_number(ret);
319 return S_OK;
322 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
323 jsval_t *r)
325 LONGLONG d = 0, hlp;
326 jsstr_t *val_str;
327 int exp = 0;
328 const WCHAR *str;
329 BOOL ret_nan = TRUE, positive = TRUE;
330 HRESULT hres;
332 if(!argc) {
333 if(r)
334 *r = jsval_number(NAN);
335 return S_OK;
338 TRACE("%s\n", debugstr_jsval(argv[0]));
340 hres = to_flat_string(ctx, argv[0], &val_str, &str);
341 if(FAILED(hres))
342 return hres;
344 while(iswspace(*str)) str++;
346 if(*str == '+')
347 str++;
348 else if(*str == '-') {
349 positive = FALSE;
350 str++;
353 if(is_digit(*str))
354 ret_nan = FALSE;
356 while(is_digit(*str)) {
357 hlp = d*10 + *(str++) - '0';
358 if(d>MAXLONGLONG/10 || hlp<0) {
359 exp++;
360 break;
362 else
363 d = hlp;
365 while(is_digit(*str)) {
366 exp++;
367 str++;
370 if(*str == '.') str++;
372 if(is_digit(*str))
373 ret_nan = FALSE;
375 while(is_digit(*str)) {
376 hlp = d*10 + *(str++) - '0';
377 if(d>MAXLONGLONG/10 || hlp<0)
378 break;
380 d = hlp;
381 exp--;
383 while(is_digit(*str))
384 str++;
386 if(*str && !ret_nan && (*str=='e' || *str=='E')) {
387 int sign = 1, e = 0;
389 str++;
390 if(*str == '+')
391 str++;
392 else if(*str == '-') {
393 sign = -1;
394 str++;
397 while(is_digit(*str)) {
398 if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0)
399 e = INT_MAX;
401 e *= sign;
403 if(exp<0 && e<0 && exp+e>0) exp = INT_MIN;
404 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
405 else exp += e;
408 jsstr_release(val_str);
410 if(ret_nan) {
411 if(r)
412 *r = jsval_number(NAN);
413 return S_OK;
416 if(!positive)
417 d = -d;
418 if(r)
419 *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
420 return S_OK;
423 static inline int hex_to_int(const WCHAR wch) {
424 if(towupper(wch)>='A' && towupper(wch)<='F') return towupper(wch)-'A'+10;
425 if(is_digit(wch)) return wch-'0';
426 return -1;
429 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
430 jsval_t *r)
432 jsstr_t *ret_str, *str;
433 const WCHAR *ptr, *buf;
434 DWORD len = 0;
435 WCHAR *ret;
436 HRESULT hres;
438 TRACE("\n");
440 if(!argc) {
441 if(r)
442 *r = jsval_string(jsstr_undefined());
443 return S_OK;
446 hres = to_flat_string(ctx, argv[0], &str, &buf);
447 if(FAILED(hres))
448 return hres;
450 for(ptr = buf; *ptr; ptr++) {
451 if(*ptr == '%') {
452 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
453 ptr += 2;
454 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
455 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1)
456 ptr += 5;
459 len++;
462 ret_str = jsstr_alloc_buf(len, &ret);
463 if(!ret_str) {
464 jsstr_release(str);
465 return E_OUTOFMEMORY;
468 len = 0;
469 for(ptr = buf; *ptr; ptr++) {
470 if(*ptr == '%') {
471 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
472 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
473 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 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8)
478 + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5));
479 ptr += 5;
481 else
482 ret[len] = *ptr;
484 else
485 ret[len] = *ptr;
487 len++;
490 jsstr_release(str);
492 if(r)
493 *r = jsval_string(ret_str);
494 else
495 jsstr_release(ret_str);
496 return S_OK;
499 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
500 jsval_t *r)
502 FIXME("\n");
503 return E_NOTIMPL;
506 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
507 jsval_t *r)
509 TRACE("\n");
511 if(r) {
512 jsstr_t *ret;
514 ret = jsstr_alloc(L"JScript");
515 if(!ret)
516 return E_OUTOFMEMORY;
518 *r = jsval_string(ret);
521 return S_OK;
524 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
525 jsval_t *r)
527 TRACE("\n");
529 if(r)
530 *r = jsval_number(JSCRIPT_MAJOR_VERSION);
531 return S_OK;
534 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
535 jsval_t *r)
537 TRACE("\n");
539 if(r)
540 *r = jsval_number(JSCRIPT_MINOR_VERSION);
541 return S_OK;
544 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
545 jsval_t *r)
547 TRACE("\n");
549 if(r)
550 *r = jsval_number(JSCRIPT_BUILD_VERSION);
551 return S_OK;
554 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
555 jsval_t *r)
557 return gc_run(ctx);
560 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
561 jsval_t *r)
563 const WCHAR *ptr, *uri;
564 jsstr_t *str, *ret;
565 DWORD len = 0, i;
566 char buf[4];
567 WCHAR *rptr;
568 HRESULT hres;
570 TRACE("\n");
572 if(!argc) {
573 if(r)
574 *r = jsval_string(jsstr_undefined());
575 return S_OK;
578 hres = to_flat_string(ctx, argv[0], &str, &uri);
579 if(FAILED(hres))
580 return hres;
582 for(ptr = uri; *ptr; ptr++) {
583 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
584 len++;
585 }else {
586 i = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL)*3;
587 if(!i) {
588 jsstr_release(str);
589 return JS_E_INVALID_URI_CHAR;
592 len += i;
596 ret = jsstr_alloc_buf(len, &rptr);
597 if(!ret) {
598 jsstr_release(str);
599 return E_OUTOFMEMORY;
602 for(ptr = uri; *ptr; ptr++) {
603 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
604 *rptr++ = *ptr;
605 }else {
606 len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL);
607 for(i=0; i<len; i++) {
608 *rptr++ = '%';
609 *rptr++ = int_to_char((BYTE)buf[i] >> 4);
610 *rptr++ = int_to_char(buf[i] & 0x0f);
615 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
616 jsstr_release(str);
618 if(r)
619 *r = jsval_string(ret);
620 else
621 jsstr_release(ret);
622 return S_OK;
625 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
626 jsval_t *r)
628 const WCHAR *ptr, *uri;
629 jsstr_t *str, *ret_str;
630 unsigned len = 0;
631 int i, val, res;
632 WCHAR *ret;
633 char buf[4];
634 WCHAR out;
635 HRESULT hres;
637 TRACE("\n");
639 if(!argc) {
640 if(r)
641 *r = jsval_string(jsstr_undefined());
642 return S_OK;
645 hres = to_flat_string(ctx, argv[0], &str, &uri);
646 if(FAILED(hres))
647 return hres;
649 for(ptr = uri; *ptr; ptr++) {
650 if(*ptr != '%') {
651 len++;
652 }else {
653 res = 0;
654 for(i=0; i<4; i++) {
655 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
656 break;
657 val += hex_to_int(ptr[i*3+1])<<4;
658 buf[i] = val;
660 res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, &out, 1);
661 if(res)
662 break;
665 if(!res) {
666 jsstr_release(str);
667 return JS_E_INVALID_URI_CODING;
670 ptr += i*3+2;
671 len++;
675 ret_str = jsstr_alloc_buf(len, &ret);
676 if(!ret_str) {
677 jsstr_release(str);
678 return E_OUTOFMEMORY;
681 for(ptr = uri; *ptr; ptr++) {
682 if(*ptr != '%') {
683 *ret++ = *ptr;
684 }else {
685 for(i=0; i<4; i++) {
686 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
687 break;
688 val += hex_to_int(ptr[i*3+1])<<4;
689 buf[i] = val;
691 res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, ret, 1);
692 if(res)
693 break;
696 ptr += i*3+2;
697 ret++;
701 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret_str));
702 jsstr_release(str);
704 if(r)
705 *r = jsval_string(ret_str);
706 else
707 jsstr_release(ret_str);
708 return S_OK;
711 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
712 jsval_t *r)
714 jsstr_t *str, *ret_str;
715 char buf[4];
716 const WCHAR *ptr, *uri;
717 DWORD len = 0, size, i;
718 WCHAR *ret;
719 HRESULT hres;
721 TRACE("\n");
723 if(!argc) {
724 if(r)
725 *r = jsval_string(jsstr_undefined());
726 return S_OK;
729 hres = to_flat_string(ctx, argv[0], &str, &uri);
730 if(FAILED(hres))
731 return hres;
733 for(ptr = uri; *ptr; ptr++) {
734 if(is_uri_unescaped(*ptr))
735 len++;
736 else {
737 size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL);
738 if(!size) {
739 jsstr_release(str);
740 return JS_E_INVALID_URI_CHAR;
742 len += size*3;
746 ret_str = jsstr_alloc_buf(len, &ret);
747 if(!ret_str) {
748 jsstr_release(str);
749 return E_OUTOFMEMORY;
752 for(ptr = uri; *ptr; ptr++) {
753 if(is_uri_unescaped(*ptr)) {
754 *ret++ = *ptr;
755 }else {
756 size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL);
757 for(i=0; i<size; i++) {
758 *ret++ = '%';
759 *ret++ = int_to_char((BYTE)buf[i] >> 4);
760 *ret++ = int_to_char(buf[i] & 0x0f);
765 jsstr_release(str);
767 if(r)
768 *r = jsval_string(ret_str);
769 else
770 jsstr_release(ret_str);
771 return S_OK;
774 /* ECMA-262 3rd Edition 15.1.3.2 */
775 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
776 jsval_t *r)
778 const WCHAR *ptr, *uri;
779 jsstr_t *str, *ret;
780 WCHAR *out_ptr;
781 DWORD len = 0;
782 HRESULT hres;
784 TRACE("\n");
786 if(!argc) {
787 if(r)
788 *r = jsval_string(jsstr_undefined());
789 return S_OK;
792 hres = to_flat_string(ctx, argv[0], &str, &uri);
793 if(FAILED(hres))
794 return hres;
796 ptr = uri;
797 while(*ptr) {
798 if(*ptr == '%') {
799 char octets[4];
800 unsigned char mask = 0x80;
801 int i, size, num_bytes = 0;
802 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
803 FIXME("Throw URIError: Invalid hex sequence\n");
804 jsstr_release(str);
805 return E_FAIL;
807 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
808 ptr += 3;
809 while(octets[0] & mask) {
810 mask = mask >> 1;
811 ++num_bytes;
813 if(num_bytes == 1 || num_bytes > 4) {
814 FIXME("Throw URIError: Invalid initial UTF character\n");
815 jsstr_release(str);
816 return E_FAIL;
818 for(i = 1; i < num_bytes; ++i) {
819 if(*ptr != '%'){
820 FIXME("Throw URIError: Incomplete UTF sequence\n");
821 jsstr_release(str);
822 return E_FAIL;
824 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
825 FIXME("Throw URIError: Invalid hex sequence\n");
826 jsstr_release(str);
827 return E_FAIL;
829 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
830 ptr += 3;
832 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
833 num_bytes ? num_bytes : 1, NULL, 0);
834 if(size == 0) {
835 FIXME("Throw URIError: Invalid UTF sequence\n");
836 jsstr_release(str);
837 return E_FAIL;
839 len += size;
840 }else {
841 ++ptr;
842 ++len;
846 ret = jsstr_alloc_buf(len, &out_ptr);
847 if(!ret) {
848 jsstr_release(str);
849 return E_OUTOFMEMORY;
852 ptr = uri;
853 while(*ptr) {
854 if(*ptr == '%') {
855 char octets[4];
856 unsigned char mask = 0x80;
857 int i, size, num_bytes = 0;
858 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
859 ptr += 3;
860 while(octets[0] & mask) {
861 mask = mask >> 1;
862 ++num_bytes;
864 for(i = 1; i < num_bytes; ++i) {
865 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
866 ptr += 3;
868 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
869 num_bytes ? num_bytes : 1, out_ptr, len);
870 len -= size;
871 out_ptr += size;
872 }else {
873 *out_ptr++ = *ptr++;
874 --len;
878 jsstr_release(str);
880 if(r)
881 *r = jsval_string(ret);
882 else
883 jsstr_release(ret);
884 return S_OK;
887 static const builtin_prop_t JSGlobal_props[] = {
888 {L"CollectGarbage", JSGlobal_CollectGarbage, PROPF_METHOD},
889 {L"GetObject", JSGlobal_GetObject, PROPF_METHOD|2},
890 {L"ScriptEngine", JSGlobal_ScriptEngine, PROPF_METHOD},
891 {L"ScriptEngineBuildVersion", JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD},
892 {L"ScriptEngineMajorVersion", JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD},
893 {L"ScriptEngineMinorVersion", JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD},
894 {L"decodeURI", JSGlobal_decodeURI, PROPF_METHOD|1},
895 {L"decodeURIComponent", JSGlobal_decodeURIComponent, PROPF_METHOD|1},
896 {L"encodeURI", JSGlobal_encodeURI, PROPF_METHOD|1},
897 {L"encodeURIComponent", JSGlobal_encodeURIComponent, PROPF_METHOD|1},
898 {L"escape", JSGlobal_escape, PROPF_METHOD|1},
899 {L"eval", JSGlobal_eval, PROPF_METHOD|1},
900 {L"isFinite", JSGlobal_isFinite, PROPF_METHOD|1},
901 {L"isNaN", JSGlobal_isNaN, PROPF_METHOD|1},
902 {L"parseFloat", JSGlobal_parseFloat, PROPF_METHOD|1},
903 {L"parseInt", JSGlobal_parseInt, PROPF_METHOD|2},
904 {L"unescape", JSGlobal_unescape, PROPF_METHOD|1}
907 static const builtin_info_t JSGlobal_info = {
908 JSCLASS_GLOBAL,
909 NULL,
910 ARRAY_SIZE(JSGlobal_props),
911 JSGlobal_props,
912 NULL,
913 NULL
916 static HRESULT init_object_prototype_accessors(script_ctx_t *ctx, jsdisp_t *object_prototype)
918 property_desc_t desc;
919 HRESULT hres = S_OK;
921 /* __proto__ is an actual accessor on native, despite being a builtin */
922 if(ctx->version >= SCRIPTLANGUAGEVERSION_ES6) {
923 desc.flags = PROPF_CONFIGURABLE;
924 desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
925 desc.explicit_getter = desc.explicit_setter = TRUE;
926 desc.explicit_value = FALSE;
928 hres = create_builtin_function(ctx, Object_get_proto_, NULL, NULL, PROPF_METHOD, NULL, &desc.getter);
929 if(SUCCEEDED(hres)) {
930 hres = create_builtin_function(ctx, Object_set_proto_, NULL, NULL, PROPF_METHOD|1, NULL, &desc.setter);
931 if(SUCCEEDED(hres)) {
932 hres = jsdisp_define_property(object_prototype, L"__proto__", &desc);
933 jsdisp_release(desc.setter);
935 jsdisp_release(desc.getter);
938 return hres;
941 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
943 HRESULT hres;
945 hres = init_function_constr(ctx, object_prototype);
946 if(FAILED(hres))
947 return hres;
949 hres = jsdisp_define_data_property(ctx->global, L"Function", PROPF_WRITABLE,
950 jsval_obj(ctx->function_constr));
951 if(FAILED(hres))
952 return hres;
954 hres = create_object_constr(ctx, object_prototype, &ctx->object_constr);
955 if(FAILED(hres))
956 return hres;
958 hres = jsdisp_define_data_property(ctx->global, L"Object", PROPF_WRITABLE,
959 jsval_obj(ctx->object_constr));
960 if(FAILED(hres))
961 return hres;
963 hres = create_array_constr(ctx, object_prototype, &ctx->array_constr);
964 if(FAILED(hres))
965 return hres;
967 hres = jsdisp_define_data_property(ctx->global, L"Array", PROPF_WRITABLE,
968 jsval_obj(ctx->array_constr));
969 if(FAILED(hres))
970 return hres;
972 hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr);
973 if(FAILED(hres))
974 return hres;
976 hres = jsdisp_define_data_property(ctx->global, L"Boolean", PROPF_WRITABLE,
977 jsval_obj(ctx->bool_constr));
978 if(FAILED(hres))
979 return hres;
981 hres = create_date_constr(ctx, object_prototype, &ctx->date_constr);
982 if(FAILED(hres))
983 return hres;
985 hres = jsdisp_define_data_property(ctx->global, L"Date", PROPF_WRITABLE,
986 jsval_obj(ctx->date_constr));
987 if(FAILED(hres))
988 return hres;
990 hres = create_enumerator_constr(ctx, object_prototype, &ctx->enumerator_constr);
991 if(FAILED(hres))
992 return hres;
994 hres = jsdisp_define_data_property(ctx->global, L"Enumerator", PROPF_WRITABLE,
995 jsval_obj(ctx->enumerator_constr));
996 if(FAILED(hres))
997 return hres;
999 hres = init_error_constr(ctx, object_prototype);
1000 if(FAILED(hres))
1001 return hres;
1003 hres = jsdisp_define_data_property(ctx->global, L"Error", PROPF_WRITABLE,
1004 jsval_obj(ctx->error_constr));
1005 if(FAILED(hres))
1006 return hres;
1008 hres = jsdisp_define_data_property(ctx->global, L"EvalError", PROPF_WRITABLE,
1009 jsval_obj(ctx->eval_error_constr));
1010 if(FAILED(hres))
1011 return hres;
1013 hres = jsdisp_define_data_property(ctx->global, L"RangeError", PROPF_WRITABLE,
1014 jsval_obj(ctx->range_error_constr));
1015 if(FAILED(hres))
1016 return hres;
1018 hres = jsdisp_define_data_property(ctx->global, L"ReferenceError", PROPF_WRITABLE,
1019 jsval_obj(ctx->reference_error_constr));
1020 if(FAILED(hres))
1021 return hres;
1023 hres = jsdisp_define_data_property(ctx->global, L"RegExpError", PROPF_WRITABLE,
1024 jsval_obj(ctx->regexp_error_constr));
1025 if(FAILED(hres))
1026 return hres;
1028 hres = jsdisp_define_data_property(ctx->global, L"SyntaxError", PROPF_WRITABLE,
1029 jsval_obj(ctx->syntax_error_constr));
1030 if(FAILED(hres))
1031 return hres;
1033 hres = jsdisp_define_data_property(ctx->global, L"TypeError", PROPF_WRITABLE,
1034 jsval_obj(ctx->type_error_constr));
1035 if(FAILED(hres))
1036 return hres;
1038 hres = jsdisp_define_data_property(ctx->global, L"URIError", PROPF_WRITABLE,
1039 jsval_obj(ctx->uri_error_constr));
1040 if(FAILED(hres))
1041 return hres;
1043 hres = create_number_constr(ctx, object_prototype, &ctx->number_constr);
1044 if(FAILED(hres))
1045 return hres;
1047 hres = jsdisp_define_data_property(ctx->global, L"Number", PROPF_WRITABLE,
1048 jsval_obj(ctx->number_constr));
1049 if(FAILED(hres))
1050 return hres;
1052 hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr);
1053 if(FAILED(hres))
1054 return hres;
1056 hres = jsdisp_define_data_property(ctx->global, L"RegExp", PROPF_WRITABLE,
1057 jsval_obj(ctx->regexp_constr));
1058 if(FAILED(hres))
1059 return hres;
1061 hres = create_string_constr(ctx, object_prototype, &ctx->string_constr);
1062 if(FAILED(hres))
1063 return hres;
1065 hres = jsdisp_define_data_property(ctx->global, L"String", PROPF_WRITABLE,
1066 jsval_obj(ctx->string_constr));
1067 if(FAILED(hres))
1068 return hres;
1070 hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr);
1071 if(FAILED(hres))
1072 return hres;
1074 hres = jsdisp_define_data_property(ctx->global, L"VBArray", PROPF_WRITABLE,
1075 jsval_obj(ctx->vbarray_constr));
1076 if(FAILED(hres))
1077 return hres;
1079 return S_OK;
1082 HRESULT init_global(script_ctx_t *ctx)
1084 unsigned const_flags = ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? 0 : PROPF_WRITABLE;
1085 jsdisp_t *math, *constr;
1086 HRESULT hres;
1088 if(ctx->global)
1089 return S_OK;
1091 hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
1092 if(FAILED(hres))
1093 return hres;
1095 hres = create_object_prototype(ctx, &ctx->object_prototype);
1096 if(FAILED(hres))
1097 return hres;
1099 hres = init_constructors(ctx, ctx->object_prototype);
1100 if(FAILED(hres))
1101 return hres;
1103 hres = init_object_prototype_accessors(ctx, ctx->object_prototype);
1104 if(FAILED(hres))
1105 return hres;
1107 hres = create_math(ctx, &math);
1108 if(FAILED(hres))
1109 return hres;
1111 hres = jsdisp_define_data_property(ctx->global, L"Math", PROPF_WRITABLE, jsval_obj(math));
1112 jsdisp_release(math);
1113 if(FAILED(hres))
1114 return hres;
1116 if(ctx->version >= 2) {
1117 jsdisp_t *json;
1119 hres = create_json(ctx, &json);
1120 if(FAILED(hres))
1121 return hres;
1123 hres = jsdisp_define_data_property(ctx->global, L"JSON", PROPF_WRITABLE, jsval_obj(json));
1124 jsdisp_release(json);
1125 if(FAILED(hres))
1126 return hres;
1129 hres = create_activex_constr(ctx, &constr);
1130 if(FAILED(hres))
1131 return hres;
1133 hres = jsdisp_define_data_property(ctx->global, L"ActiveXObject", PROPF_WRITABLE,
1134 jsval_obj(constr));
1135 jsdisp_release(constr);
1136 if(FAILED(hres))
1137 return hres;
1139 hres = jsdisp_define_data_property(ctx->global, L"undefined", const_flags, jsval_undefined());
1140 if(FAILED(hres))
1141 return hres;
1143 hres = jsdisp_define_data_property(ctx->global, L"NaN", const_flags, jsval_number(NAN));
1144 if(FAILED(hres))
1145 return hres;
1147 hres = jsdisp_define_data_property(ctx->global, L"Infinity", const_flags, jsval_number(INFINITY));
1148 if(FAILED(hres))
1149 return hres;
1151 return init_set_constructor(ctx);