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