jscript: Implement the String.sup() method.
[wine] / dlls / jscript / jsutils.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
24 #include "jscript.h"
25 #include "engine.h"
26
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
30
31 const char *debugstr_variant(const VARIANT *v)
32 {
33     switch(V_VT(v)) {
34     case VT_EMPTY:
35         return wine_dbg_sprintf("{VT_EMPTY}");
36     case VT_NULL:
37         return wine_dbg_sprintf("{VT_NULL}");
38     case VT_I4:
39         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
40     case VT_R8:
41         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
42     case VT_BSTR:
43         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
44     case VT_DISPATCH:
45         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
46     case VT_BOOL:
47         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
48     default:
49         return wine_dbg_sprintf("{vt %d}", V_VT(v));
50     }
51 }
52
53 #define MIN_BLOCK_SIZE  128
54
55 static inline DWORD block_size(DWORD block)
56 {
57     return MIN_BLOCK_SIZE << block;
58 }
59
60 void jsheap_init(jsheap_t *heap)
61 {
62     memset(heap, 0, sizeof(*heap));
63     list_init(&heap->custom_blocks);
64 }
65
66 void *jsheap_alloc(jsheap_t *heap, DWORD size)
67 {
68     struct list *list;
69     void *tmp;
70
71     if(!heap->block_cnt) {
72         if(!heap->blocks) {
73             heap->blocks = heap_alloc(sizeof(void*));
74             if(!heap->blocks)
75                 return NULL;
76         }
77
78         tmp = heap_alloc(block_size(0));
79         if(!tmp)
80             return NULL;
81
82         heap->blocks[0] = tmp;
83         heap->block_cnt = 1;
84     }
85
86     if(heap->offset + size < block_size(heap->last_block)) {
87         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
88         heap->offset += size;
89         return tmp;
90     }
91
92     if(size < block_size(heap->last_block+1)) {
93         if(heap->last_block+1 == heap->block_cnt) {
94             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
95             if(!tmp)
96                 return NULL;
97             heap->blocks = tmp;
98         }
99
100         tmp = heap_alloc(block_size(heap->block_cnt+1));
101         if(!tmp)
102             return NULL;
103
104         heap->blocks[heap->block_cnt++] = tmp;
105
106         heap->last_block++;
107         heap->offset = size;
108         return heap->blocks[heap->last_block];
109     }
110
111     list = heap_alloc(size + sizeof(struct list));
112     if(!list)
113         return NULL;
114
115     list_add_head(&heap->custom_blocks, list);
116     return list+1;
117 }
118
119 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
120 {
121     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
122        && heap->offset+inc < block_size(heap->last_block)) {
123         heap->offset += inc;
124         return mem;
125     }
126
127     return jsheap_alloc(heap, size+inc);
128 }
129
130 void jsheap_clear(jsheap_t *heap)
131 {
132     struct list *tmp;
133
134     if(!heap)
135         return;
136
137     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
138         list_remove(tmp);
139         heap_free(tmp);
140     }
141
142     heap->last_block = heap->offset = 0;
143 }
144
145 void jsheap_free(jsheap_t *heap)
146 {
147     DWORD i;
148
149     jsheap_clear(heap);
150
151     for(i=0; i < heap->block_cnt; i++)
152         heap_free(heap->blocks[i]);
153     heap_free(heap->blocks);
154
155     jsheap_init(heap);
156 }
157
158 jsheap_t *jsheap_mark(jsheap_t *heap)
159 {
160     if(heap->mark)
161         return NULL;
162
163     heap->mark = TRUE;
164     return heap;
165 }
166
167 /* ECMA-262 3rd Edition    9.1 */
168 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
169 {
170     switch(V_VT(v)) {
171     case VT_EMPTY:
172     case VT_NULL:
173     case VT_BOOL:
174     case VT_I4:
175     case VT_R8:
176         *ret = *v;
177         break;
178     case VT_BSTR:
179         V_VT(ret) = VT_BSTR;
180         V_BSTR(ret) = SysAllocString(V_BSTR(v));
181         break;
182     case VT_DISPATCH:
183         return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/);
184     default:
185         FIXME("Unimplemented for vt %d\n", V_VT(v));
186         return E_NOTIMPL;
187     }
188
189     return S_OK;
190 }
191
192 /* ECMA-262 3rd Edition    9.2 */
193 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
194 {
195     switch(V_VT(v)) {
196     case VT_EMPTY:
197     case VT_NULL:
198         *b = VARIANT_FALSE;
199         break;
200     case VT_I4:
201         *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
202         break;
203     case VT_R8:
204         *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
205         break;
206     case VT_BSTR:
207         *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
208         break;
209     case VT_DISPATCH:
210         *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
211         break;
212     case VT_BOOL:
213         *b = V_BOOL(v);
214         break;
215     default:
216         FIXME("unimplemented for vt %d\n", V_VT(v));
217         return E_NOTIMPL;
218     }
219
220     return S_OK;
221 }
222
223 static int hex_to_int(WCHAR c)
224 {
225     if('0' <= c && c <= '9')
226         return c-'0';
227
228     if('a' <= c && c <= 'f')
229         return c-'a'+10;
230
231     if('A' <= c && c <= 'F')
232         return c-'A'+10;
233
234     return -1;
235 }
236
237 /* ECMA-262 3rd Edition    9.3.1 */
238 static HRESULT str_to_number(BSTR str, VARIANT *ret)
239 {
240     const WCHAR *ptr = str;
241     BOOL neg = FALSE;
242     DOUBLE d = 0.0;
243
244     static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
245
246     while(isspaceW(*ptr))
247         ptr++;
248
249     if(*ptr == '-') {
250         neg = TRUE;
251         ptr++;
252     }else if(*ptr == '+') {
253         ptr++;
254     }
255
256     if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
257         ptr += sizeof(infinityW)/sizeof(WCHAR);
258         while(*ptr && isspaceW(*ptr))
259             ptr++;
260
261         if(*ptr)
262             num_set_nan(ret);
263         else
264             num_set_inf(ret, !neg);
265         return S_OK;
266     }
267
268     if(*ptr == '0' && ptr[1] == 'x') {
269         DWORD l = 0;
270
271         ptr += 2;
272         while((l = hex_to_int(*ptr)) != -1) {
273             d = d*16 + l;
274             ptr++;
275         }
276
277         num_set_val(ret, d);
278         return S_OK;
279     }
280
281     while(isdigitW(*ptr))
282         d = d*10 + (*ptr++ - '0');
283
284     if(*ptr == 'e' || *ptr == 'E') {
285         BOOL eneg = FALSE;
286         LONG l = 0;
287
288         ptr++;
289         if(*ptr == '-') {
290             ptr++;
291             eneg = TRUE;
292         }else if(*ptr == '+') {
293             ptr++;
294         }
295
296         while(isdigitW(*ptr))
297             l = l*10 + (*ptr++ - '0');
298         if(eneg)
299             l = -l;
300
301         d *= pow(10, l);
302     }else if(*ptr == '.') {
303         DOUBLE dec = 0.1;
304
305         ptr++;
306         while(isdigitW(*ptr)) {
307             d += dec * (*ptr++ - '0');
308             dec *= 0.1;
309         }
310     }
311
312     while(isspaceW(*ptr))
313         ptr++;
314
315     if(*ptr) {
316         num_set_nan(ret);
317         return S_OK;
318     }
319
320     if(neg)
321         d = -d;
322
323     num_set_val(ret, d);
324     return S_OK;
325 }
326
327 /* ECMA-262 3rd Edition    9.3 */
328 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
329 {
330     switch(V_VT(v)) {
331     case VT_EMPTY:
332         num_set_nan(ret);
333         break;
334     case VT_NULL:
335         V_VT(ret) = VT_I4;
336         V_I4(ret) = 0;
337         break;
338     case VT_I4:
339     case VT_R8:
340         *ret = *v;
341         break;
342     case VT_BSTR:
343         return str_to_number(V_BSTR(v), ret);
344     case VT_DISPATCH: {
345         VARIANT prim;
346         HRESULT hres;
347
348         hres = to_primitive(ctx, v, ei, &prim);
349         if(FAILED(hres))
350             return hres;
351
352         hres = to_number(ctx, &prim, ei, ret);
353         VariantClear(&prim);
354         return hres;
355     }
356     case VT_BOOL:
357         V_VT(ret) = VT_I4;
358         V_I4(ret) = V_BOOL(v) ? 1 : 0;
359         break;
360     default:
361         FIXME("unimplemented for vt %d\n", V_VT(v));
362         return E_NOTIMPL;
363     }
364
365     return S_OK;
366 }
367
368 /* ECMA-262 3rd Edition    9.4 */
369 HRESULT to_integer(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
370 {
371     VARIANT num;
372     HRESULT hres;
373
374     hres = to_number(ctx, v, ei, &num);
375     if(FAILED(hres))
376         return hres;
377
378     if(V_VT(&num) == VT_I4)
379         *ret = num;
380     else
381         num_set_val(ret, V_R8(&num) >= 0.0 ? floor(V_R8(&num)) : -floor(-V_R8(&num)));
382
383     return S_OK;
384 }
385
386 /* ECMA-262 3rd Edition    9.5 */
387 HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
388 {
389     VARIANT num;
390     HRESULT hres;
391
392     hres = to_number(ctx, v, ei, &num);
393     if(FAILED(hres))
394         return hres;
395
396     *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (INT)V_R8(&num);
397     return S_OK;
398 }
399
400 /* ECMA-262 3rd Edition    9.6 */
401 HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
402 {
403     VARIANT num;
404     HRESULT hres;
405
406     hres = to_number(ctx, v, ei, &num);
407     if(FAILED(hres))
408         return hres;
409
410     *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (DWORD)V_R8(&num);
411     return S_OK;
412 }
413
414 static BSTR int_to_bstr(INT i)
415 {
416     WCHAR buf[12], *p;
417     BOOL neg = FALSE;
418
419     if(!i) {
420         static const WCHAR zeroW[] = {'0',0};
421         return SysAllocString(zeroW);
422     }
423
424     if(i < 0) {
425         neg = TRUE;
426         i = -i;
427     }
428
429     p = buf + sizeof(buf)/sizeof(*buf)-1;
430     *p-- = 0;
431     while(i) {
432         *p-- = i%10 + '0';
433         i /= 10;
434     }
435
436     if(neg)
437         *p = '-';
438     else
439         p++;
440
441     return SysAllocString(p);
442 }
443
444 /* ECMA-262 3rd Edition    9.8 */
445 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
446 {
447     const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
448     const WCHAR nullW[] = {'n','u','l','l',0};
449     const WCHAR trueW[] = {'t','r','u','e',0};
450     const WCHAR falseW[] = {'f','a','l','s','e',0};
451
452     switch(V_VT(v)) {
453     case VT_EMPTY:
454         *str = SysAllocString(undefinedW);
455         break;
456     case VT_NULL:
457         *str = SysAllocString(nullW);
458         break;
459     case VT_I4:
460         *str = int_to_bstr(V_I4(v));
461         break;
462     case VT_R8: {
463         VARIANT strv;
464         HRESULT hres;
465
466         V_VT(&strv) = VT_EMPTY;
467         hres = VariantChangeTypeEx(&strv, v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
468         if(FAILED(hres))
469             return hres;
470
471         *str = V_BSTR(&strv);
472         return S_OK;
473     }
474     case VT_BSTR:
475         *str = SysAllocString(V_BSTR(v));
476         break;
477     case VT_DISPATCH: {
478         VARIANT prim;
479         HRESULT hres;
480
481         hres = to_primitive(ctx, v, ei, &prim);
482         if(FAILED(hres))
483             return hres;
484
485         hres = to_string(ctx, &prim, ei, str);
486         VariantClear(&prim);
487         return hres;
488     }
489     case VT_BOOL:
490         *str = SysAllocString(V_BOOL(v) ? trueW : falseW);
491         break;
492     default:
493         FIXME("unsupported vt %d\n", V_VT(v));
494         return E_NOTIMPL;
495     }
496
497     return *str ? S_OK : E_OUTOFMEMORY;
498 }
499
500 /* ECMA-262 3rd Edition    9.9 */
501 HRESULT to_object(exec_ctx_t *ctx, VARIANT *v, IDispatch **disp)
502 {
503     DispatchEx *dispex;
504     HRESULT hres;
505
506     switch(V_VT(v)) {
507     case VT_BSTR:
508         hres = create_string(ctx->parser->script, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
509         if(FAILED(hres))
510             return hres;
511
512         *disp = (IDispatch*)_IDispatchEx_(dispex);
513         break;
514     case VT_I4:
515     case VT_R8:
516         hres = create_number(ctx->parser->script, v, &dispex);
517         if(FAILED(hres))
518             return hres;
519
520         *disp = (IDispatch*)_IDispatchEx_(dispex);
521         break;
522     case VT_DISPATCH:
523         IDispatch_AddRef(V_DISPATCH(v));
524         *disp = V_DISPATCH(v);
525         break;
526     case VT_BOOL:
527         hres = create_bool(ctx->parser->script, V_BOOL(v), &dispex);
528         if(FAILED(hres))
529             return hres;
530
531         *disp = (IDispatch*)_IDispatchEx_(dispex);
532         break;
533     default:
534         FIXME("unsupported vt %d\n", V_VT(v));
535         return E_NOTIMPL;
536     }
537
538     return S_OK;
539 }