ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

jsutils.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 Jacek Caban for CodeWeavers
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "config.h"
00020 #include "wine/port.h"
00021 
00022 #include <math.h>
00023 
00024 #include "jscript.h"
00025 #include "engine.h"
00026 
00027 #include "wine/debug.h"
00028 
00029 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
00030 WINE_DECLARE_DEBUG_CHANNEL(heap);
00031 
00032 const char *debugstr_variant(const VARIANT *v)
00033 {
00034     if(!v)
00035         return "(null)";
00036 
00037     switch(V_VT(v)) {
00038     case VT_EMPTY:
00039         return "{VT_EMPTY}";
00040     case VT_NULL:
00041         return "{VT_NULL}";
00042     case VT_I4:
00043         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
00044     case VT_R8:
00045         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
00046     case VT_BSTR:
00047         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
00048     case VT_DISPATCH:
00049         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
00050     case VT_BOOL:
00051         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
00052     default:
00053         return wine_dbg_sprintf("{vt %d}", V_VT(v));
00054     }
00055 }
00056 
00057 #define MIN_BLOCK_SIZE  128
00058 #define ARENA_FREE_FILLER  0xaa
00059 
00060 static inline DWORD block_size(DWORD block)
00061 {
00062     return MIN_BLOCK_SIZE << block;
00063 }
00064 
00065 void jsheap_init(jsheap_t *heap)
00066 {
00067     memset(heap, 0, sizeof(*heap));
00068     list_init(&heap->custom_blocks);
00069 }
00070 
00071 void *jsheap_alloc(jsheap_t *heap, DWORD size)
00072 {
00073     struct list *list;
00074     void *tmp;
00075 
00076     if(!heap->block_cnt) {
00077         if(!heap->blocks) {
00078             heap->blocks = heap_alloc(sizeof(void*));
00079             if(!heap->blocks)
00080                 return NULL;
00081         }
00082 
00083         tmp = heap_alloc(block_size(0));
00084         if(!tmp)
00085             return NULL;
00086 
00087         heap->blocks[0] = tmp;
00088         heap->block_cnt = 1;
00089     }
00090 
00091     if(heap->offset + size <= block_size(heap->last_block)) {
00092         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
00093         heap->offset += size;
00094         return tmp;
00095     }
00096 
00097     if(size <= block_size(heap->last_block+1)) {
00098         if(heap->last_block+1 == heap->block_cnt) {
00099             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
00100             if(!tmp)
00101                 return NULL;
00102 
00103             heap->blocks = tmp;
00104             heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
00105             if(!heap->blocks[heap->block_cnt])
00106                 return NULL;
00107 
00108             heap->block_cnt++;
00109         }
00110 
00111         heap->last_block++;
00112         heap->offset = size;
00113         return heap->blocks[heap->last_block];
00114     }
00115 
00116     list = heap_alloc(size + sizeof(struct list));
00117     if(!list)
00118         return NULL;
00119 
00120     list_add_head(&heap->custom_blocks, list);
00121     return list+1;
00122 }
00123 
00124 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
00125 {
00126     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
00127        && heap->offset+inc < block_size(heap->last_block)) {
00128         heap->offset += inc;
00129         return mem;
00130     }
00131 
00132     return jsheap_alloc(heap, size+inc);
00133 }
00134 
00135 void jsheap_clear(jsheap_t *heap)
00136 {
00137     struct list *tmp;
00138 
00139     if(!heap)
00140         return;
00141 
00142     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
00143         list_remove(tmp);
00144         heap_free(tmp);
00145     }
00146 
00147     if(WARN_ON(heap)) {
00148         DWORD i;
00149 
00150         for(i=0; i < heap->block_cnt; i++)
00151             memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
00152     }
00153 
00154     heap->last_block = heap->offset = 0;
00155     heap->mark = FALSE;
00156 }
00157 
00158 void jsheap_free(jsheap_t *heap)
00159 {
00160     DWORD i;
00161 
00162     jsheap_clear(heap);
00163 
00164     for(i=0; i < heap->block_cnt; i++)
00165         heap_free(heap->blocks[i]);
00166     heap_free(heap->blocks);
00167 
00168     jsheap_init(heap);
00169 }
00170 
00171 jsheap_t *jsheap_mark(jsheap_t *heap)
00172 {
00173     if(heap->mark)
00174         return NULL;
00175 
00176     heap->mark = TRUE;
00177     return heap;
00178 }
00179 
00180 /* ECMA-262 3rd Edition    9.1 */
00181 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret, hint_t hint)
00182 {
00183     switch(V_VT(v)) {
00184     case VT_EMPTY:
00185     case VT_NULL:
00186     case VT_BOOL:
00187     case VT_I4:
00188     case VT_R8:
00189         *ret = *v;
00190         break;
00191     case VT_BSTR:
00192         V_VT(ret) = VT_BSTR;
00193         V_BSTR(ret) = SysAllocString(V_BSTR(v));
00194         break;
00195     case VT_DISPATCH: {
00196         DispatchEx *jsdisp;
00197         DISPID id;
00198         DISPPARAMS dp = {NULL, NULL, 0, 0};
00199         HRESULT hres;
00200 
00201         static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
00202         static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
00203 
00204         if(!V_DISPATCH(v)) {
00205             V_VT(ret) = VT_NULL;
00206             break;
00207         }
00208 
00209         jsdisp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
00210         if(!jsdisp) {
00211             V_VT(ret) = VT_EMPTY;
00212             return disp_propget(ctx, V_DISPATCH(v), DISPID_VALUE, ret, ei, NULL /*FIXME*/);
00213         }
00214 
00215         if(hint == NO_HINT)
00216             hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
00217 
00218         /* Native implementation doesn't throw TypeErrors, returns strange values */
00219 
00220         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id);
00221         if(SUCCEEDED(hres)) {
00222             hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, &dp, ret, ei, NULL /*FIXME*/);
00223             if(FAILED(hres)) {
00224                 WARN("call error - forwarding exception\n");
00225                 jsdisp_release(jsdisp);
00226                 return hres;
00227             }
00228             else if(V_VT(ret) != VT_DISPATCH) {
00229                 jsdisp_release(jsdisp);
00230                 return S_OK;
00231             }
00232             else
00233                 IDispatch_Release(V_DISPATCH(ret));
00234         }
00235 
00236         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id);
00237         if(SUCCEEDED(hres)) {
00238             hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, &dp, ret, ei, NULL /*FIXME*/);
00239             if(FAILED(hres)) {
00240                 WARN("call error - forwarding exception\n");
00241                 jsdisp_release(jsdisp);
00242                 return hres;
00243             }
00244             else if(V_VT(ret) != VT_DISPATCH) {
00245                 jsdisp_release(jsdisp);
00246                 return S_OK;
00247             }
00248             else
00249                 IDispatch_Release(V_DISPATCH(ret));
00250         }
00251 
00252         jsdisp_release(jsdisp);
00253 
00254         WARN("failed\n");
00255         return throw_type_error(ctx, ei, IDS_TO_PRIMITIVE, NULL);
00256     }
00257     default:
00258         FIXME("Unimplemented for vt %d\n", V_VT(v));
00259         return E_NOTIMPL;
00260     }
00261 
00262     return S_OK;
00263 }
00264 
00265 /* ECMA-262 3rd Edition    9.2 */
00266 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
00267 {
00268     switch(V_VT(v)) {
00269     case VT_EMPTY:
00270     case VT_NULL:
00271         *b = VARIANT_FALSE;
00272         break;
00273     case VT_I4:
00274         *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
00275         break;
00276     case VT_R8:
00277         if(isnan(V_R8(v))) *b = VARIANT_FALSE;
00278         else *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
00279         break;
00280     case VT_BSTR:
00281         *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
00282         break;
00283     case VT_DISPATCH:
00284         *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
00285         break;
00286     case VT_BOOL:
00287         *b = V_BOOL(v);
00288         break;
00289     default:
00290         FIXME("unimplemented for vt %d\n", V_VT(v));
00291         return E_NOTIMPL;
00292     }
00293 
00294     return S_OK;
00295 }
00296 
00297 static int hex_to_int(WCHAR c)
00298 {
00299     if('0' <= c && c <= '9')
00300         return c-'0';
00301 
00302     if('a' <= c && c <= 'f')
00303         return c-'a'+10;
00304 
00305     if('A' <= c && c <= 'F')
00306         return c-'A'+10;
00307 
00308     return -1;
00309 }
00310 
00311 /* ECMA-262 3rd Edition    9.3.1 */
00312 static HRESULT str_to_number(BSTR str, VARIANT *ret)
00313 {
00314     const WCHAR *ptr = str;
00315     BOOL neg = FALSE;
00316     DOUBLE d = 0.0;
00317 
00318     static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
00319 
00320     while(isspaceW(*ptr))
00321         ptr++;
00322 
00323     if(*ptr == '-') {
00324         neg = TRUE;
00325         ptr++;
00326     }else if(*ptr == '+') {
00327         ptr++;
00328     }
00329 
00330     if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
00331         ptr += sizeof(infinityW)/sizeof(WCHAR);
00332         while(*ptr && isspaceW(*ptr))
00333             ptr++;
00334 
00335         if(*ptr)
00336             num_set_nan(ret);
00337         else
00338             num_set_inf(ret, !neg);
00339         return S_OK;
00340     }
00341 
00342     if(*ptr == '0' && ptr[1] == 'x') {
00343         DWORD l = 0;
00344 
00345         ptr += 2;
00346         while((l = hex_to_int(*ptr)) != -1) {
00347             d = d*16 + l;
00348             ptr++;
00349         }
00350 
00351         num_set_val(ret, d);
00352         return S_OK;
00353     }
00354 
00355     while(isdigitW(*ptr))
00356         d = d*10 + (*ptr++ - '0');
00357 
00358     if(*ptr == 'e' || *ptr == 'E') {
00359         BOOL eneg = FALSE;
00360         LONG l = 0;
00361 
00362         ptr++;
00363         if(*ptr == '-') {
00364             ptr++;
00365             eneg = TRUE;
00366         }else if(*ptr == '+') {
00367             ptr++;
00368         }
00369 
00370         while(isdigitW(*ptr))
00371             l = l*10 + (*ptr++ - '0');
00372         if(eneg)
00373             l = -l;
00374 
00375         d *= pow(10, l);
00376     }else if(*ptr == '.') {
00377         DOUBLE dec = 0.1;
00378 
00379         ptr++;
00380         while(isdigitW(*ptr)) {
00381             d += dec * (*ptr++ - '0');
00382             dec *= 0.1;
00383         }
00384     }
00385 
00386     while(isspaceW(*ptr))
00387         ptr++;
00388 
00389     if(*ptr) {
00390         num_set_nan(ret);
00391         return S_OK;
00392     }
00393 
00394     if(neg)
00395         d = -d;
00396 
00397     num_set_val(ret, d);
00398     return S_OK;
00399 }
00400 
00401 /* ECMA-262 3rd Edition    9.3 */
00402 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
00403 {
00404     switch(V_VT(v)) {
00405     case VT_EMPTY:
00406         num_set_nan(ret);
00407         break;
00408     case VT_NULL:
00409         V_VT(ret) = VT_I4;
00410         V_I4(ret) = 0;
00411         break;
00412     case VT_I4:
00413     case VT_R8:
00414         *ret = *v;
00415         break;
00416     case VT_BSTR:
00417         return str_to_number(V_BSTR(v), ret);
00418     case VT_DISPATCH: {
00419         VARIANT prim;
00420         HRESULT hres;
00421 
00422         hres = to_primitive(ctx, v, ei, &prim, HINT_NUMBER);
00423         if(FAILED(hres))
00424             return hres;
00425 
00426         hres = to_number(ctx, &prim, ei, ret);
00427         VariantClear(&prim);
00428         return hres;
00429     }
00430     case VT_BOOL:
00431         V_VT(ret) = VT_I4;
00432         V_I4(ret) = V_BOOL(v) ? 1 : 0;
00433         break;
00434     default:
00435         FIXME("unimplemented for vt %d\n", V_VT(v));
00436         return E_NOTIMPL;
00437     }
00438 
00439     return S_OK;
00440 }
00441 
00442 /* ECMA-262 3rd Edition    9.4 */
00443 HRESULT to_integer(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
00444 {
00445     VARIANT num;
00446     HRESULT hres;
00447 
00448     hres = to_number(ctx, v, ei, &num);
00449     if(FAILED(hres))
00450         return hres;
00451 
00452     if(V_VT(&num) == VT_I4) {
00453         *ret = num;
00454     }else if(isnan(V_R8(&num))) {
00455         V_VT(ret) = VT_I4;
00456         V_I4(ret) = 0;
00457     }else {
00458         num_set_val(ret, V_R8(&num) >= 0.0 ? floor(V_R8(&num)) : -floor(-V_R8(&num)));
00459     }
00460 
00461     return S_OK;
00462 }
00463 
00464 /* ECMA-262 3rd Edition    9.5 */
00465 HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
00466 {
00467     VARIANT num;
00468     HRESULT hres;
00469 
00470     hres = to_number(ctx, v, ei, &num);
00471     if(FAILED(hres))
00472         return hres;
00473 
00474     if(V_VT(&num) == VT_I4)
00475         *ret = V_I4(&num);
00476     else
00477         *ret = isnan(V_R8(&num)) || isinf(V_R8(&num)) ? 0 : (INT)V_R8(&num);
00478     return S_OK;
00479 }
00480 
00481 /* ECMA-262 3rd Edition    9.6 */
00482 HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
00483 {
00484     VARIANT num;
00485     HRESULT hres;
00486 
00487     hres = to_number(ctx, v, ei, &num);
00488     if(FAILED(hres))
00489         return hres;
00490 
00491     if(V_VT(&num) == VT_I4)
00492         *ret = V_I4(&num);
00493     else
00494         *ret = isnan(V_R8(&num)) || isinf(V_R8(&num)) ? 0 : (DWORD)V_R8(&num);
00495     return S_OK;
00496 }
00497 
00498 static BSTR int_to_bstr(INT i)
00499 {
00500     WCHAR buf[12], *p;
00501     BOOL neg = FALSE;
00502 
00503     if(!i) {
00504         static const WCHAR zeroW[] = {'0',0};
00505         return SysAllocString(zeroW);
00506     }
00507 
00508     if(i < 0) {
00509         neg = TRUE;
00510         i = -i;
00511     }
00512 
00513     p = buf + sizeof(buf)/sizeof(*buf)-1;
00514     *p-- = 0;
00515     while(i) {
00516         *p-- = i%10 + '0';
00517         i /= 10;
00518     }
00519 
00520     if(neg)
00521         *p = '-';
00522     else
00523         p++;
00524 
00525     return SysAllocString(p);
00526 }
00527 
00528 /* ECMA-262 3rd Edition    9.8 */
00529 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
00530 {
00531     const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
00532     const WCHAR nullW[] = {'n','u','l','l',0};
00533     const WCHAR trueW[] = {'t','r','u','e',0};
00534     const WCHAR falseW[] = {'f','a','l','s','e',0};
00535     const WCHAR NaNW[] = {'N','a','N',0};
00536     const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
00537 
00538     switch(V_VT(v)) {
00539     case VT_EMPTY:
00540         *str = SysAllocString(undefinedW);
00541         break;
00542     case VT_NULL:
00543         *str = SysAllocString(nullW);
00544         break;
00545     case VT_I4:
00546         *str = int_to_bstr(V_I4(v));
00547         break;
00548     case VT_R8: {
00549         if(isnan(V_R8(v)))
00550             *str = SysAllocString(NaNW);
00551         else if(isinf(V_R8(v)))
00552             *str = SysAllocString(V_R8(v)<0 ? InfinityW : InfinityW+1);
00553         else {
00554             VARIANT strv;
00555             HRESULT hres;
00556 
00557             V_VT(&strv) = VT_EMPTY;
00558             hres = VariantChangeTypeEx(&strv, v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
00559             if(FAILED(hres))
00560                 return hres;
00561 
00562             *str = V_BSTR(&strv);
00563             return S_OK;
00564         }
00565         break;
00566     }
00567     case VT_BSTR:
00568         *str = SysAllocString(V_BSTR(v));
00569         break;
00570     case VT_DISPATCH: {
00571         VARIANT prim;
00572         HRESULT hres;
00573 
00574         hres = to_primitive(ctx, v, ei, &prim, HINT_STRING);
00575         if(FAILED(hres))
00576             return hres;
00577 
00578         hres = to_string(ctx, &prim, ei, str);
00579         VariantClear(&prim);
00580         return hres;
00581     }
00582     case VT_BOOL:
00583         *str = SysAllocString(V_BOOL(v) ? trueW : falseW);
00584         break;
00585     default:
00586         FIXME("unsupported vt %d\n", V_VT(v));
00587         return E_NOTIMPL;
00588     }
00589 
00590     return *str ? S_OK : E_OUTOFMEMORY;
00591 }
00592 
00593 /* ECMA-262 3rd Edition    9.9 */
00594 HRESULT to_object(script_ctx_t *ctx, VARIANT *v, IDispatch **disp)
00595 {
00596     DispatchEx *dispex;
00597     HRESULT hres;
00598 
00599     switch(V_VT(v)) {
00600     case VT_BSTR:
00601         hres = create_string(ctx, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
00602         if(FAILED(hres))
00603             return hres;
00604 
00605         *disp = (IDispatch*)_IDispatchEx_(dispex);
00606         break;
00607     case VT_I4:
00608     case VT_R8:
00609         hres = create_number(ctx, v, &dispex);
00610         if(FAILED(hres))
00611             return hres;
00612 
00613         *disp = (IDispatch*)_IDispatchEx_(dispex);
00614         break;
00615     case VT_DISPATCH:
00616         if(V_DISPATCH(v)) {
00617             IDispatch_AddRef(V_DISPATCH(v));
00618             *disp = V_DISPATCH(v);
00619         }else {
00620             DispatchEx *obj;
00621 
00622             hres = create_object(ctx, NULL, &obj);
00623             if(FAILED(hres))
00624                 return hres;
00625 
00626             *disp = (IDispatch*)_IDispatchEx_(obj);
00627         }
00628         break;
00629     case VT_BOOL:
00630         hres = create_bool(ctx, V_BOOL(v), &dispex);
00631         if(FAILED(hres))
00632             return hres;
00633 
00634         *disp = (IDispatch*)_IDispatchEx_(dispex);
00635         break;
00636     default:
00637         FIXME("unsupported vt %d\n", V_VT(v));
00638         return E_NOTIMPL;
00639     }
00640 
00641     return S_OK;
00642 }

Generated on Fri May 25 2012 04:22:14 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.