jscript: Added to_string(VT_I4) 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 "jscript.h"
20 #include "engine.h"
21
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
25
26 const char *debugstr_variant(const VARIANT *v)
27 {
28     switch(V_VT(v)) {
29     case VT_EMPTY:
30         return wine_dbg_sprintf("{VT_EMPTY}");
31     case VT_NULL:
32         return wine_dbg_sprintf("{VT_NULL}");
33     case VT_I4:
34         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
35     case VT_R8:
36         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
37     case VT_BSTR:
38         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
39     case VT_DISPATCH:
40         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
41     case VT_BOOL:
42         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
43     default:
44         return wine_dbg_sprintf("{vt %d}", V_VT(v));
45     }
46 }
47
48 #define MIN_BLOCK_SIZE  128
49
50 static inline DWORD block_size(DWORD block)
51 {
52     return MIN_BLOCK_SIZE << block;
53 }
54
55 void jsheap_init(jsheap_t *heap)
56 {
57     memset(heap, 0, sizeof(*heap));
58     list_init(&heap->custom_blocks);
59 }
60
61 void *jsheap_alloc(jsheap_t *heap, DWORD size)
62 {
63     struct list *list;
64     void *tmp;
65
66     if(!heap->block_cnt) {
67         if(!heap->blocks) {
68             heap->blocks = heap_alloc(sizeof(void*));
69             if(!heap->blocks)
70                 return NULL;
71         }
72
73         tmp = heap_alloc(block_size(0));
74         if(!tmp)
75             return NULL;
76
77         heap->blocks[0] = tmp;
78         heap->block_cnt = 1;
79     }
80
81     if(heap->offset + size < block_size(heap->last_block)) {
82         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
83         heap->offset += size;
84         return tmp;
85     }
86
87     if(size < block_size(heap->last_block+1)) {
88         if(heap->last_block+1 == heap->block_cnt) {
89             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
90             if(!tmp)
91                 return NULL;
92             heap->blocks = tmp;
93         }
94
95         tmp = heap_alloc(block_size(heap->block_cnt+1));
96         if(!tmp)
97             return NULL;
98
99         heap->blocks[heap->block_cnt++] = tmp;
100
101         heap->last_block++;
102         heap->offset = size;
103         return heap->blocks[heap->last_block];
104     }
105
106     list = heap_alloc(size + sizeof(struct list));
107     if(!list)
108         return NULL;
109
110     list_add_head(&heap->custom_blocks, list);
111     return list+1;
112 }
113
114 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
115 {
116     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
117        && heap->offset+inc < block_size(heap->last_block)) {
118         heap->offset += inc;
119         return mem;
120     }
121
122     return jsheap_alloc(heap, size+inc);
123 }
124
125 void jsheap_clear(jsheap_t *heap)
126 {
127     struct list *tmp;
128
129     if(!heap)
130         return;
131
132     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
133         list_remove(tmp);
134         heap_free(tmp);
135     }
136
137     heap->last_block = heap->offset = 0;
138 }
139
140 void jsheap_free(jsheap_t *heap)
141 {
142     DWORD i;
143
144     jsheap_clear(heap);
145
146     for(i=0; i < heap->block_cnt; i++)
147         heap_free(heap->blocks[i]);
148     heap_free(heap->blocks);
149
150     jsheap_init(heap);
151 }
152
153 jsheap_t *jsheap_mark(jsheap_t *heap)
154 {
155     if(heap->mark)
156         return NULL;
157
158     heap->mark = TRUE;
159     return heap;
160 }
161
162 /* ECMA-262 3rd Edition    9.1 */
163 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
164 {
165     switch(V_VT(v)) {
166     case VT_EMPTY:
167     case VT_NULL:
168     case VT_BOOL:
169     case VT_I4:
170     case VT_R8:
171         *ret = *v;
172         break;
173     case VT_BSTR:
174         V_VT(ret) = VT_BSTR;
175         V_BSTR(ret) = SysAllocString(V_BSTR(v));
176         break;
177     case VT_DISPATCH:
178         return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/);
179     default:
180         FIXME("Unimplemented for vt %d\n", V_VT(v));
181         return E_NOTIMPL;
182     }
183
184     return S_OK;
185 }
186
187 /* ECMA-262 3rd Edition    9.2 */
188 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
189 {
190     switch(V_VT(v)) {
191     case VT_EMPTY:
192     case VT_NULL:
193         *b = VARIANT_FALSE;
194         break;
195     case VT_I4:
196         *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
197         break;
198     case VT_R8:
199         *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
200         break;
201     case VT_BSTR:
202         *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
203         break;
204     case VT_DISPATCH:
205         *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
206         break;
207     case VT_BOOL:
208         *b = V_BOOL(v);
209         break;
210     default:
211         FIXME("unimplemented for vt %d\n", V_VT(v));
212         return E_NOTIMPL;
213     }
214
215     return S_OK;
216 }
217
218 /* ECMA-262 3rd Edition    9.3 */
219 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
220 {
221     switch(V_VT(v)) {
222     case VT_NULL:
223         V_VT(ret) = VT_I4;
224         V_I4(ret) = 0;
225         break;
226     case VT_I4:
227     case VT_R8:
228         *ret = *v;
229         break;
230     case VT_BOOL:
231         V_VT(ret) = VT_I4;
232         V_I4(ret) = V_BOOL(v) ? 1 : 0;
233         break;
234     default:
235         FIXME("unimplemented for vt %d\n", V_VT(v));
236         return E_NOTIMPL;
237     }
238
239     return S_OK;
240 }
241
242 /* ECMA-262 3rd Edition    9.5 */
243 HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
244 {
245     VARIANT num;
246     HRESULT hres;
247
248     hres = to_number(ctx, v, ei, &num);
249     if(FAILED(hres))
250         return hres;
251
252     *ret = V_VT(&num) == VT_I4 ? V_I4(&num) : (INT)V_R8(&num);
253     return S_OK;
254 }
255
256 static BSTR int_to_bstr(INT i)
257 {
258     WCHAR buf[12], *p;
259     BOOL neg = FALSE;
260
261     if(!i) {
262         static const WCHAR zeroW[] = {'0',0};
263         return SysAllocString(zeroW);
264     }
265
266     if(i < 0) {
267         neg = TRUE;
268         i = -i;
269     }
270
271     p = buf + sizeof(buf)/sizeof(*buf)-1;
272     *p-- = 0;
273     while(i) {
274         *p-- = i%10 + '0';
275         i /= 10;
276     }
277
278     if(neg)
279         *p = '-';
280     else
281         p++;
282
283     return SysAllocString(p);
284 }
285
286 /* ECMA-262 3rd Edition    9.8 */
287 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
288 {
289     switch(V_VT(v)) {
290     case VT_I4:
291         *str = int_to_bstr(V_I4(v));
292         break;
293
294     case VT_BSTR:
295         *str = SysAllocString(V_BSTR(v));
296         break;
297
298     default:
299         FIXME("unsupported vt %d\n", V_VT(v));
300         return E_NOTIMPL;
301     }
302
303     return *str ? S_OK : E_OUTOFMEMORY;
304 }
305
306 /* ECMA-262 3rd Edition    9.9 */
307 HRESULT to_object(exec_ctx_t *ctx, VARIANT *v, IDispatch **disp)
308 {
309     DispatchEx *dispex;
310     HRESULT hres;
311
312     switch(V_VT(v)) {
313     case VT_BSTR:
314         hres = create_string(ctx->parser->script, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
315         if(FAILED(hres))
316             return hres;
317
318         *disp = (IDispatch*)_IDispatchEx_(dispex);
319         break;
320     case VT_I4:
321     case VT_R8:
322         hres = create_number(ctx->parser->script, v, &dispex);
323         if(FAILED(hres))
324             return hres;
325
326         *disp = (IDispatch*)_IDispatchEx_(dispex);
327         break;
328     case VT_DISPATCH:
329         IDispatch_AddRef(V_DISPATCH(v));
330         *disp = V_DISPATCH(v);
331         break;
332     case VT_BOOL:
333         hres = create_bool(ctx->parser->script, V_BOOL(v), &dispex);
334         if(FAILED(hres))
335             return hres;
336
337         *disp = (IDispatch*)_IDispatchEx_(dispex);
338         break;
339     default:
340         FIXME("unsupported vt %d\n", V_VT(v));
341         return E_NOTIMPL;
342     }
343
344     return S_OK;
345 }