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