makefiles: Replace the libwine makefile rules by variable declarations.
[wine.git] / dlls / jscript / global.c
blobdbfb95bf599effd54cbce12b19b518ac0ae99ca8
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <math.h>
23 #include <limits.h>
25 #include "jscript.h"
26 #include "engine.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
32 static const WCHAR NaNW[] = {'N','a','N',0};
33 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0};
34 static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
35 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0};
36 static const WCHAR DateW[] = {'D','a','t','e',0};
37 static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
38 static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
39 static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0};
40 static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0};
41 static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0};
42 static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0};
43 static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
44 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
45 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
46 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
47 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
48 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
49 static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0};
50 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
51 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
52 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
53 static const WCHAR escapeW[] = {'e','s','c','a','p','e',0};
54 static const WCHAR evalW[] = {'e','v','a','l',0};
55 static const WCHAR isNaNW[] = {'i','s','N','a','N',0};
56 static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0};
57 static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0};
58 static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0};
59 static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0};
60 static const WCHAR _GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0};
61 static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0};
62 static const WCHAR ScriptEngineMajorVersionW[] =
63 {'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};
64 static const WCHAR ScriptEngineMinorVersionW[] =
65 {'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};
66 static const WCHAR ScriptEngineBuildVersionW[] =
67 {'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};
68 static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0};
69 static const WCHAR MathW[] = {'M','a','t','h',0};
70 static const WCHAR encodeURIW[] = {'e','n','c','o','d','e','U','R','I',0};
71 static const WCHAR decodeURIW[] = {'d','e','c','o','d','e','U','R','I',0};
72 static const WCHAR encodeURIComponentW[] = {'e','n','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
73 static const WCHAR decodeURIComponentW[] = {'d','e','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
75 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
77 static int uri_char_table[] = {
78 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */
79 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */
80 0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */
81 2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */
82 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */
83 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */
84 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */
85 2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */
88 /* 1 - reserved */
89 /* 2 - unescaped */
91 static inline BOOL is_uri_reserved(WCHAR c)
93 return c < 128 && uri_char_table[c] == 1;
96 static inline BOOL is_uri_unescaped(WCHAR c)
98 return c < 128 && uri_char_table[c] == 2;
101 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
102 static inline BOOL is_ecma_nonblank(const WCHAR c)
104 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
105 c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
108 static WCHAR int_to_char(int i)
110 if(i < 10)
111 return '0'+i;
112 return 'A'+i-10;
115 static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
116 jsval_t *r)
118 FIXME("\n");
119 return E_NOTIMPL;
122 static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
123 jsval_t *r)
125 jsstr_t *ret_str, *str;
126 const WCHAR *ptr, *buf;
127 DWORD len = 0;
128 WCHAR *ret;
129 HRESULT hres;
131 TRACE("\n");
133 if(!argc) {
134 if(r)
135 *r = jsval_string(jsstr_undefined());
136 return S_OK;
139 hres = to_flat_string(ctx, argv[0], &str, &buf);
140 if(FAILED(hres))
141 return hres;
143 for(ptr = buf; *ptr; ptr++) {
144 if(*ptr > 0xff)
145 len += 6;
146 else if(is_ecma_nonblank(*ptr))
147 len++;
148 else
149 len += 3;
152 ret = jsstr_alloc_buf(len, &ret_str);
153 if(!ret) {
154 jsstr_release(str);
155 return E_OUTOFMEMORY;
158 len = 0;
159 for(ptr = buf; *ptr; ptr++) {
160 if(*ptr > 0xff) {
161 ret[len++] = '%';
162 ret[len++] = 'u';
163 ret[len++] = int_to_char(*ptr >> 12);
164 ret[len++] = int_to_char((*ptr >> 8) & 0xf);
165 ret[len++] = int_to_char((*ptr >> 4) & 0xf);
166 ret[len++] = int_to_char(*ptr & 0xf);
168 else if(is_ecma_nonblank(*ptr))
169 ret[len++] = *ptr;
170 else {
171 ret[len++] = '%';
172 ret[len++] = int_to_char(*ptr >> 4);
173 ret[len++] = int_to_char(*ptr & 0xf);
177 jsstr_release(str);
179 if(r)
180 *r = jsval_string(ret_str);
181 else
182 jsstr_release(ret_str);
183 return S_OK;
186 /* ECMA-262 3rd Edition 15.1.2.1 */
187 static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
188 jsval_t *r)
190 bytecode_t *code;
191 const WCHAR *src;
192 HRESULT hres;
194 TRACE("\n");
196 if(!argc) {
197 if(r)
198 *r = jsval_undefined();
199 return S_OK;
202 if(!is_string(argv[0])) {
203 if(r)
204 return jsval_copy(argv[0], r);
205 return S_OK;
208 if(!ctx->exec_ctx) {
209 FIXME("No active exec_ctx\n");
210 return E_UNEXPECTED;
213 src = jsstr_flatten(get_string(argv[0]));
214 if(!src)
215 return E_OUTOFMEMORY;
217 TRACE("parsing %s\n", debugstr_jsval(argv[0]));
218 hres = compile_script(ctx, src, NULL, NULL, TRUE, FALSE, &code);
219 if(FAILED(hres)) {
220 WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres);
221 return throw_syntax_error(ctx, hres, NULL);
224 hres = exec_source(ctx->exec_ctx, code, &code->global_code, TRUE, r);
225 release_bytecode(code);
226 return hres;
229 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
230 jsval_t *r)
232 BOOL ret = TRUE;
233 double n;
234 HRESULT hres;
236 TRACE("\n");
238 if(argc) {
239 hres = to_number(ctx, argv[0], &n);
240 if(FAILED(hres))
241 return hres;
243 if(!isnan(n))
244 ret = FALSE;
247 if(r)
248 *r = jsval_bool(ret);
249 return S_OK;
252 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
253 jsval_t *r)
255 BOOL ret = FALSE;
256 HRESULT hres;
258 TRACE("\n");
260 if(argc) {
261 double n;
263 hres = to_number(ctx, argv[0], &n);
264 if(FAILED(hres))
265 return hres;
267 if(!isinf(n) && !isnan(n))
268 ret = TRUE;
271 if(r)
272 *r = jsval_bool(ret);
273 return S_OK;
276 static INT char_to_int(WCHAR c)
278 if('0' <= c && c <= '9')
279 return c - '0';
280 if('a' <= c && c <= 'z')
281 return c - 'a' + 10;
282 if('A' <= c && c <= 'Z')
283 return c - 'A' + 10;
284 return 100;
287 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
288 jsval_t *r)
290 BOOL neg = FALSE, empty = TRUE;
291 const WCHAR *ptr;
292 DOUBLE ret = 0.0;
293 INT radix=0, i;
294 jsstr_t *str;
295 HRESULT hres;
297 if(!argc) {
298 if(r)
299 *r = jsval_number(NAN);
300 return S_OK;
303 if(argc >= 2) {
304 hres = to_int32(ctx, argv[1], &radix);
305 if(FAILED(hres))
306 return hres;
308 if(radix && (radix < 2 || radix > 36)) {
309 WARN("radix %d out of range\n", radix);
310 if(r)
311 *r = jsval_number(NAN);
312 return S_OK;
316 hres = to_flat_string(ctx, argv[0], &str, &ptr);
317 if(FAILED(hres))
318 return hres;
320 while(isspaceW(*ptr))
321 ptr++;
323 switch(*ptr) {
324 case '+':
325 ptr++;
326 break;
327 case '-':
328 neg = TRUE;
329 ptr++;
330 break;
333 if(!radix) {
334 if(*ptr == '0') {
335 if(ptr[1] == 'x' || ptr[1] == 'X') {
336 radix = 16;
337 ptr += 2;
338 }else {
339 radix = 8;
340 ptr++;
341 empty = FALSE;
343 }else {
344 radix = 10;
348 i = char_to_int(*ptr++);
349 if(i < radix) {
350 do {
351 ret = ret*radix + i;
352 i = char_to_int(*ptr++);
353 }while(i < radix);
354 }else if(empty) {
355 ret = NAN;
358 jsstr_release(str);
360 if(neg)
361 ret = -ret;
363 if(r)
364 *r = jsval_number(ret);
365 return S_OK;
368 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
369 jsval_t *r)
371 LONGLONG d = 0, hlp;
372 jsstr_t *val_str;
373 int exp = 0;
374 const WCHAR *str;
375 BOOL ret_nan = TRUE, positive = TRUE;
376 HRESULT hres;
378 if(!argc) {
379 if(r)
380 *r = jsval_number(NAN);
381 return S_OK;
384 hres = to_flat_string(ctx, argv[0], &val_str, &str);
385 if(FAILED(hres))
386 return hres;
388 while(isspaceW(*str)) str++;
390 if(*str == '+')
391 str++;
392 else if(*str == '-') {
393 positive = FALSE;
394 str++;
397 if(isdigitW(*str))
398 ret_nan = FALSE;
400 while(isdigitW(*str)) {
401 hlp = d*10 + *(str++) - '0';
402 if(d>MAXLONGLONG/10 || hlp<0) {
403 exp++;
404 break;
406 else
407 d = hlp;
409 while(isdigitW(*str)) {
410 exp++;
411 str++;
414 if(*str == '.') str++;
416 if(isdigitW(*str))
417 ret_nan = FALSE;
419 while(isdigitW(*str)) {
420 hlp = d*10 + *(str++) - '0';
421 if(d>MAXLONGLONG/10 || hlp<0)
422 break;
424 d = hlp;
425 exp--;
427 while(isdigitW(*str))
428 str++;
430 if(*str && !ret_nan && (*str=='e' || *str=='E')) {
431 int sign = 1, e = 0;
433 str++;
434 if(*str == '+')
435 str++;
436 else if(*str == '-') {
437 sign = -1;
438 str++;
441 while(isdigitW(*str)) {
442 if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0)
443 e = INT_MAX;
445 e *= sign;
447 if(exp<0 && e<0 && exp+e>0) exp = INT_MIN;
448 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
449 else exp += e;
452 jsstr_release(val_str);
454 if(ret_nan) {
455 if(r)
456 *r = jsval_number(NAN);
457 return S_OK;
460 if(!positive)
461 d = -d;
462 if(r)
463 *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
464 return S_OK;
467 static inline int hex_to_int(const WCHAR wch) {
468 if(toupperW(wch)>='A' && toupperW(wch)<='F') return toupperW(wch)-'A'+10;
469 if(isdigitW(wch)) return wch-'0';
470 return -1;
473 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
474 jsval_t *r)
476 jsstr_t *ret_str, *str;
477 const WCHAR *ptr, *buf;
478 DWORD len = 0;
479 WCHAR *ret;
480 HRESULT hres;
482 TRACE("\n");
484 if(!argc) {
485 if(r)
486 *r = jsval_string(jsstr_undefined());
487 return S_OK;
490 hres = to_flat_string(ctx, argv[0], &str, &buf);
491 if(FAILED(hres))
492 return hres;
494 for(ptr = buf; *ptr; ptr++) {
495 if(*ptr == '%') {
496 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
497 ptr += 2;
498 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
499 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1)
500 ptr += 5;
503 len++;
506 ret = jsstr_alloc_buf(len, &ret_str);
507 if(!ret) {
508 jsstr_release(str);
509 return E_OUTOFMEMORY;
512 len = 0;
513 for(ptr = buf; *ptr; ptr++) {
514 if(*ptr == '%') {
515 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
516 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
517 ptr += 2;
519 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
520 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) {
521 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8)
522 + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5));
523 ptr += 5;
525 else
526 ret[len] = *ptr;
528 else
529 ret[len] = *ptr;
531 len++;
534 jsstr_release(str);
536 if(r)
537 *r = jsval_string(ret_str);
538 else
539 jsstr_release(ret_str);
540 return S_OK;
543 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
544 jsval_t *r)
546 FIXME("\n");
547 return E_NOTIMPL;
550 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
551 jsval_t *r)
553 static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0};
555 TRACE("\n");
557 if(r) {
558 jsstr_t *ret;
560 ret = jsstr_alloc(JScriptW);
561 if(!ret)
562 return E_OUTOFMEMORY;
564 *r = jsval_string(ret);
567 return S_OK;
570 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
571 jsval_t *r)
573 TRACE("\n");
575 if(r)
576 *r = jsval_number(JSCRIPT_MAJOR_VERSION);
577 return S_OK;
580 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
581 jsval_t *r)
583 TRACE("\n");
585 if(r)
586 *r = jsval_number(JSCRIPT_MINOR_VERSION);
587 return S_OK;
590 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
591 jsval_t *r)
593 TRACE("\n");
595 if(r)
596 *r = jsval_number(JSCRIPT_BUILD_VERSION);
597 return S_OK;
600 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
601 jsval_t *r)
603 static int once = 0;
604 if (!once++)
605 FIXME(": stub\n");
606 return S_OK;
609 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
610 jsval_t *r)
612 const WCHAR *ptr, *uri;
613 jsstr_t *str, *ret;
614 DWORD len = 0, i;
615 char buf[4];
616 WCHAR *rptr;
617 HRESULT hres;
619 TRACE("\n");
621 if(!argc) {
622 if(r)
623 *r = jsval_string(jsstr_undefined());
624 return S_OK;
627 hres = to_flat_string(ctx, argv[0], &str, &uri);
628 if(FAILED(hres))
629 return hres;
631 for(ptr = uri; *ptr; ptr++) {
632 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
633 len++;
634 }else {
635 i = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL)*3;
636 if(!i) {
637 jsstr_release(str);
638 return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL);
641 len += i;
645 rptr = jsstr_alloc_buf(len, &ret);
646 if(!rptr) {
647 jsstr_release(str);
648 return E_OUTOFMEMORY;
651 for(ptr = uri; *ptr; ptr++) {
652 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
653 *rptr++ = *ptr;
654 }else {
655 len = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
656 for(i=0; i<len; i++) {
657 *rptr++ = '%';
658 *rptr++ = int_to_char((BYTE)buf[i] >> 4);
659 *rptr++ = int_to_char(buf[i] & 0x0f);
664 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret));
665 jsstr_release(str);
667 if(r)
668 *r = jsval_string(ret);
669 else
670 jsstr_release(ret);
671 return S_OK;
674 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
675 jsval_t *r)
677 const WCHAR *ptr, *uri;
678 jsstr_t *str, *ret_str;
679 unsigned len = 0;
680 int i, val, res;
681 WCHAR *ret;
682 char buf[4];
683 WCHAR out;
684 HRESULT hres;
686 TRACE("\n");
688 if(!argc) {
689 if(r)
690 *r = jsval_string(jsstr_undefined());
691 return S_OK;
694 hres = to_flat_string(ctx, argv[0], &str, &uri);
695 if(FAILED(hres))
696 return hres;
698 for(ptr = uri; *ptr; ptr++) {
699 if(*ptr != '%') {
700 len++;
701 }else {
702 res = 0;
703 for(i=0; i<4; i++) {
704 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
705 break;
706 val += hex_to_int(ptr[i*3+1])<<4;
707 buf[i] = val;
709 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, &out, 1);
710 if(res)
711 break;
714 if(!res) {
715 jsstr_release(str);
716 return throw_uri_error(ctx, JS_E_INVALID_URI_CODING, NULL);
719 ptr += i*3+2;
720 len++;
724 ret = jsstr_alloc_buf(len, &ret_str);
725 if(!ret) {
726 jsstr_release(str);
727 return E_OUTOFMEMORY;
730 for(ptr = uri; *ptr; ptr++) {
731 if(*ptr != '%') {
732 *ret++ = *ptr;
733 }else {
734 for(i=0; i<4; i++) {
735 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
736 break;
737 val += hex_to_int(ptr[i*3+1])<<4;
738 buf[i] = val;
740 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, ret, 1);
741 if(res)
742 break;
745 ptr += i*3+2;
746 ret++;
750 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret_str));
751 jsstr_release(str);
753 if(r)
754 *r = jsval_string(ret_str);
755 else
756 jsstr_release(ret_str);
757 return S_OK;
760 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
761 jsval_t *r)
763 jsstr_t *str, *ret_str;
764 char buf[4];
765 const WCHAR *ptr, *uri;
766 DWORD len = 0, size, i;
767 WCHAR *ret;
768 HRESULT hres;
770 TRACE("\n");
772 if(!argc) {
773 if(r)
774 *r = jsval_string(jsstr_undefined());
775 return S_OK;
778 hres = to_flat_string(ctx, argv[0], &str, &uri);
779 if(FAILED(hres))
780 return hres;
782 for(ptr = uri; *ptr; ptr++) {
783 if(is_uri_unescaped(*ptr))
784 len++;
785 else {
786 size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL);
787 if(!size) {
788 jsstr_release(str);
789 return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL);
791 len += size*3;
795 ret = jsstr_alloc_buf(len, &ret_str);
796 if(!ret) {
797 jsstr_release(str);
798 return E_OUTOFMEMORY;
801 for(ptr = uri; *ptr; ptr++) {
802 if(is_uri_unescaped(*ptr)) {
803 *ret++ = *ptr;
804 }else {
805 size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
806 for(i=0; i<size; i++) {
807 *ret++ = '%';
808 *ret++ = int_to_char((BYTE)buf[i] >> 4);
809 *ret++ = int_to_char(buf[i] & 0x0f);
814 jsstr_release(str);
816 if(r)
817 *r = jsval_string(ret_str);
818 else
819 jsstr_release(ret_str);
820 return S_OK;
823 /* ECMA-262 3rd Edition 15.1.3.2 */
824 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
825 jsval_t *r)
827 const WCHAR *ptr, *uri;
828 jsstr_t *str, *ret;
829 WCHAR *out_ptr;
830 DWORD len = 0;
831 HRESULT hres;
833 TRACE("\n");
835 if(!argc) {
836 if(r)
837 *r = jsval_string(jsstr_undefined());
838 return S_OK;
841 hres = to_flat_string(ctx, argv[0], &str, &uri);
842 if(FAILED(hres))
843 return hres;
845 ptr = uri;
846 while(*ptr) {
847 if(*ptr == '%') {
848 char octets[4];
849 unsigned char mask = 0x80;
850 int i, size, num_bytes = 0;
851 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
852 FIXME("Throw URIError: Invalid hex sequence\n");
853 jsstr_release(str);
854 return E_FAIL;
856 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
857 ptr += 3;
858 while(octets[0] & mask) {
859 mask = mask >> 1;
860 ++num_bytes;
862 if(num_bytes == 1 || num_bytes > 4) {
863 FIXME("Throw URIError: Invalid initial UTF character\n");
864 jsstr_release(str);
865 return E_FAIL;
867 for(i = 1; i < num_bytes; ++i) {
868 if(*ptr != '%'){
869 FIXME("Throw URIError: Incomplete UTF sequence\n");
870 jsstr_release(str);
871 return E_FAIL;
873 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
874 FIXME("Throw URIError: Invalid hex sequence\n");
875 jsstr_release(str);
876 return E_FAIL;
878 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
879 ptr += 3;
881 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
882 num_bytes ? num_bytes : 1, NULL, 0);
883 if(size == 0) {
884 FIXME("Throw URIError: Invalid UTF sequence\n");
885 jsstr_release(str);
886 return E_FAIL;
888 len += size;
889 }else {
890 ++ptr;
891 ++len;
895 out_ptr = jsstr_alloc_buf(len, &ret);
896 if(!ret) {
897 jsstr_release(str);
898 return E_OUTOFMEMORY;
901 ptr = uri;
902 while(*ptr) {
903 if(*ptr == '%') {
904 char octets[4];
905 unsigned char mask = 0x80;
906 int i, size, num_bytes = 0;
907 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
908 ptr += 3;
909 while(octets[0] & mask) {
910 mask = mask >> 1;
911 ++num_bytes;
913 for(i = 1; i < num_bytes; ++i) {
914 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
915 ptr += 3;
917 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
918 num_bytes ? num_bytes : 1, out_ptr, len);
919 len -= size;
920 out_ptr += size;
921 }else {
922 *out_ptr++ = *ptr++;
923 --len;
927 jsstr_release(str);
929 if(r)
930 *r = jsval_string(ret);
931 else
932 jsstr_release(ret);
933 return S_OK;
936 static const builtin_prop_t JSGlobal_props[] = {
937 {CollectGarbageW, JSGlobal_CollectGarbage, PROPF_METHOD},
938 {EnumeratorW, JSGlobal_Enumerator, PROPF_METHOD|7},
939 {_GetObjectW, JSGlobal_GetObject, PROPF_METHOD|2},
940 {ScriptEngineW, JSGlobal_ScriptEngine, PROPF_METHOD},
941 {ScriptEngineBuildVersionW, JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD},
942 {ScriptEngineMajorVersionW, JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD},
943 {ScriptEngineMinorVersionW, JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD},
944 {decodeURIW, JSGlobal_decodeURI, PROPF_METHOD|1},
945 {decodeURIComponentW, JSGlobal_decodeURIComponent, PROPF_METHOD|1},
946 {encodeURIW, JSGlobal_encodeURI, PROPF_METHOD|1},
947 {encodeURIComponentW, JSGlobal_encodeURIComponent, PROPF_METHOD|1},
948 {escapeW, JSGlobal_escape, PROPF_METHOD|1},
949 {evalW, JSGlobal_eval, PROPF_METHOD|1},
950 {isFiniteW, JSGlobal_isFinite, PROPF_METHOD|1},
951 {isNaNW, JSGlobal_isNaN, PROPF_METHOD|1},
952 {parseFloatW, JSGlobal_parseFloat, PROPF_METHOD|1},
953 {parseIntW, JSGlobal_parseInt, PROPF_METHOD|2},
954 {unescapeW, JSGlobal_unescape, PROPF_METHOD|1}
957 static const builtin_info_t JSGlobal_info = {
958 JSCLASS_GLOBAL,
959 {NULL, NULL, 0},
960 sizeof(JSGlobal_props)/sizeof(*JSGlobal_props),
961 JSGlobal_props,
962 NULL,
963 NULL
966 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
968 HRESULT hres;
970 hres = init_function_constr(ctx, object_prototype);
971 if(FAILED(hres))
972 return hres;
974 hres = jsdisp_propput_dontenum(ctx->global, FunctionW, jsval_obj(ctx->function_constr));
975 if(FAILED(hres))
976 return hres;
978 hres = create_object_constr(ctx, object_prototype, &ctx->object_constr);
979 if(FAILED(hres))
980 return hres;
982 hres = jsdisp_propput_dontenum(ctx->global, ObjectW, jsval_obj(ctx->object_constr));
983 if(FAILED(hres))
984 return hres;
986 hres = create_array_constr(ctx, object_prototype, &ctx->array_constr);
987 if(FAILED(hres))
988 return hres;
990 hres = jsdisp_propput_dontenum(ctx->global, ArrayW, jsval_obj(ctx->array_constr));
991 if(FAILED(hres))
992 return hres;
994 hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr);
995 if(FAILED(hres))
996 return hres;
998 hres = jsdisp_propput_dontenum(ctx->global, BooleanW, jsval_obj(ctx->bool_constr));
999 if(FAILED(hres))
1000 return hres;
1002 hres = create_date_constr(ctx, object_prototype, &ctx->date_constr);
1003 if(FAILED(hres))
1004 return hres;
1006 hres = jsdisp_propput_dontenum(ctx->global, DateW, jsval_obj(ctx->date_constr));
1007 if(FAILED(hres))
1008 return hres;
1010 hres = init_error_constr(ctx, object_prototype);
1011 if(FAILED(hres))
1012 return hres;
1014 hres = jsdisp_propput_dontenum(ctx->global, ErrorW, jsval_obj(ctx->error_constr));
1015 if(FAILED(hres))
1016 return hres;
1018 hres = jsdisp_propput_dontenum(ctx->global, EvalErrorW, jsval_obj(ctx->eval_error_constr));
1019 if(FAILED(hres))
1020 return hres;
1022 hres = jsdisp_propput_dontenum(ctx->global, RangeErrorW, jsval_obj(ctx->range_error_constr));
1023 if(FAILED(hres))
1024 return hres;
1026 hres = jsdisp_propput_dontenum(ctx->global, ReferenceErrorW, jsval_obj(ctx->reference_error_constr));
1027 if(FAILED(hres))
1028 return hres;
1030 hres = jsdisp_propput_dontenum(ctx->global, RegExpErrorW, jsval_obj(ctx->regexp_error_constr));
1031 if(FAILED(hres))
1032 return hres;
1034 hres = jsdisp_propput_dontenum(ctx->global, SyntaxErrorW, jsval_obj(ctx->syntax_error_constr));
1035 if(FAILED(hres))
1036 return hres;
1038 hres = jsdisp_propput_dontenum(ctx->global, TypeErrorW, jsval_obj(ctx->type_error_constr));
1039 if(FAILED(hres))
1040 return hres;
1042 hres = jsdisp_propput_dontenum(ctx->global, URIErrorW, jsval_obj(ctx->uri_error_constr));
1043 if(FAILED(hres))
1044 return hres;
1046 hres = create_number_constr(ctx, object_prototype, &ctx->number_constr);
1047 if(FAILED(hres))
1048 return hres;
1050 hres = jsdisp_propput_dontenum(ctx->global, NumberW, jsval_obj(ctx->number_constr));
1051 if(FAILED(hres))
1052 return hres;
1054 hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr);
1055 if(FAILED(hres))
1056 return hres;
1058 hres = jsdisp_propput_dontenum(ctx->global, RegExpW, 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_propput_dontenum(ctx->global, StringW, 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_propput_dontenum(ctx->global, VBArrayW, jsval_obj(ctx->vbarray_constr));
1075 if(FAILED(hres))
1076 return hres;
1078 return S_OK;
1081 HRESULT init_global(script_ctx_t *ctx)
1083 jsdisp_t *math, *object_prototype, *constr;
1084 HRESULT hres;
1086 if(ctx->global)
1087 return S_OK;
1089 hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
1090 if(FAILED(hres))
1091 return hres;
1093 hres = create_object_prototype(ctx, &object_prototype);
1094 if(FAILED(hres))
1095 return hres;
1097 hres = init_constructors(ctx, object_prototype);
1098 jsdisp_release(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_propput_dontenum(ctx->global, MathW, jsval_obj(math));
1107 jsdisp_release(math);
1108 if(FAILED(hres))
1109 return hres;
1111 hres = create_activex_constr(ctx, &constr);
1112 if(FAILED(hres))
1113 return hres;
1115 hres = jsdisp_propput_dontenum(ctx->global, ActiveXObjectW, jsval_obj(constr));
1116 jsdisp_release(constr);
1117 if(FAILED(hres))
1118 return hres;
1120 hres = jsdisp_propput_dontenum(ctx->global, undefinedW, jsval_undefined());
1121 if(FAILED(hres))
1122 return hres;
1124 hres = jsdisp_propput_dontenum(ctx->global, NaNW, jsval_number(NAN));
1125 if(FAILED(hres))
1126 return hres;
1128 hres = jsdisp_propput_dontenum(ctx->global, InfinityW, jsval_number(INFINITY));
1129 return hres;