wbemprox: Implement IEnumWbemClassObject::Clone.
[wine] / dlls / jscript / global.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <math.h>
23 #include <limits.h>
24
25 #include "jscript.h"
26 #include "engine.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
31
32 #define LONGLONG_MAX (((LONGLONG)0x7fffffff<<32)|0xffffffff)
33
34 static const WCHAR NaNW[] = {'N','a','N',0};
35 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0};
36 static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
37 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0};
38 static const WCHAR DateW[] = {'D','a','t','e',0};
39 static const WCHAR ErrorW[] = {'E','r','r','o','r',0};
40 static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0};
41 static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0};
42 static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0};
43 static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0};
44 static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0};
45 static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0};
46 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0};
47 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0};
48 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
49 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
50 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0};
51 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0};
52 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0};
53 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0};
54 static const WCHAR escapeW[] = {'e','s','c','a','p','e',0};
55 static const WCHAR evalW[] = {'e','v','a','l',0};
56 static const WCHAR isNaNW[] = {'i','s','N','a','N',0};
57 static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0};
58 static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0};
59 static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0};
60 static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0};
61 static const WCHAR _GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0};
62 static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0};
63 static const WCHAR ScriptEngineMajorVersionW[] =
64     {'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};
65 static const WCHAR ScriptEngineMinorVersionW[] =
66     {'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};
67 static const WCHAR ScriptEngineBuildVersionW[] =
68     {'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};
69 static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0};
70 static const WCHAR MathW[] = {'M','a','t','h',0};
71 static const WCHAR encodeURIW[] = {'e','n','c','o','d','e','U','R','I',0};
72 static const WCHAR decodeURIW[] = {'d','e','c','o','d','e','U','R','I',0};
73 static const WCHAR encodeURIComponentW[] = {'e','n','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
74 static const WCHAR decodeURIComponentW[] = {'d','e','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0};
75
76 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
77
78 static int uri_char_table[] = {
79     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */
80     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */
81     0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */
82     2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */
83     1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */
84     2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */
85     0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */
86     2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */
87 };
88
89 /* 1 - reserved */
90 /* 2 - unescaped */
91
92 static inline BOOL is_uri_reserved(WCHAR c)
93 {
94     return c < 128 && uri_char_table[c] == 1;
95 }
96
97 static inline BOOL is_uri_unescaped(WCHAR c)
98 {
99     return c < 128 && uri_char_table[c] == 2;
100 }
101
102 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
103 static inline BOOL is_ecma_nonblank(const WCHAR c)
104 {
105     return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
106         c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/');
107 }
108
109 static WCHAR int_to_char(int i)
110 {
111     if(i < 10)
112         return '0'+i;
113     return 'A'+i-10;
114 }
115
116 static HRESULT constructor_call(jsdisp_t *constr, WORD flags, unsigned argc, VARIANT *argv,
117         VARIANT *retv, jsexcept_t *ei)
118 {
119     if(flags != DISPATCH_PROPERTYGET)
120         return jsdisp_call_value(constr, NULL, flags, argc, argv, retv, ei);
121
122     jsdisp_addref(constr);
123     var_set_jsdisp(retv, constr);
124     return S_OK;
125 }
126
127 static HRESULT JSGlobal_Array(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
128         VARIANT *retv, jsexcept_t *ei)
129 {
130     TRACE("\n");
131
132     return constructor_call(ctx->array_constr, flags, argc, argv, retv, ei);
133 }
134
135 static HRESULT JSGlobal_Boolean(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
136         VARIANT *retv, jsexcept_t *ei)
137 {
138     TRACE("\n");
139
140     return constructor_call(ctx->bool_constr, flags, argc, argv, retv, ei);
141 }
142
143 static HRESULT JSGlobal_Date(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
144         VARIANT *retv, jsexcept_t *ei)
145 {
146     TRACE("\n");
147
148     return constructor_call(ctx->date_constr, flags, argc, argv, retv, ei);
149 }
150
151 static HRESULT JSGlobal_Error(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
152         VARIANT *retv, jsexcept_t *ei)
153 {
154     TRACE("\n");
155
156     return constructor_call(ctx->error_constr, flags, argc, argv, retv, ei);
157 }
158
159 static HRESULT JSGlobal_EvalError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
160         VARIANT *retv, jsexcept_t *ei)
161 {
162     TRACE("\n");
163
164     return constructor_call(ctx->eval_error_constr, flags, argc, argv, retv, ei);
165 }
166
167 static HRESULT JSGlobal_RangeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
168         VARIANT *retv, jsexcept_t *ei)
169 {
170     TRACE("\n");
171
172     return constructor_call(ctx->range_error_constr, flags, argc, argv, retv, ei);
173 }
174
175 static HRESULT JSGlobal_ReferenceError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
176         VARIANT *retv, jsexcept_t *ei)
177 {
178     TRACE("\n");
179
180     return constructor_call(ctx->reference_error_constr, flags, argc, argv, retv, ei);
181 }
182
183 static HRESULT JSGlobal_SyntaxError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
184         VARIANT *retv, jsexcept_t *ei)
185 {
186     TRACE("\n");
187
188     return constructor_call(ctx->syntax_error_constr, flags, argc, argv, retv, ei);
189 }
190
191 static HRESULT JSGlobal_TypeError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
192         VARIANT *retv, jsexcept_t *ei)
193 {
194     TRACE("\n");
195
196     return constructor_call(ctx->type_error_constr, flags, argc, argv, retv, ei);
197 }
198
199 static HRESULT JSGlobal_URIError(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
200         VARIANT *retv, jsexcept_t *ei)
201 {
202     TRACE("\n");
203
204     return constructor_call(ctx->uri_error_constr, flags, argc, argv, retv, ei);
205 }
206
207 static HRESULT JSGlobal_Function(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
208         VARIANT *retv, jsexcept_t *ei)
209 {
210     TRACE("\n");
211
212     return constructor_call(ctx->function_constr, flags, argc, argv, retv, ei);
213 }
214
215 static HRESULT JSGlobal_Number(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
216         VARIANT *retv, jsexcept_t *ei)
217 {
218     TRACE("\n");
219
220     return constructor_call(ctx->number_constr, flags, argc, argv, retv, ei);
221 }
222
223 static HRESULT JSGlobal_Object(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
224         VARIANT *retv, jsexcept_t *ei)
225 {
226     TRACE("\n");
227
228     return constructor_call(ctx->object_constr, flags, argc, argv, retv, ei);
229 }
230
231 static HRESULT JSGlobal_String(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
232         VARIANT *retv, jsexcept_t *ei)
233 {
234     TRACE("\n");
235
236     return constructor_call(ctx->string_constr, flags, argc, argv, retv, ei);
237 }
238
239 static HRESULT JSGlobal_RegExp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
240         VARIANT *retv, jsexcept_t *ei)
241 {
242     TRACE("\n");
243
244     return constructor_call(ctx->regexp_constr, flags, argc, argv, retv, ei);
245 }
246
247 static HRESULT JSGlobal_ActiveXObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
248         VARIANT *retv, jsexcept_t *ei)
249 {
250     TRACE("\n");
251
252     return constructor_call(ctx->activex_constr, flags, argc, argv, retv, ei);
253 }
254
255 static HRESULT JSGlobal_VBArray(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
256         VARIANT *retv, jsexcept_t *ei)
257 {
258     TRACE("\n");
259
260     return constructor_call(ctx->vbarray_constr, flags, argc, argv, retv, ei);
261 }
262
263 static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
264         VARIANT *retv, jsexcept_t *ei)
265 {
266     FIXME("\n");
267     return E_NOTIMPL;
268 }
269
270 static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
271         VARIANT *retv, jsexcept_t *ei)
272 {
273     BSTR ret, str;
274     const WCHAR *ptr;
275     DWORD len = 0;
276     HRESULT hres;
277
278     TRACE("\n");
279
280     if(!argc) {
281         if(retv) {
282             ret = SysAllocString(undefinedW);
283             if(!ret)
284                 return E_OUTOFMEMORY;
285
286             V_VT(retv) = VT_BSTR;
287             V_BSTR(retv) = ret;
288         }
289
290         return S_OK;
291     }
292
293     hres = to_string(ctx, argv, ei, &str);
294     if(FAILED(hres))
295         return hres;
296
297     for(ptr=str; *ptr; ptr++) {
298         if(*ptr > 0xff)
299             len += 6;
300         else if(is_ecma_nonblank(*ptr))
301             len++;
302         else
303             len += 3;
304     }
305
306     ret = SysAllocStringLen(NULL, len);
307     if(!ret) {
308         SysFreeString(str);
309         return E_OUTOFMEMORY;
310     }
311
312     len = 0;
313     for(ptr=str; *ptr; ptr++) {
314         if(*ptr > 0xff) {
315             ret[len++] = '%';
316             ret[len++] = 'u';
317             ret[len++] = int_to_char(*ptr >> 12);
318             ret[len++] = int_to_char((*ptr >> 8) & 0xf);
319             ret[len++] = int_to_char((*ptr >> 4) & 0xf);
320             ret[len++] = int_to_char(*ptr & 0xf);
321         }
322         else if(is_ecma_nonblank(*ptr))
323             ret[len++] = *ptr;
324         else {
325             ret[len++] = '%';
326             ret[len++] = int_to_char(*ptr >> 4);
327             ret[len++] = int_to_char(*ptr & 0xf);
328         }
329     }
330
331     SysFreeString(str);
332
333     if(retv) {
334         V_VT(retv) = VT_BSTR;
335         V_BSTR(retv) = ret;
336     }
337     else
338         SysFreeString(ret);
339
340     return S_OK;
341 }
342
343 /* ECMA-262 3rd Edition    15.1.2.1 */
344 static HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
345         VARIANT *retv, jsexcept_t *ei)
346 {
347     bytecode_t *code;
348     HRESULT hres;
349
350     TRACE("\n");
351
352     if(!argc) {
353         if(retv)
354             V_VT(retv) = VT_EMPTY;
355         return S_OK;
356     }
357
358     if(V_VT(argv) != VT_BSTR) {
359         if(retv) {
360             V_VT(retv) = VT_EMPTY;
361             return VariantCopy(retv, argv);
362         }
363         return S_OK;
364     }
365
366     if(!ctx->exec_ctx) {
367         FIXME("No active exec_ctx\n");
368         return E_UNEXPECTED;
369     }
370
371     TRACE("parsing %s\n", debugstr_w(V_BSTR(argv)));
372     hres = compile_script(ctx, V_BSTR(argv), NULL, TRUE, FALSE, &code);
373     if(FAILED(hres)) {
374         WARN("parse (%s) failed: %08x\n", debugstr_w(V_BSTR(argv)), hres);
375         return throw_syntax_error(ctx, ei, hres, NULL);
376     }
377
378     hres = exec_source(ctx->exec_ctx, code, &code->global_code, TRUE, ei, retv);
379
380     release_bytecode(code);
381     return hres;
382 }
383
384 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
385         VARIANT *retv, jsexcept_t *ei)
386 {
387     VARIANT_BOOL ret = VARIANT_TRUE;
388     double n;
389     HRESULT hres;
390
391     TRACE("\n");
392
393     if(argc) {
394         hres = to_number(ctx, argv, ei, &n);
395         if(FAILED(hres))
396             return hres;
397
398         if(!isnan(n))
399             ret = VARIANT_FALSE;
400     }
401
402     if(retv) {
403         V_VT(retv) = VT_BOOL;
404         V_BOOL(retv) = ret;
405     }
406     return S_OK;
407 }
408
409 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
410         VARIANT *retv, jsexcept_t *ei)
411 {
412     VARIANT_BOOL ret = VARIANT_FALSE;
413     HRESULT hres;
414
415     TRACE("\n");
416
417     if(argc) {
418         double n;
419
420         hres = to_number(ctx, argv, ei, &n);
421         if(FAILED(hres))
422             return hres;
423
424         if(!isinf(n) && !isnan(n))
425             ret = VARIANT_TRUE;
426     }
427
428     if(retv) {
429         V_VT(retv) = VT_BOOL;
430         V_BOOL(retv) = ret;
431     }
432     return S_OK;
433 }
434
435 static INT char_to_int(WCHAR c)
436 {
437     if('0' <= c && c <= '9')
438         return c - '0';
439     if('a' <= c && c <= 'z')
440         return c - 'a' + 10;
441     if('A' <= c && c <= 'Z')
442         return c - 'A' + 10;
443     return 100;
444 }
445
446 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
447         VARIANT *retv, jsexcept_t *ei)
448 {
449     BOOL neg = FALSE, empty = TRUE;
450     DOUBLE ret = 0.0;
451     INT radix=0, i;
452     WCHAR *ptr;
453     BSTR str;
454     HRESULT hres;
455
456     if(!argc) {
457         if(retv) num_set_val(retv, NAN);
458         return S_OK;
459     }
460
461     if(argc >= 2) {
462         hres = to_int32(ctx, argv+1, ei, &radix);
463         if(FAILED(hres))
464             return hres;
465
466         if(radix && (radix < 2 || radix > 36)) {
467             WARN("radix %d out of range\n", radix);
468             if(retv)
469                 num_set_val(retv, NAN);
470             return S_OK;
471         }
472     }
473
474     hres = to_string(ctx, argv, ei, &str);
475     if(FAILED(hres))
476         return hres;
477
478     for(ptr = str; isspaceW(*ptr); ptr++);
479
480     switch(*ptr) {
481     case '+':
482         ptr++;
483         break;
484     case '-':
485         neg = TRUE;
486         ptr++;
487         break;
488     }
489
490     if(!radix) {
491         if(*ptr == '0') {
492             if(ptr[1] == 'x' || ptr[1] == 'X') {
493                 radix = 16;
494                 ptr += 2;
495             }else {
496                 radix = 8;
497                 ptr++;
498                 empty = FALSE;
499             }
500         }else {
501             radix = 10;
502         }
503     }
504
505     i = char_to_int(*ptr++);
506     if(i < radix) {
507         do {
508             ret = ret*radix + i;
509             i = char_to_int(*ptr++);
510         }while(i < radix);
511     }else if(empty) {
512         ret = NAN;
513     }
514
515     SysFreeString(str);
516
517     if(neg)
518         ret = -ret;
519
520     if(retv)
521         num_set_val(retv, ret);
522     return S_OK;
523 }
524
525 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
526         VARIANT *retv, jsexcept_t *ei)
527 {
528     LONGLONG d = 0, hlp;
529     int exp = 0;
530     WCHAR *str;
531     BSTR val_str = NULL;
532     BOOL ret_nan = TRUE, positive = TRUE;
533     HRESULT hres;
534
535     if(!argc) {
536         if(retv)
537             num_set_val(retv, NAN);
538         return S_OK;
539     }
540
541     hres = to_string(ctx, argv, ei, &val_str);
542     if(FAILED(hres))
543         return hres;
544
545     str = val_str;
546
547     while(isspaceW(*str)) str++;
548
549     if(*str == '+')
550         str++;
551     else if(*str == '-') {
552         positive = FALSE;
553         str++;
554     }
555
556     if(isdigitW(*str))
557         ret_nan = FALSE;
558
559     while(isdigitW(*str)) {
560         hlp = d*10 + *(str++) - '0';
561         if(d>LONGLONG_MAX/10 || hlp<0) {
562             exp++;
563             break;
564         }
565         else
566             d = hlp;
567     }
568     while(isdigitW(*str)) {
569         exp++;
570         str++;
571     }
572
573     if(*str == '.') str++;
574
575     if(isdigitW(*str))
576         ret_nan = FALSE;
577
578     while(isdigitW(*str)) {
579         hlp = d*10 + *(str++) - '0';
580         if(d>LONGLONG_MAX/10 || hlp<0)
581             break;
582
583         d = hlp;
584         exp--;
585     }
586     while(isdigitW(*str))
587         str++;
588
589     if(*str && !ret_nan && (*str=='e' || *str=='E')) {
590         int sign = 1, e = 0;
591
592         str++;
593         if(*str == '+')
594             str++;
595         else if(*str == '-') {
596             sign = -1;
597             str++;
598         }
599
600         while(isdigitW(*str)) {
601             if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0)
602                 e = INT_MAX;
603         }
604         e *= sign;
605
606         if(exp<0 && e<0 && exp+e>0) exp = INT_MIN;
607         else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
608         else exp += e;
609     }
610
611     SysFreeString(val_str);
612
613     if(ret_nan) {
614         if(retv)
615             num_set_val(retv, NAN);
616         return S_OK;
617     }
618
619     V_VT(retv) = VT_R8;
620     if(!positive)
621         d = -d;
622     V_R8(retv) = (exp>0 ? d*pow(10, exp) : d/pow(10, -exp));
623     return S_OK;
624 }
625
626 static inline int hex_to_int(const WCHAR wch) {
627     if(toupperW(wch)>='A' && toupperW(wch)<='F') return toupperW(wch)-'A'+10;
628     if(isdigitW(wch)) return wch-'0';
629     return -1;
630 }
631
632 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
633         VARIANT *retv, jsexcept_t *ei)
634 {
635     BSTR ret, str;
636     const WCHAR *ptr;
637     DWORD len = 0;
638     HRESULT hres;
639
640     TRACE("\n");
641
642     if(!argc) {
643         if(retv) {
644             ret = SysAllocString(undefinedW);
645             if(!ret)
646                 return E_OUTOFMEMORY;
647
648             V_VT(retv) = VT_BSTR;
649             V_BSTR(retv) = ret;
650         }
651
652         return S_OK;
653     }
654
655     hres = to_string(ctx, argv, ei, &str);
656     if(FAILED(hres))
657         return hres;
658
659     for(ptr=str; *ptr; ptr++) {
660         if(*ptr == '%') {
661             if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1)
662                 ptr += 2;
663             else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
664                     && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1)
665                 ptr += 5;
666         }
667
668         len++;
669     }
670
671     ret = SysAllocStringLen(NULL, len);
672     if(!ret) {
673         SysFreeString(str);
674         return E_OUTOFMEMORY;
675     }
676
677     len = 0;
678     for(ptr=str; *ptr; ptr++) {
679         if(*ptr == '%') {
680             if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) {
681                 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2));
682                 ptr += 2;
683             }
684             else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1
685                     && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) {
686                 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8)
687                     + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5));
688                 ptr += 5;
689             }
690             else
691                 ret[len] = *ptr;
692         }
693         else
694             ret[len] = *ptr;
695
696         len++;
697     }
698
699     SysFreeString(str);
700
701     if(retv) {
702         V_VT(retv) = VT_BSTR;
703         V_BSTR(retv) = ret;
704     }
705     else
706         SysFreeString(ret);
707
708     return S_OK;
709 }
710
711 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
712         VARIANT *retv, jsexcept_t *ei)
713 {
714     FIXME("\n");
715     return E_NOTIMPL;
716 }
717
718 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
719         VARIANT *retv, jsexcept_t *ei)
720 {
721     static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0};
722
723     TRACE("\n");
724
725     if(retv) {
726         BSTR ret;
727
728         ret = SysAllocString(JScriptW);
729         if(!ret)
730             return E_OUTOFMEMORY;
731
732         V_VT(retv) = VT_BSTR;
733         V_BSTR(retv) = ret;
734     }
735
736     return S_OK;
737 }
738
739 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
740         VARIANT *retv, jsexcept_t *ei)
741 {
742     TRACE("\n");
743
744     if(retv)
745         num_set_int(retv, JSCRIPT_MAJOR_VERSION);
746     return S_OK;
747 }
748
749 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
750         VARIANT *retv, jsexcept_t *ei)
751 {
752     TRACE("\n");
753
754     if(retv)
755         num_set_int(retv, JSCRIPT_MINOR_VERSION);
756     return S_OK;
757 }
758
759 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
760         VARIANT *retv, jsexcept_t *ei)
761 {
762     TRACE("\n");
763
764     if(retv)
765         num_set_int(retv, JSCRIPT_BUILD_VERSION);
766     return S_OK;
767 }
768
769 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
770         VARIANT *retv, jsexcept_t *ei)
771 {
772     FIXME("\n");
773     return E_NOTIMPL;
774 }
775
776 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
777         VARIANT *retv, jsexcept_t *ei)
778 {
779     const WCHAR *ptr;
780     DWORD len = 0, i;
781     char buf[4];
782     BSTR str, ret;
783     WCHAR *rptr;
784     HRESULT hres;
785
786     TRACE("\n");
787
788     if(!argc) {
789         if(retv) {
790             ret = SysAllocString(undefinedW);
791             if(!ret)
792                 return E_OUTOFMEMORY;
793
794             V_VT(retv) = VT_BSTR;
795             V_BSTR(retv) = ret;
796         }
797
798         return S_OK;
799     }
800
801     hres = to_string(ctx, argv, ei, &str);
802     if(FAILED(hres))
803         return hres;
804
805     for(ptr = str; *ptr; ptr++) {
806         if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
807             len++;
808         }else {
809             i = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL)*3;
810             if(!i) {
811                 SysFreeString(str);
812                 return throw_uri_error(ctx, ei, JS_E_INVALID_URI_CHAR, NULL);
813             }
814
815             len += i;
816         }
817     }
818
819     rptr = ret = SysAllocStringLen(NULL, len);
820     if(!ret) {
821         SysFreeString(str);
822         return E_OUTOFMEMORY;
823     }
824
825     for(ptr = str; *ptr; ptr++) {
826         if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') {
827             *rptr++ = *ptr;
828         }else {
829             len = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
830             for(i=0; i<len; i++) {
831                 *rptr++ = '%';
832                 *rptr++ = int_to_char((BYTE)buf[i] >> 4);
833                 *rptr++ = int_to_char(buf[i] & 0x0f);
834             }
835         }
836     }
837
838     TRACE("%s -> %s\n", debugstr_w(str), debugstr_w(ret));
839     SysFreeString(str);
840
841     if(retv) {
842         V_VT(retv) = VT_BSTR;
843         V_BSTR(retv) = ret;
844     }else {
845         SysFreeString(ret);
846     }
847     return S_OK;
848 }
849
850 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
851         VARIANT *retv, jsexcept_t *ei)
852 {
853     BSTR str, ret;
854     WCHAR *ptr;
855     int i, len = 0, val, res;
856     char buf[4];
857     WCHAR out;
858     HRESULT hres;
859
860     TRACE("\n");
861
862     if(!argc) {
863         if(retv) {
864             ret = SysAllocString(undefinedW);
865             if(!ret)
866                 return E_OUTOFMEMORY;
867
868             V_VT(retv) = VT_BSTR;
869             V_BSTR(retv) = ret;
870         }
871
872         return S_OK;
873     }
874
875     hres = to_string(ctx, argv, ei, &str);
876     if(FAILED(hres))
877         return hres;
878
879     for(ptr=str; *ptr; ptr++) {
880         if(*ptr != '%') {
881             len++;
882         }else {
883             res = 0;
884             for(i=0; i<4; i++) {
885                 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
886                     break;
887                 val += hex_to_int(ptr[i*3+1])<<4;
888                 buf[i] = val;
889
890                 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, &out, 1);
891                 if(res)
892                     break;
893             }
894
895             if(!res) {
896                 SysFreeString(str);
897                 return throw_uri_error(ctx, ei, JS_E_INVALID_URI_CODING, NULL);
898             }
899
900             ptr += i*3+2;
901             len++;
902         }
903     }
904
905     ret = SysAllocStringLen(NULL, len);
906     if(!ret) {
907         SysFreeString(str);
908         return E_OUTOFMEMORY;
909     }
910
911     len = 0;
912     for(ptr=str; *ptr; ptr++) {
913         if(*ptr != '%') {
914             ret[len] = *ptr;
915             len++;
916         }else {
917             for(i=0; i<4; i++) {
918                 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1)
919                     break;
920                 val += hex_to_int(ptr[i*3+1])<<4;
921                 buf[i] = val;
922
923                 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, ret+len, 1);
924                 if(res)
925                     break;
926             }
927
928             ptr += i*3+2;
929             len++;
930         }
931     }
932
933     TRACE("%s -> %s\n", debugstr_w(str), debugstr_w(ret));
934     SysFreeString(str);
935
936     if(retv) {
937         V_VT(retv) = VT_BSTR;
938         V_BSTR(retv) = ret;
939     }else {
940         SysFreeString(ret);
941     }
942
943     return S_OK;
944 }
945
946 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
947         VARIANT *retv, jsexcept_t *ei)
948 {
949     BSTR str, ret;
950     char buf[4];
951     const WCHAR *ptr;
952     DWORD len = 0, size, i;
953     HRESULT hres;
954
955     TRACE("\n");
956
957     if(!argc) {
958         if(retv) {
959             ret = SysAllocString(undefinedW);
960             if(!ret)
961                 return E_OUTOFMEMORY;
962
963             V_VT(retv) = VT_BSTR;
964             V_BSTR(retv) = ret;
965         }
966
967         return S_OK;
968     }
969
970     hres = to_string(ctx, argv, ei, &str);
971     if(FAILED(hres))
972         return hres;
973
974     for(ptr=str; *ptr; ptr++) {
975         if(is_uri_unescaped(*ptr))
976             len++;
977         else {
978             size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL);
979             if(!size) {
980                 SysFreeString(str);
981                 return throw_uri_error(ctx, ei, JS_E_INVALID_URI_CHAR, NULL);
982             }
983             len += size*3;
984         }
985     }
986
987     ret = SysAllocStringLen(NULL, len);
988     if(!ret) {
989         SysFreeString(str);
990         return E_OUTOFMEMORY;
991     }
992
993     len = 0;
994     for(ptr=str; *ptr; ptr++) {
995         if(is_uri_unescaped(*ptr))
996             ret[len++] = *ptr;
997         else {
998             size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL);
999             for(i=0; i<size; i++) {
1000                 ret[len++] = '%';
1001                 ret[len++] = int_to_char((BYTE)buf[i] >> 4);
1002                 ret[len++] = int_to_char(buf[i] & 0x0f);
1003             }
1004         }
1005     }
1006
1007     SysFreeString(str);
1008
1009     if(retv) {
1010         V_VT(retv) = VT_BSTR;
1011         V_BSTR(retv) = ret;
1012     } else {
1013         SysFreeString(ret);
1014     }
1015
1016     return S_OK;
1017 }
1018
1019 /* ECMA-262 3rd Edition    15.1.3.2 */
1020 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, VARIANT *argv,
1021         VARIANT *retv, jsexcept_t *ei)
1022 {
1023     BSTR str, ret;
1024     const WCHAR *ptr;
1025     WCHAR *out_ptr;
1026     DWORD len = 0;
1027     HRESULT hres;
1028
1029     TRACE("\n");
1030
1031     if(!argc) {
1032         if(retv) {
1033             ret = SysAllocString(undefinedW);
1034             if(!ret)
1035                 return E_OUTOFMEMORY;
1036
1037             V_VT(retv) = VT_BSTR;
1038             V_BSTR(retv) = ret;
1039         }
1040
1041         return S_OK;
1042     }
1043
1044     hres = to_string(ctx, argv, ei, &str);
1045     if(FAILED(hres))
1046         return hres;
1047
1048     ptr = str;
1049     while(*ptr) {
1050         if(*ptr == '%') {
1051             char octets[4];
1052             unsigned char mask = 0x80;
1053             int i, size, num_bytes = 0;
1054             if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
1055                 FIXME("Throw URIError: Invalid hex sequence\n");
1056                 SysFreeString(str);
1057                 return E_FAIL;
1058             }
1059             octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
1060             ptr += 3;
1061             while(octets[0] & mask) {
1062                 mask = mask >> 1;
1063                 ++num_bytes;
1064             }
1065             if(num_bytes == 1 || num_bytes > 4) {
1066                 FIXME("Throw URIError: Invalid initial UTF character\n");
1067                 SysFreeString(str);
1068                 return E_FAIL;
1069             }
1070             for(i = 1; i < num_bytes; ++i) {
1071                 if(*ptr != '%'){
1072                     FIXME("Throw URIError: Incomplete UTF sequence\n");
1073                     SysFreeString(str);
1074                     return E_FAIL;
1075                 }
1076                 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) {
1077                     FIXME("Throw URIError: Invalid hex sequence\n");
1078                     SysFreeString(str);
1079                     return E_FAIL;
1080                 }
1081                 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
1082                 ptr += 3;
1083             }
1084             size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
1085                     num_bytes ? num_bytes : 1, NULL, 0);
1086             if(size == 0) {
1087                 FIXME("Throw URIError: Invalid UTF sequence\n");
1088                 SysFreeString(str);
1089                 return E_FAIL;
1090             }
1091             len += size;
1092         }else {
1093             ++ptr;
1094             ++len;
1095         }
1096     }
1097
1098     out_ptr = ret = SysAllocStringLen(NULL, len);
1099     if(!ret) {
1100         SysFreeString(str);
1101         return E_OUTOFMEMORY;
1102     }
1103
1104     ptr = str;
1105     while(*ptr) {
1106         if(*ptr == '%') {
1107             char octets[4];
1108             unsigned char mask = 0x80;
1109             int i, size, num_bytes = 0;
1110             octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
1111             ptr += 3;
1112             while(octets[0] & mask) {
1113                 mask = mask >> 1;
1114                 ++num_bytes;
1115             }
1116             for(i = 1; i < num_bytes; ++i) {
1117                 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2));
1118                 ptr += 3;
1119             }
1120             size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets,
1121                     num_bytes ? num_bytes : 1, out_ptr, len);
1122             len -= size;
1123             out_ptr += size;
1124         }else {
1125             *out_ptr++ = *ptr++;
1126             --len;
1127         }
1128     }
1129
1130     SysFreeString(str);
1131
1132     if(retv) {
1133         V_VT(retv) = VT_BSTR;
1134         V_BSTR(retv) = ret;
1135     }else {
1136         SysFreeString(ret);
1137     }
1138
1139     return S_OK;
1140 }
1141
1142 static const builtin_prop_t JSGlobal_props[] = {
1143     {ActiveXObjectW,             JSGlobal_ActiveXObject,             PROPF_CONSTR|1},
1144     {ArrayW,                     JSGlobal_Array,                     PROPF_CONSTR|1},
1145     {BooleanW,                   JSGlobal_Boolean,                   PROPF_CONSTR|1},
1146     {CollectGarbageW,            JSGlobal_CollectGarbage,            PROPF_METHOD},
1147     {DateW,                      JSGlobal_Date,                      PROPF_CONSTR|7},
1148     {EnumeratorW,                JSGlobal_Enumerator,                PROPF_METHOD|7},
1149     {ErrorW,                     JSGlobal_Error,                     PROPF_CONSTR|1},
1150     {EvalErrorW,                 JSGlobal_EvalError,                 PROPF_CONSTR|1},
1151     {FunctionW,                  JSGlobal_Function,                  PROPF_CONSTR|1},
1152     {_GetObjectW,                JSGlobal_GetObject,                 PROPF_METHOD|2},
1153     {NumberW,                    JSGlobal_Number,                    PROPF_CONSTR|1},
1154     {ObjectW,                    JSGlobal_Object,                    PROPF_CONSTR|1},
1155     {RangeErrorW,                JSGlobal_RangeError,                PROPF_CONSTR|1},
1156     {ReferenceErrorW,            JSGlobal_ReferenceError,            PROPF_CONSTR|1},
1157     {RegExpW,                    JSGlobal_RegExp,                    PROPF_CONSTR|2},
1158     {ScriptEngineW,              JSGlobal_ScriptEngine,              PROPF_METHOD},
1159     {ScriptEngineBuildVersionW,  JSGlobal_ScriptEngineBuildVersion,  PROPF_METHOD},
1160     {ScriptEngineMajorVersionW,  JSGlobal_ScriptEngineMajorVersion,  PROPF_METHOD},
1161     {ScriptEngineMinorVersionW,  JSGlobal_ScriptEngineMinorVersion,  PROPF_METHOD},
1162     {StringW,                    JSGlobal_String,                    PROPF_CONSTR|1},
1163     {SyntaxErrorW,               JSGlobal_SyntaxError,               PROPF_CONSTR|1},
1164     {TypeErrorW,                 JSGlobal_TypeError,                 PROPF_CONSTR|1},
1165     {URIErrorW,                  JSGlobal_URIError,                  PROPF_CONSTR|1},
1166     {VBArrayW,                   JSGlobal_VBArray,                   PROPF_CONSTR|1},
1167     {decodeURIW,                 JSGlobal_decodeURI,                 PROPF_METHOD|1},
1168     {decodeURIComponentW,        JSGlobal_decodeURIComponent,        PROPF_METHOD|1},
1169     {encodeURIW,                 JSGlobal_encodeURI,                 PROPF_METHOD|1},
1170     {encodeURIComponentW,        JSGlobal_encodeURIComponent,        PROPF_METHOD|1},
1171     {escapeW,                    JSGlobal_escape,                    PROPF_METHOD|1},
1172     {evalW,                      JSGlobal_eval,                      PROPF_METHOD|1},
1173     {isFiniteW,                  JSGlobal_isFinite,                  PROPF_METHOD|1},
1174     {isNaNW,                     JSGlobal_isNaN,                     PROPF_METHOD|1},
1175     {parseFloatW,                JSGlobal_parseFloat,                PROPF_METHOD|1},
1176     {parseIntW,                  JSGlobal_parseInt,                  PROPF_METHOD|2},
1177     {unescapeW,                  JSGlobal_unescape,                  PROPF_METHOD|1}
1178 };
1179
1180 static const builtin_info_t JSGlobal_info = {
1181     JSCLASS_GLOBAL,
1182     {NULL, NULL, 0},
1183     sizeof(JSGlobal_props)/sizeof(*JSGlobal_props),
1184     JSGlobal_props,
1185     NULL,
1186     NULL
1187 };
1188
1189 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
1190 {
1191     HRESULT hres;
1192
1193     hres = init_function_constr(ctx, object_prototype);
1194     if(FAILED(hres))
1195         return hres;
1196
1197     hres = create_object_constr(ctx, object_prototype, &ctx->object_constr);
1198     if(FAILED(hres))
1199         return hres;
1200
1201     hres = create_activex_constr(ctx, &ctx->activex_constr);
1202     if(FAILED(hres))
1203         return hres;
1204
1205     hres = create_array_constr(ctx, object_prototype, &ctx->array_constr);
1206     if(FAILED(hres))
1207         return hres;
1208
1209     hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr);
1210     if(FAILED(hres))
1211         return hres;
1212
1213     hres = create_date_constr(ctx, object_prototype, &ctx->date_constr);
1214     if(FAILED(hres))
1215         return hres;
1216
1217     hres = init_error_constr(ctx, object_prototype);
1218     if(FAILED(hres))
1219         return hres;
1220
1221     hres = create_number_constr(ctx, object_prototype, &ctx->number_constr);
1222     if(FAILED(hres))
1223         return hres;
1224
1225     hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr);
1226     if(FAILED(hres))
1227         return hres;
1228
1229     hres = create_string_constr(ctx, object_prototype, &ctx->string_constr);
1230     if(FAILED(hres))
1231         return hres;
1232
1233     hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr);
1234     if(FAILED(hres))
1235         return hres;
1236
1237     return S_OK;
1238 }
1239
1240 HRESULT init_global(script_ctx_t *ctx)
1241 {
1242     jsdisp_t *math, *object_prototype;
1243     VARIANT var;
1244     HRESULT hres;
1245
1246     if(ctx->global)
1247         return S_OK;
1248
1249     hres = create_object_prototype(ctx, &object_prototype);
1250     if(FAILED(hres))
1251         return hres;
1252
1253     hres = init_constructors(ctx, object_prototype);
1254     jsdisp_release(object_prototype);
1255     if(FAILED(hres))
1256         return hres;
1257
1258     hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global);
1259     if(FAILED(hres))
1260         return hres;
1261
1262     hres = create_math(ctx, &math);
1263     if(FAILED(hres))
1264         return hres;
1265
1266     var_set_jsdisp(&var, math);
1267     hres = jsdisp_propput_name(ctx->global, MathW, &var, NULL/*FIXME*/);
1268     jsdisp_release(math);
1269     if(FAILED(hres))
1270         return hres;
1271
1272     V_VT(&var) = VT_EMPTY;
1273     hres = jsdisp_propput_name(ctx->global, undefinedW, &var, NULL/*FIXME*/);
1274     if(FAILED(hres))
1275         return hres;
1276
1277     num_set_val(&var, NAN);
1278     hres = jsdisp_propput_name(ctx->global, NaNW, &var, NULL/*FIXME*/);
1279     if(FAILED(hres))
1280         return hres;
1281
1282     num_set_val(&var, INFINITY);
1283     hres = jsdisp_propput_name(ctx->global, InfinityW, &var, NULL/*FIXME*/);
1284     return hres;
1285 }