winhttp: Don't refill buffer after receiving server response.
[wine.git] / dlls / jscript / global.c
blob9dd969aa3345f8aab0ab44327c556a3d39a5bb6b
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 JSGlobal_eval(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
134 jsval_t *r)
136 call_frame_t *frame = ctx->call_ctx;
137 DWORD exec_flags = EXEC_EVAL;
138 bytecode_t *code;
139 const WCHAR *src;
140 HRESULT hres;
142 TRACE("\n");
144 if(!argc) {
145 if(r)
146 *r = jsval_undefined();
147 return S_OK;
150 if(!is_string(argv[0])) {
151 if(r)
152 return jsval_copy(argv[0], r);
153 return S_OK;
156 src = jsstr_flatten(get_string(argv[0]));
157 if(!src)
158 return E_OUTOFMEMORY;
160 TRACE("parsing %s\n", debugstr_jsval(argv[0]));
161 hres = compile_script(ctx, src, 0, 0, NULL, NULL, TRUE, FALSE, frame ? frame->bytecode->named_item : NULL, &code);
162 if(FAILED(hres)) {
163 WARN("parse (%s) failed: %08lx\n", debugstr_jsval(argv[0]), hres);
164 return hres;
167 if(!frame || (frame->flags & EXEC_GLOBAL))
168 exec_flags |= EXEC_GLOBAL;
169 if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE)
170 exec_flags |= EXEC_RETURN_TO_INTERP;
171 hres = exec_source(ctx, exec_flags, code, &code->global_code, frame ? frame->scope : NULL,
172 frame ? frame->this_obj : NULL, NULL, 0, NULL, r);
173 release_bytecode(code);
174 return hres;
177 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
178 jsval_t *r)
180 BOOL ret = TRUE;
181 double n;
182 HRESULT hres;
184 TRACE("\n");
186 if(argc) {
187 hres = to_number(ctx, argv[0], &n);
188 if(FAILED(hres))
189 return hres;
191 if(!isnan(n))
192 ret = FALSE;
195 if(r)
196 *r = jsval_bool(ret);
197 return S_OK;
200 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
201 jsval_t *r)
203 BOOL ret = FALSE;
204 HRESULT hres;
206 TRACE("\n");
208 if(argc) {
209 double n;
211 hres = to_number(ctx, argv[0], &n);
212 if(FAILED(hres))
213 return hres;
215 ret = isfinite(n);
218 if(r)
219 *r = jsval_bool(ret);
220 return S_OK;
223 static INT char_to_int(WCHAR c)
225 if('0' <= c && c <= '9')
226 return c - '0';
227 if('a' <= c && c <= 'z')
228 return c - 'a' + 10;
229 if('A' <= c && c <= 'Z')
230 return c - 'A' + 10;
231 return 100;
234 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
235 jsval_t *r)
237 BOOL neg = FALSE, empty = TRUE;
238 const WCHAR *ptr;
239 DOUBLE ret = 0.0;
240 INT radix=0, i;
241 jsstr_t *str;
242 HRESULT hres;
244 if(!argc) {
245 if(r)
246 *r = jsval_number(NAN);
247 return S_OK;
250 if(argc >= 2) {
251 hres = to_int32(ctx, argv[1], &radix);
252 if(FAILED(hres))
253 return hres;
255 if(radix && (radix < 2 || radix > 36)) {
256 WARN("radix %d out of range\n", radix);
257 if(r)
258 *r = jsval_number(NAN);
259 return S_OK;
263 hres = to_flat_string(ctx, argv[0], &str, &ptr);
264 if(FAILED(hres))
265 return hres;
267 while(iswspace(*ptr))
268 ptr++;
270 switch(*ptr) {
271 case '+':
272 ptr++;
273 break;
274 case '-':
275 neg = TRUE;
276 ptr++;
277 break;
280 if(!radix) {
281 if(*ptr == '0') {
282 if(ptr[1] == 'x' || ptr[1] == 'X') {
283 radix = 16;
284 ptr += 2;
285 }else {
286 radix = 8;
287 ptr++;
288 empty = FALSE;
290 }else {
291 radix = 10;
293 }else if(radix == 16 && *ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
294 ptr += 2;
297 i = char_to_int(*ptr++);
298 if(i < radix) {
299 do {
300 ret = ret*radix + i;
301 i = char_to_int(*ptr++);
302 }while(i < radix);
303 }else if(empty) {
304 ret = NAN;
307 jsstr_release(str);
309 if(neg)
310 ret = -ret;
312 if(r)
313 *r = jsval_number(ret);
314 return S_OK;
317 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
318 jsval_t *r)
320 LONGLONG d = 0, hlp;
321 jsstr_t *val_str;
322 int exp = 0;
323 const WCHAR *str;
324 BOOL ret_nan = TRUE, positive = TRUE;
325 HRESULT hres;
327 if(!argc) {
328 if(r)
329 *r = jsval_number(NAN);
330 return S_OK;
333 TRACE("%s\n", debugstr_jsval(argv[0]));
335 hres = to_flat_string(ctx, argv[0], &val_str, &str);
336 if(FAILED(hres))
337 return hres;
339 while(iswspace(*str)) str++;
341 if(*str == '+')
342 str++;
343 else if(*str == '-') {
344 positive = FALSE;
345 str++;
348 if(is_digit(*str))
349 ret_nan = FALSE;
351 while(is_digit(*str)) {
352 hlp = d*10 + *(str++) - '0';
353 if(d>MAXLONGLONG/10 || hlp<0) {
354 exp++;
355 break;
357 else
358 d = hlp;
360 while(is_digit(*str)) {
361 exp++;
362 str++;
365 if(*str == '.') str++;
367 if(is_digit(*str))
368 ret_nan = FALSE;
370 while(is_digit(*str)) {
371 hlp = d*10 + *(str++) - '0';
372 if(d>MAXLONGLONG/10 || hlp<0)
373 break;
375 d = hlp;
376 exp--;
378 while(is_digit(*str))
379 str++;
381 if(*str && !ret_nan && (*str=='e' || *str=='E')) {
382 int sign = 1, e = 0;
384 str++;
385 if(*str == '+')
386 str++;
387 else if(*str == '-') {
388 sign = -1;
389 str++;
392 while(is_digit(*str)) {
393 if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0)
394 e = INT_MAX;
396 e *= sign;
398 if(exp<0 && e<0 && exp+e>0) exp = INT_MIN;
399 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
400 else exp += e;
403 jsstr_release(val_str);
405 if(ret_nan) {
406 if(r)
407 *r = jsval_number(NAN);
408 return S_OK;
411 if(!positive)
412 d = -d;
413 if(r)
414 *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
415 return S_OK;
418 static inline int hex_to_int(const WCHAR wch) {
419 if(towupper(wch)>='A' && towupper(wch)<='F') return towupper(wch)-'A'+10;
420 if(is_digit(wch)) return wch-'0';
421 return -1;
424 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
425 jsval_t *r)
427 jsstr_t *ret_str, *str;
428 const WCHAR *ptr, *buf;
429 DWORD len = 0;
430 WCHAR *ret;
431 HRESULT hres;
433 TRACE("\n");
435 if(!argc) {
436 if(r)
437 *r = jsval_string(jsstr_undefined());
438 return S_OK;
441 hres = to_flat_string(ctx, argv[0], &str, &buf);
442 if(FAILED(hres))
443 return hres;
445 for(ptr = buf; *ptr; ptr++) {
446 if(*ptr == '%') {
447 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
448 ptr += 2;
449 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
450 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1)
451 ptr += 5;
454 len++;
457 ret_str = jsstr_alloc_buf(len, &ret);
458 if(!ret_str) {
459 jsstr_release(str);
460 return E_OUTOFMEMORY;
463 len = 0;
464 for(ptr = buf; *ptr; ptr++) {
465 if(*ptr == '%') {
466 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
467 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
468 ptr += 2;
470 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
471 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) {
472 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8)
473 + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5));
474 ptr += 5;
476 else
477 ret[len] = *ptr;
479 else
480 ret[len] = *ptr;
482 len++;
485 jsstr_release(str);
487 if(r)
488 *r = jsval_string(ret_str);
489 else
490 jsstr_release(ret_str);
491 return S_OK;
494 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
495 jsval_t *r)
497 FIXME("\n");
498 return E_NOTIMPL;
501 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
502 jsval_t *r)
504 TRACE("\n");
506 if(r) {
507 jsstr_t *ret;
509 ret = jsstr_alloc(L"JScript");
510 if(!ret)
511 return E_OUTOFMEMORY;
513 *r = jsval_string(ret);
516 return S_OK;
519 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
520 jsval_t *r)
522 TRACE("\n");
524 if(r)
525 *r = jsval_number(JSCRIPT_MAJOR_VERSION);
526 return S_OK;
529 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
530 jsval_t *r)
532 TRACE("\n");
534 if(r)
535 *r = jsval_number(JSCRIPT_MINOR_VERSION);
536 return S_OK;
539 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
540 jsval_t *r)
542 TRACE("\n");
544 if(r)
545 *r = jsval_number(JSCRIPT_BUILD_VERSION);
546 return S_OK;
549 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
550 jsval_t *r)
552 return gc_run(ctx);
555 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
556 jsval_t *r)
558 const WCHAR *ptr, *uri;
559 jsstr_t *str, *ret;
560 DWORD len = 0, i;
561 char buf[4];
562 WCHAR *rptr;
563 HRESULT hres;
565 TRACE("\n");
567 if(!argc) {
568 if(r)
569 *r = jsval_string(jsstr_undefined());
570 return S_OK;
573 hres = to_flat_string(ctx, argv[0], &str, &uri);
574 if(FAILED(hres))
575 return hres;
577 for(ptr = uri; *ptr; ptr++) {
578 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
579 len++;
580 }else {
581 i = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL)*3;
582 if(!i) {
583 jsstr_release(str);
584 return JS_E_INVALID_URI_CHAR;
587 len += i;
591 ret = jsstr_alloc_buf(len, &rptr);
592 if(!ret) {
593 jsstr_release(str);
594 return E_OUTOFMEMORY;
597 for(ptr = uri; *ptr; ptr++) {
598 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
599 *rptr++ = *ptr;
600 }else {
601 len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL);
602 for(i=0; i<len; i++) {
603 *rptr++ = '%';
604 *rptr++ = int_to_char((BYTE)buf[i] >> 4);
605 *rptr++ = int_to_char(buf[i] & 0x0f);
610 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
611 jsstr_release(str);
613 if(r)
614 *r = jsval_string(ret);
615 else
616 jsstr_release(ret);
617 return S_OK;
620 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
621 jsval_t *r)
623 const WCHAR *ptr, *uri;
624 jsstr_t *str, *ret_str;
625 unsigned len = 0;
626 int i, val, res;
627 WCHAR *ret;
628 char buf[4];
629 WCHAR out;
630 HRESULT hres;
632 TRACE("\n");
634 if(!argc) {
635 if(r)
636 *r = jsval_string(jsstr_undefined());
637 return S_OK;
640 hres = to_flat_string(ctx, argv[0], &str, &uri);
641 if(FAILED(hres))
642 return hres;
644 for(ptr = uri; *ptr; ptr++) {
645 if(*ptr != '%') {
646 len++;
647 }else {
648 res = 0;
649 for(i=0; i<4; i++) {
650 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
651 break;
652 val += hex_to_int(ptr[i*3+1])<<4;
653 buf[i] = val;
655 res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, &out, 1);
656 if(res)
657 break;
660 if(!res) {
661 jsstr_release(str);
662 return JS_E_INVALID_URI_CODING;
665 ptr += i*3+2;
666 len++;
670 ret_str = jsstr_alloc_buf(len, &ret);
671 if(!ret_str) {
672 jsstr_release(str);
673 return E_OUTOFMEMORY;
676 for(ptr = uri; *ptr; ptr++) {
677 if(*ptr != '%') {
678 *ret++ = *ptr;
679 }else {
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, ret, 1);
687 if(res)
688 break;
691 ptr += i*3+2;
692 ret++;
696 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret_str));
697 jsstr_release(str);
699 if(r)
700 *r = jsval_string(ret_str);
701 else
702 jsstr_release(ret_str);
703 return S_OK;
706 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
707 jsval_t *r)
709 jsstr_t *str, *ret_str;
710 char buf[4];
711 const WCHAR *ptr, *uri;
712 DWORD len = 0, size, i;
713 WCHAR *ret;
714 HRESULT hres;
716 TRACE("\n");
718 if(!argc) {
719 if(r)
720 *r = jsval_string(jsstr_undefined());
721 return S_OK;
724 hres = to_flat_string(ctx, argv[0], &str, &uri);
725 if(FAILED(hres))
726 return hres;
728 for(ptr = uri; *ptr; ptr++) {
729 if(is_uri_unescaped(*ptr))
730 len++;
731 else {
732 size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL);
733 if(!size) {
734 jsstr_release(str);
735 return JS_E_INVALID_URI_CHAR;
737 len += size*3;
741 ret_str = jsstr_alloc_buf(len, &ret);
742 if(!ret_str) {
743 jsstr_release(str);
744 return E_OUTOFMEMORY;
747 for(ptr = uri; *ptr; ptr++) {
748 if(is_uri_unescaped(*ptr)) {
749 *ret++ = *ptr;
750 }else {
751 size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL);
752 for(i=0; i<size; i++) {
753 *ret++ = '%';
754 *ret++ = int_to_char((BYTE)buf[i] >> 4);
755 *ret++ = int_to_char(buf[i] & 0x0f);
760 jsstr_release(str);
762 if(r)
763 *r = jsval_string(ret_str);
764 else
765 jsstr_release(ret_str);
766 return S_OK;
769 /* ECMA-262 3rd Edition 15.1.3.2 */
770 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
771 jsval_t *r)
773 const WCHAR *ptr, *uri;
774 jsstr_t *str, *ret;
775 WCHAR *out_ptr;
776 DWORD len = 0;
777 HRESULT hres;
779 TRACE("\n");
781 if(!argc) {
782 if(r)
783 *r = jsval_string(jsstr_undefined());
784 return S_OK;
787 hres = to_flat_string(ctx, argv[0], &str, &uri);
788 if(FAILED(hres))
789 return hres;
791 ptr = uri;
792 while(*ptr) {
793 if(*ptr == '%') {
794 char octets[4];
795 unsigned char mask = 0x80;
796 int i, size, num_bytes = 0;
797 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
798 FIXME("Throw URIError: Invalid hex sequence\n");
799 jsstr_release(str);
800 return E_FAIL;
802 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
803 ptr += 3;
804 while(octets[0] & mask) {
805 mask = mask >> 1;
806 ++num_bytes;
808 if(num_bytes == 1 || num_bytes > 4) {
809 FIXME("Throw URIError: Invalid initial UTF character\n");
810 jsstr_release(str);
811 return E_FAIL;
813 for(i = 1; i < num_bytes; ++i) {
814 if(*ptr != '%'){
815 FIXME("Throw URIError: Incomplete UTF sequence\n");
816 jsstr_release(str);
817 return E_FAIL;
819 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
820 FIXME("Throw URIError: Invalid hex sequence\n");
821 jsstr_release(str);
822 return E_FAIL;
824 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
825 ptr += 3;
827 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
828 num_bytes ? num_bytes : 1, NULL, 0);
829 if(size == 0) {
830 FIXME("Throw URIError: Invalid UTF sequence\n");
831 jsstr_release(str);
832 return E_FAIL;
834 len += size;
835 }else {
836 ++ptr;
837 ++len;
841 ret = jsstr_alloc_buf(len, &out_ptr);
842 if(!ret) {
843 jsstr_release(str);
844 return E_OUTOFMEMORY;
847 ptr = uri;
848 while(*ptr) {
849 if(*ptr == '%') {
850 char octets[4];
851 unsigned char mask = 0x80;
852 int i, size, num_bytes = 0;
853 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
854 ptr += 3;
855 while(octets[0] & mask) {
856 mask = mask >> 1;
857 ++num_bytes;
859 for(i = 1; i < num_bytes; ++i) {
860 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
861 ptr += 3;
863 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
864 num_bytes ? num_bytes : 1, out_ptr, len);
865 len -= size;
866 out_ptr += size;
867 }else {
868 *out_ptr++ = *ptr++;
869 --len;
873 jsstr_release(str);
875 if(r)
876 *r = jsval_string(ret);
877 else
878 jsstr_release(ret);
879 return S_OK;
882 static const builtin_prop_t JSGlobal_props[] = {
883 {L"CollectGarbage", JSGlobal_CollectGarbage, PROPF_METHOD},
884 {L"GetObject", JSGlobal_GetObject, PROPF_METHOD|2},
885 {L"ScriptEngine", JSGlobal_ScriptEngine, PROPF_METHOD},
886 {L"ScriptEngineBuildVersion", JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD},
887 {L"ScriptEngineMajorVersion", JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD},
888 {L"ScriptEngineMinorVersion", JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD},
889 {L"decodeURI", JSGlobal_decodeURI, PROPF_METHOD|1},
890 {L"decodeURIComponent", JSGlobal_decodeURIComponent, PROPF_METHOD|1},
891 {L"encodeURI", JSGlobal_encodeURI, PROPF_METHOD|1},
892 {L"encodeURIComponent", JSGlobal_encodeURIComponent, PROPF_METHOD|1},
893 {L"escape", JSGlobal_escape, PROPF_METHOD|1},
894 {L"eval", JSGlobal_eval, PROPF_METHOD|1},
895 {L"isFinite", JSGlobal_isFinite, PROPF_METHOD|1},
896 {L"isNaN", JSGlobal_isNaN, PROPF_METHOD|1},
897 {L"parseFloat", JSGlobal_parseFloat, PROPF_METHOD|1},
898 {L"parseInt", JSGlobal_parseInt, PROPF_METHOD|2},
899 {L"unescape", JSGlobal_unescape, PROPF_METHOD|1}
902 static const builtin_info_t JSGlobal_info = {
903 JSCLASS_GLOBAL,
904 NULL,
905 ARRAY_SIZE(JSGlobal_props),
906 JSGlobal_props,
907 NULL,
908 NULL
911 static HRESULT init_object_prototype_accessors(script_ctx_t *ctx, jsdisp_t *object_prototype)
913 property_desc_t desc;
914 HRESULT hres = S_OK;
916 /* __proto__ is an actual accessor on native, despite being a builtin */
917 if(ctx->version >= SCRIPTLANGUAGEVERSION_ES6) {
918 desc.flags = PROPF_CONFIGURABLE;
919 desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
920 desc.explicit_getter = desc.explicit_setter = TRUE;
921 desc.explicit_value = FALSE;
923 hres = create_builtin_function(ctx, Object_get_proto_, NULL, NULL, PROPF_METHOD, NULL, &desc.getter);
924 if(SUCCEEDED(hres)) {
925 hres = create_builtin_function(ctx, Object_set_proto_, NULL, NULL, PROPF_METHOD|1, NULL, &desc.setter);
926 if(SUCCEEDED(hres)) {
927 hres = jsdisp_define_property(object_prototype, L"__proto__", &desc);
928 jsdisp_release(desc.setter);
930 jsdisp_release(desc.getter);
933 return hres;
936 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
938 HRESULT hres;
940 hres = init_function_constr(ctx, object_prototype);
941 if(FAILED(hres))
942 return hres;
944 hres = jsdisp_define_data_property(ctx->global, L"Function", PROPF_WRITABLE,
945 jsval_obj(ctx->function_constr));
946 if(FAILED(hres))
947 return hres;
949 hres = create_object_constr(ctx, object_prototype, &ctx->object_constr);
950 if(FAILED(hres))
951 return hres;
953 hres = jsdisp_define_data_property(ctx->global, L"Object", PROPF_WRITABLE,
954 jsval_obj(ctx->object_constr));
955 if(FAILED(hres))
956 return hres;
958 hres = create_array_constr(ctx, object_prototype, &ctx->array_constr);
959 if(FAILED(hres))
960 return hres;
962 hres = jsdisp_define_data_property(ctx->global, L"Array", PROPF_WRITABLE,
963 jsval_obj(ctx->array_constr));
964 if(FAILED(hres))
965 return hres;
967 hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr);
968 if(FAILED(hres))
969 return hres;
971 hres = jsdisp_define_data_property(ctx->global, L"Boolean", PROPF_WRITABLE,
972 jsval_obj(ctx->bool_constr));
973 if(FAILED(hres))
974 return hres;
976 hres = create_date_constr(ctx, object_prototype, &ctx->date_constr);
977 if(FAILED(hres))
978 return hres;
980 hres = jsdisp_define_data_property(ctx->global, L"Date", PROPF_WRITABLE,
981 jsval_obj(ctx->date_constr));
982 if(FAILED(hres))
983 return hres;
985 hres = create_enumerator_constr(ctx, object_prototype, &ctx->enumerator_constr);
986 if(FAILED(hres))
987 return hres;
989 hres = jsdisp_define_data_property(ctx->global, L"Enumerator", PROPF_WRITABLE,
990 jsval_obj(ctx->enumerator_constr));
991 if(FAILED(hres))
992 return hres;
994 hres = init_error_constr(ctx, object_prototype);
995 if(FAILED(hres))
996 return hres;
998 hres = jsdisp_define_data_property(ctx->global, L"Error", PROPF_WRITABLE,
999 jsval_obj(ctx->error_constr));
1000 if(FAILED(hres))
1001 return hres;
1003 hres = jsdisp_define_data_property(ctx->global, L"EvalError", PROPF_WRITABLE,
1004 jsval_obj(ctx->eval_error_constr));
1005 if(FAILED(hres))
1006 return hres;
1008 hres = jsdisp_define_data_property(ctx->global, L"RangeError", PROPF_WRITABLE,
1009 jsval_obj(ctx->range_error_constr));
1010 if(FAILED(hres))
1011 return hres;
1013 hres = jsdisp_define_data_property(ctx->global, L"ReferenceError", PROPF_WRITABLE,
1014 jsval_obj(ctx->reference_error_constr));
1015 if(FAILED(hres))
1016 return hres;
1018 hres = jsdisp_define_data_property(ctx->global, L"RegExpError", PROPF_WRITABLE,
1019 jsval_obj(ctx->regexp_error_constr));
1020 if(FAILED(hres))
1021 return hres;
1023 hres = jsdisp_define_data_property(ctx->global, L"SyntaxError", PROPF_WRITABLE,
1024 jsval_obj(ctx->syntax_error_constr));
1025 if(FAILED(hres))
1026 return hres;
1028 hres = jsdisp_define_data_property(ctx->global, L"TypeError", PROPF_WRITABLE,
1029 jsval_obj(ctx->type_error_constr));
1030 if(FAILED(hres))
1031 return hres;
1033 hres = jsdisp_define_data_property(ctx->global, L"URIError", PROPF_WRITABLE,
1034 jsval_obj(ctx->uri_error_constr));
1035 if(FAILED(hres))
1036 return hres;
1038 hres = create_number_constr(ctx, object_prototype, &ctx->number_constr);
1039 if(FAILED(hres))
1040 return hres;
1042 hres = jsdisp_define_data_property(ctx->global, L"Number", PROPF_WRITABLE,
1043 jsval_obj(ctx->number_constr));
1044 if(FAILED(hres))
1045 return hres;
1047 hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr);
1048 if(FAILED(hres))
1049 return hres;
1051 hres = jsdisp_define_data_property(ctx->global, L"RegExp", PROPF_WRITABLE,
1052 jsval_obj(ctx->regexp_constr));
1053 if(FAILED(hres))
1054 return hres;
1056 hres = create_string_constr(ctx, object_prototype, &ctx->string_constr);
1057 if(FAILED(hres))
1058 return hres;
1060 hres = jsdisp_define_data_property(ctx->global, L"String", PROPF_WRITABLE,
1061 jsval_obj(ctx->string_constr));
1062 if(FAILED(hres))
1063 return hres;
1065 hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr);
1066 if(FAILED(hres))
1067 return hres;
1069 hres = jsdisp_define_data_property(ctx->global, L"VBArray", PROPF_WRITABLE,
1070 jsval_obj(ctx->vbarray_constr));
1071 if(FAILED(hres))
1072 return hres;
1074 return S_OK;
1077 HRESULT init_global(script_ctx_t *ctx)
1079 unsigned const_flags = ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? 0 : PROPF_WRITABLE;
1080 jsdisp_t *math, *constr;
1081 HRESULT hres;
1083 if(ctx->global)
1084 return S_OK;
1086 hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
1087 if(FAILED(hres))
1088 return hres;
1090 hres = create_object_prototype(ctx, &ctx->object_prototype);
1091 if(FAILED(hres))
1092 return hres;
1094 hres = init_constructors(ctx, ctx->object_prototype);
1095 if(FAILED(hres))
1096 return hres;
1098 hres = init_object_prototype_accessors(ctx, ctx->object_prototype);
1099 if(FAILED(hres))
1100 return hres;
1102 hres = create_math(ctx, &math);
1103 if(FAILED(hres))
1104 return hres;
1106 hres = jsdisp_define_data_property(ctx->global, L"Math", PROPF_WRITABLE, jsval_obj(math));
1107 jsdisp_release(math);
1108 if(FAILED(hres))
1109 return hres;
1111 if(ctx->version >= 2) {
1112 jsdisp_t *json;
1114 hres = create_json(ctx, &json);
1115 if(FAILED(hres))
1116 return hres;
1118 hres = jsdisp_define_data_property(ctx->global, L"JSON", PROPF_WRITABLE, jsval_obj(json));
1119 jsdisp_release(json);
1120 if(FAILED(hres))
1121 return hres;
1124 hres = create_activex_constr(ctx, &constr);
1125 if(FAILED(hres))
1126 return hres;
1128 hres = jsdisp_define_data_property(ctx->global, L"ActiveXObject", PROPF_WRITABLE,
1129 jsval_obj(constr));
1130 jsdisp_release(constr);
1131 if(FAILED(hres))
1132 return hres;
1134 hres = jsdisp_define_data_property(ctx->global, L"undefined", const_flags, jsval_undefined());
1135 if(FAILED(hres))
1136 return hres;
1138 hres = jsdisp_define_data_property(ctx->global, L"NaN", const_flags, jsval_number(NAN));
1139 if(FAILED(hres))
1140 return hres;
1142 hres = jsdisp_define_data_property(ctx->global, L"Infinity", const_flags, jsval_number(INFINITY));
1143 if(FAILED(hres))
1144 return hres;
1146 return init_set_constructor(ctx);