Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenjsutils.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
1.7.6.1
|