Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenarray.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 "wine/config.h" 00020 #include "wine/port.h" 00021 00022 #include <math.h> 00023 00024 #include "jscript.h" 00025 00026 #include "wine/debug.h" 00027 00028 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 00029 00030 typedef struct { 00031 DispatchEx dispex; 00032 00033 DWORD length; 00034 } ArrayInstance; 00035 00036 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0}; 00037 static const WCHAR concatW[] = {'c','o','n','c','a','t',0}; 00038 static const WCHAR joinW[] = {'j','o','i','n',0}; 00039 static const WCHAR popW[] = {'p','o','p',0}; 00040 static const WCHAR pushW[] = {'p','u','s','h',0}; 00041 static const WCHAR reverseW[] = {'r','e','v','e','r','s','e',0}; 00042 static const WCHAR shiftW[] = {'s','h','i','f','t',0}; 00043 static const WCHAR sliceW[] = {'s','l','i','c','e',0}; 00044 static const WCHAR sortW[] = {'s','o','r','t',0}; 00045 static const WCHAR spliceW[] = {'s','p','l','i','c','e',0}; 00046 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; 00047 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0}; 00048 static const WCHAR unshiftW[] = {'u','n','s','h','i','f','t',0}; 00049 00050 static const WCHAR default_separatorW[] = {',',0}; 00051 00052 static inline ArrayInstance *array_from_vdisp(vdisp_t *vdisp) 00053 { 00054 return (ArrayInstance*)vdisp->u.jsdisp; 00055 } 00056 00057 static inline ArrayInstance *array_this(vdisp_t *jsthis) 00058 { 00059 return is_vclass(jsthis, JSCLASS_ARRAY) ? array_from_vdisp(jsthis) : NULL; 00060 } 00061 00062 static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsexcept_t *ei, DispatchEx **jsthis, DWORD *ret) 00063 { 00064 ArrayInstance *array; 00065 VARIANT var; 00066 HRESULT hres; 00067 00068 array = array_this(vdisp); 00069 if(array) { 00070 *jsthis = &array->dispex; 00071 *ret = array->length; 00072 return S_OK; 00073 } 00074 00075 if(!is_jsdisp(vdisp)) 00076 return throw_type_error(ctx, ei, IDS_JSCRIPT_EXPECTED, NULL); 00077 00078 hres = jsdisp_propget_name(vdisp->u.jsdisp, lengthW, &var, ei, NULL/*FIXME*/); 00079 if(FAILED(hres)) 00080 return hres; 00081 00082 hres = to_uint32(ctx, &var, ei, ret); 00083 VariantClear(&var); 00084 if(FAILED(hres)) 00085 return hres; 00086 00087 *jsthis = vdisp->u.jsdisp; 00088 return S_OK; 00089 } 00090 00091 static HRESULT set_length(DispatchEx *obj, jsexcept_t *ei, DWORD length) 00092 { 00093 VARIANT var; 00094 00095 if(is_class(obj, JSCLASS_ARRAY)) { 00096 ((ArrayInstance*)obj)->length = length; 00097 return S_OK; 00098 } 00099 00100 V_VT(&var) = VT_I4; 00101 V_I4(&var) = length; 00102 return jsdisp_propput_name(obj, lengthW, &var, ei, NULL/*FIXME*/); 00103 } 00104 00105 static WCHAR *idx_to_str(DWORD idx, WCHAR *ptr) 00106 { 00107 if(!idx) { 00108 *ptr = '0'; 00109 return ptr; 00110 } 00111 00112 while(idx) { 00113 *ptr-- = '0' + (idx%10); 00114 idx /= 10; 00115 } 00116 00117 return ptr+1; 00118 } 00119 00120 static HRESULT Array_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00121 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00122 { 00123 ArrayInstance *This = array_from_vdisp(jsthis); 00124 00125 TRACE("%p %d\n", This, This->length); 00126 00127 switch(flags) { 00128 case DISPATCH_PROPERTYGET: 00129 V_VT(retv) = VT_I4; 00130 V_I4(retv) = This->length; 00131 break; 00132 case DISPATCH_PROPERTYPUT: { 00133 VARIANT num; 00134 DOUBLE len = -1; 00135 DWORD i; 00136 HRESULT hres; 00137 00138 hres = to_number(ctx, get_arg(dp, 0), ei, &num); 00139 if(V_VT(&num) == VT_I4) 00140 len = V_I4(&num); 00141 else 00142 len = floor(V_R8(&num)); 00143 00144 if(len!=(DWORD)len) 00145 return throw_range_error(ctx, ei, IDS_INVALID_LENGTH, NULL); 00146 00147 for(i=len; i<This->length; i++) { 00148 hres = jsdisp_delete_idx(&This->dispex, i); 00149 if(FAILED(hres)) 00150 return hres; 00151 } 00152 00153 This->length = len; 00154 break; 00155 } 00156 default: 00157 FIXME("unimplemented flags %x\n", flags); 00158 return E_NOTIMPL; 00159 } 00160 00161 return S_OK; 00162 } 00163 00164 static HRESULT concat_array(DispatchEx *array, ArrayInstance *obj, DWORD *len, 00165 jsexcept_t *ei, IServiceProvider *caller) 00166 { 00167 VARIANT var; 00168 DWORD i; 00169 HRESULT hres; 00170 00171 for(i=0; i < obj->length; i++) { 00172 hres = jsdisp_get_idx(&obj->dispex, i, &var, ei, caller); 00173 if(hres == DISP_E_UNKNOWNNAME) 00174 continue; 00175 if(FAILED(hres)) 00176 return hres; 00177 00178 hres = jsdisp_propput_idx(array, *len+i, &var, ei, caller); 00179 VariantClear(&var); 00180 if(FAILED(hres)) 00181 return hres; 00182 } 00183 00184 *len += obj->length; 00185 return S_OK; 00186 } 00187 00188 static HRESULT concat_obj(DispatchEx *array, IDispatch *obj, DWORD *len, jsexcept_t *ei, IServiceProvider *caller) 00189 { 00190 DispatchEx *jsobj; 00191 VARIANT var; 00192 HRESULT hres; 00193 00194 jsobj = iface_to_jsdisp((IUnknown*)obj); 00195 if(jsobj) { 00196 if(is_class(jsobj, JSCLASS_ARRAY)) { 00197 hres = concat_array(array, (ArrayInstance*)jsobj, len, ei, caller); 00198 jsdisp_release(jsobj); 00199 return hres; 00200 } 00201 jsdisp_release(jsobj); 00202 } 00203 00204 V_VT(&var) = VT_DISPATCH; 00205 V_DISPATCH(&var) = obj; 00206 return jsdisp_propput_idx(array, (*len)++, &var, ei, caller); 00207 } 00208 00209 static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00210 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00211 { 00212 DispatchEx *ret; 00213 DWORD len = 0; 00214 HRESULT hres; 00215 00216 TRACE("\n"); 00217 00218 hres = create_array(ctx, 0, &ret); 00219 if(FAILED(hres)) 00220 return hres; 00221 00222 hres = concat_obj(ret, jsthis->u.disp, &len, ei, caller); 00223 if(SUCCEEDED(hres)) { 00224 VARIANT *arg; 00225 DWORD i; 00226 00227 for(i=0; i < arg_cnt(dp); i++) { 00228 arg = get_arg(dp, i); 00229 if(V_VT(arg) == VT_DISPATCH) 00230 hres = concat_obj(ret, V_DISPATCH(arg), &len, ei, caller); 00231 else 00232 hres = jsdisp_propput_idx(ret, len++, arg, ei, caller); 00233 if(FAILED(hres)) 00234 break; 00235 } 00236 } 00237 00238 if(FAILED(hres)) 00239 return hres; 00240 00241 if(retv) { 00242 V_VT(retv) = VT_DISPATCH; 00243 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret); 00244 }else { 00245 jsdisp_release(ret); 00246 } 00247 return S_OK; 00248 } 00249 00250 static HRESULT array_join(script_ctx_t *ctx, DispatchEx *array, DWORD length, const WCHAR *sep, VARIANT *retv, 00251 jsexcept_t *ei, IServiceProvider *caller) 00252 { 00253 BSTR *str_tab, ret = NULL; 00254 VARIANT var; 00255 DWORD i; 00256 HRESULT hres = E_FAIL; 00257 00258 if(!length) { 00259 if(retv) { 00260 V_VT(retv) = VT_BSTR; 00261 V_BSTR(retv) = SysAllocStringLen(NULL, 0); 00262 if(!V_BSTR(retv)) 00263 return E_OUTOFMEMORY; 00264 } 00265 return S_OK; 00266 } 00267 00268 str_tab = heap_alloc_zero(length * sizeof(BSTR)); 00269 if(!str_tab) 00270 return E_OUTOFMEMORY; 00271 00272 for(i=0; i < length; i++) { 00273 hres = jsdisp_get_idx(array, i, &var, ei, caller); 00274 if(hres == DISP_E_UNKNOWNNAME) { 00275 hres = S_OK; 00276 continue; 00277 } else if(FAILED(hres)) 00278 break; 00279 00280 if(V_VT(&var) != VT_EMPTY && V_VT(&var) != VT_NULL) 00281 hres = to_string(ctx, &var, ei, str_tab+i); 00282 VariantClear(&var); 00283 if(FAILED(hres)) 00284 break; 00285 } 00286 00287 if(SUCCEEDED(hres)) { 00288 DWORD seplen = 0, len = 0; 00289 WCHAR *ptr; 00290 00291 seplen = strlenW(sep); 00292 00293 if(str_tab[0]) 00294 len = SysStringLen(str_tab[0]); 00295 for(i=1; i < length; i++) 00296 len += seplen + SysStringLen(str_tab[i]); 00297 00298 ret = SysAllocStringLen(NULL, len); 00299 if(ret) { 00300 DWORD tmplen = 0; 00301 00302 if(str_tab[0]) { 00303 tmplen = SysStringLen(str_tab[0]); 00304 memcpy(ret, str_tab[0], tmplen*sizeof(WCHAR)); 00305 } 00306 00307 ptr = ret + tmplen; 00308 for(i=1; i < length; i++) { 00309 if(seplen) { 00310 memcpy(ptr, sep, seplen*sizeof(WCHAR)); 00311 ptr += seplen; 00312 } 00313 00314 if(str_tab[i]) { 00315 tmplen = SysStringLen(str_tab[i]); 00316 memcpy(ptr, str_tab[i], tmplen*sizeof(WCHAR)); 00317 ptr += tmplen; 00318 } 00319 } 00320 *ptr=0; 00321 }else { 00322 hres = E_OUTOFMEMORY; 00323 } 00324 } 00325 00326 for(i=0; i < length; i++) 00327 SysFreeString(str_tab[i]); 00328 heap_free(str_tab); 00329 if(FAILED(hres)) 00330 return hres; 00331 00332 TRACE("= %s\n", debugstr_w(ret)); 00333 00334 if(retv) { 00335 if(!ret) { 00336 ret = SysAllocStringLen(NULL, 0); 00337 if(!ret) 00338 return E_OUTOFMEMORY; 00339 } 00340 00341 V_VT(retv) = VT_BSTR; 00342 V_BSTR(retv) = ret; 00343 }else { 00344 SysFreeString(ret); 00345 } 00346 00347 return S_OK; 00348 } 00349 00350 /* ECMA-262 3rd Edition 15.4.4.5 */ 00351 static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00352 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00353 { 00354 DispatchEx *jsthis; 00355 DWORD length; 00356 HRESULT hres; 00357 00358 TRACE("\n"); 00359 00360 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00361 if(FAILED(hres)) 00362 return hres; 00363 00364 if(arg_cnt(dp)) { 00365 BSTR sep; 00366 00367 hres = to_string(ctx, get_arg(dp,0), ei, &sep); 00368 if(FAILED(hres)) 00369 return hres; 00370 00371 hres = array_join(ctx, jsthis, length, sep, retv, ei, caller); 00372 00373 SysFreeString(sep); 00374 }else { 00375 hres = array_join(ctx, jsthis, length, default_separatorW, retv, ei, caller); 00376 } 00377 00378 return hres; 00379 } 00380 00381 static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00382 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00383 { 00384 DispatchEx *jsthis; 00385 VARIANT val; 00386 DWORD length; 00387 HRESULT hres; 00388 00389 TRACE("\n"); 00390 00391 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00392 if(FAILED(hres)) 00393 return hres; 00394 00395 if(!length) { 00396 hres = set_length(jsthis, ei, 0); 00397 if(FAILED(hres)) 00398 return hres; 00399 00400 if(retv) 00401 V_VT(retv) = VT_EMPTY; 00402 return S_OK; 00403 } 00404 00405 length--; 00406 hres = jsdisp_get_idx(jsthis, length, &val, ei, caller); 00407 if(SUCCEEDED(hres)) { 00408 hres = jsdisp_delete_idx(jsthis, length); 00409 } else if(hres == DISP_E_UNKNOWNNAME) { 00410 V_VT(&val) = VT_EMPTY; 00411 hres = S_OK; 00412 } else 00413 return hres; 00414 00415 if(SUCCEEDED(hres)) 00416 hres = set_length(jsthis, ei, length); 00417 00418 if(FAILED(hres)) { 00419 VariantClear(&val); 00420 return hres; 00421 } 00422 00423 if(retv) 00424 *retv = val; 00425 else 00426 VariantClear(&val); 00427 00428 return S_OK; 00429 } 00430 00431 /* ECMA-262 3rd Edition 15.4.4.7 */ 00432 static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00433 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00434 { 00435 DispatchEx *jsthis; 00436 DWORD length = 0; 00437 int i, n; 00438 HRESULT hres; 00439 00440 TRACE("\n"); 00441 00442 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00443 if(FAILED(hres)) 00444 return hres; 00445 00446 n = arg_cnt(dp); 00447 for(i=0; i < n; i++) { 00448 hres = jsdisp_propput_idx(jsthis, length+i, get_arg(dp, i), ei, sp); 00449 if(FAILED(hres)) 00450 return hres; 00451 } 00452 00453 hres = set_length(jsthis, ei, length+n); 00454 if(FAILED(hres)) 00455 return hres; 00456 00457 if(retv) { 00458 V_VT(retv) = VT_I4; 00459 V_I4(retv) = length+n; 00460 } 00461 return S_OK; 00462 } 00463 00464 static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00465 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00466 { 00467 DispatchEx *jsthis; 00468 DWORD length, k, l; 00469 VARIANT v1, v2; 00470 HRESULT hres1, hres2; 00471 00472 TRACE("\n"); 00473 00474 hres1 = get_length(ctx, vthis, ei, &jsthis, &length); 00475 if(FAILED(hres1)) 00476 return hres1; 00477 00478 for(k=0; k<length/2; k++) { 00479 l = length-k-1; 00480 00481 hres1 = jsdisp_get_idx(jsthis, k, &v1, ei, sp); 00482 if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME) 00483 return hres1; 00484 00485 hres2 = jsdisp_get_idx(jsthis, l, &v2, ei, sp); 00486 if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) { 00487 VariantClear(&v1); 00488 return hres2; 00489 } 00490 00491 if(hres1 == DISP_E_UNKNOWNNAME) 00492 hres1 = jsdisp_delete_idx(jsthis, l); 00493 else 00494 hres1 = jsdisp_propput_idx(jsthis, l, &v1, ei, sp); 00495 00496 if(FAILED(hres1)) { 00497 VariantClear(&v1); 00498 VariantClear(&v2); 00499 return hres1; 00500 } 00501 00502 if(hres2 == DISP_E_UNKNOWNNAME) 00503 hres2 = jsdisp_delete_idx(jsthis, k); 00504 else 00505 hres2 = jsdisp_propput_idx(jsthis, k, &v2, ei, sp); 00506 00507 if(FAILED(hres2)) { 00508 VariantClear(&v2); 00509 return hres2; 00510 } 00511 } 00512 00513 if(retv) { 00514 V_VT(retv) = VT_DISPATCH; 00515 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsthis); 00516 IDispatch_AddRef(V_DISPATCH(retv)); 00517 } 00518 00519 return S_OK; 00520 } 00521 00522 /* ECMA-262 3rd Edition 15.4.4.9 */ 00523 static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00524 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00525 { 00526 DispatchEx *jsthis; 00527 DWORD length = 0, i; 00528 VARIANT v, ret; 00529 HRESULT hres; 00530 00531 TRACE("\n"); 00532 00533 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00534 if(FAILED(hres)) 00535 return hres; 00536 00537 if(!length) { 00538 hres = set_length(jsthis, ei, 0); 00539 if(FAILED(hres)) 00540 return hres; 00541 } 00542 00543 if(!length) { 00544 if(retv) 00545 V_VT(retv) = VT_EMPTY; 00546 return S_OK; 00547 } 00548 00549 hres = jsdisp_get_idx(jsthis, 0, &ret, ei, caller); 00550 if(hres == DISP_E_UNKNOWNNAME) { 00551 V_VT(&ret) = VT_EMPTY; 00552 hres = S_OK; 00553 } 00554 00555 for(i=1; SUCCEEDED(hres) && i<length; i++) { 00556 hres = jsdisp_get_idx(jsthis, i, &v, ei, caller); 00557 if(hres == DISP_E_UNKNOWNNAME) 00558 hres = jsdisp_delete_idx(jsthis, i-1); 00559 else if(SUCCEEDED(hres)) 00560 hres = jsdisp_propput_idx(jsthis, i-1, &v, ei, caller); 00561 } 00562 00563 if(SUCCEEDED(hres)) { 00564 hres = jsdisp_delete_idx(jsthis, length-1); 00565 if(SUCCEEDED(hres)) 00566 hres = set_length(jsthis, ei, length-1); 00567 } 00568 00569 if(SUCCEEDED(hres) && retv) 00570 *retv = ret; 00571 else 00572 VariantClear(&ret); 00573 return hres; 00574 } 00575 00576 /* ECMA-262 3rd Edition 15.4.4.10 */ 00577 static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00578 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00579 { 00580 DispatchEx *arr, *jsthis; 00581 VARIANT v; 00582 DOUBLE range; 00583 DWORD length, start, end, idx; 00584 HRESULT hres; 00585 00586 TRACE("\n"); 00587 00588 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00589 if(FAILED(hres)) 00590 return hres; 00591 00592 if(arg_cnt(dp)) { 00593 hres = to_number(ctx, get_arg(dp, 0), ei, &v); 00594 if(FAILED(hres)) 00595 return hres; 00596 00597 if(V_VT(&v) == VT_I4) 00598 range = V_I4(&v); 00599 else 00600 range = floor(V_R8(&v)); 00601 00602 if(-range>length || isnan(range)) start = 0; 00603 else if(range < 0) start = range+length; 00604 else if(range <= length) start = range; 00605 else start = length; 00606 } 00607 else start = 0; 00608 00609 if(arg_cnt(dp)>1) { 00610 hres = to_number(ctx, get_arg(dp, 1), ei, &v); 00611 if(FAILED(hres)) 00612 return hres; 00613 00614 if(V_VT(&v) == VT_I4) 00615 range = V_I4(&v); 00616 else 00617 range = floor(V_R8(&v)); 00618 00619 if(-range>length) end = 0; 00620 else if(range < 0) end = range+length; 00621 else if(range <= length) end = range; 00622 else end = length; 00623 } 00624 else end = length; 00625 00626 hres = create_array(ctx, (end>start)?end-start:0, &arr); 00627 if(FAILED(hres)) 00628 return hres; 00629 00630 for(idx=start; idx<end; idx++) { 00631 hres = jsdisp_get_idx(jsthis, idx, &v, ei, sp); 00632 if(hres == DISP_E_UNKNOWNNAME) 00633 continue; 00634 00635 if(SUCCEEDED(hres)) { 00636 hres = jsdisp_propput_idx(arr, idx-start, &v, ei, sp); 00637 VariantClear(&v); 00638 } 00639 00640 if(FAILED(hres)) { 00641 jsdisp_release(arr); 00642 return hres; 00643 } 00644 } 00645 00646 if(retv) { 00647 V_VT(retv) = VT_DISPATCH; 00648 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(arr); 00649 } 00650 else 00651 jsdisp_release(arr); 00652 00653 return S_OK; 00654 } 00655 00656 static HRESULT sort_cmp(script_ctx_t *ctx, DispatchEx *cmp_func, VARIANT *v1, VARIANT *v2, jsexcept_t *ei, 00657 IServiceProvider *caller, INT *cmp) 00658 { 00659 HRESULT hres; 00660 00661 if(cmp_func) { 00662 VARIANTARG args[2]; 00663 DISPPARAMS dp = {args, NULL, 2, 0}; 00664 VARIANT tmp; 00665 VARIANT res; 00666 00667 args[0] = *v2; 00668 args[1] = *v1; 00669 00670 hres = jsdisp_call_value(cmp_func, DISPATCH_METHOD, &dp, &res, ei, caller); 00671 if(FAILED(hres)) 00672 return hres; 00673 00674 hres = to_number(ctx, &res, ei, &tmp); 00675 VariantClear(&res); 00676 if(FAILED(hres)) 00677 return hres; 00678 00679 if(V_VT(&tmp) == VT_I4) 00680 *cmp = V_I4(&tmp); 00681 else 00682 *cmp = V_R8(&tmp) > 0.0 ? 1 : -1; 00683 }else if(V_VT(v1) == VT_EMPTY) { 00684 *cmp = V_VT(v2) == VT_EMPTY ? 0 : 1; 00685 }else if(V_VT(v2) == VT_EMPTY) { 00686 *cmp = -1; 00687 }else if(is_num_vt(V_VT(v1)) && is_num_vt(V_VT(v2))) { 00688 DOUBLE d = num_val(v1)-num_val(v2); 00689 if(d > 0.0) 00690 *cmp = 1; 00691 else 00692 *cmp = d < -0.0 ? -1 : 0; 00693 }else { 00694 BSTR x, y; 00695 00696 hres = to_string(ctx, v1, ei, &x); 00697 if(FAILED(hres)) 00698 return hres; 00699 00700 hres = to_string(ctx, v2, ei, &y); 00701 if(SUCCEEDED(hres)) { 00702 *cmp = strcmpW(x, y); 00703 SysFreeString(y); 00704 } 00705 SysFreeString(x); 00706 if(FAILED(hres)) 00707 return hres; 00708 } 00709 00710 return S_OK; 00711 } 00712 00713 /* ECMA-262 3rd Edition 15.4.4.11 */ 00714 static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00715 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00716 { 00717 DispatchEx *jsthis, *cmp_func = NULL; 00718 VARIANT *vtab, **sorttab = NULL; 00719 DWORD length; 00720 DWORD i; 00721 HRESULT hres = S_OK; 00722 00723 TRACE("\n"); 00724 00725 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00726 if(FAILED(hres)) 00727 return hres; 00728 00729 if(arg_cnt(dp) > 1) { 00730 WARN("invalid arg_cnt %d\n", arg_cnt(dp)); 00731 return E_FAIL; 00732 } 00733 00734 if(arg_cnt(dp) == 1) { 00735 VARIANT *arg = get_arg(dp, 0); 00736 00737 if(V_VT(arg) != VT_DISPATCH) { 00738 WARN("arg is not dispatch\n"); 00739 return E_FAIL; 00740 } 00741 00742 00743 cmp_func = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg)); 00744 if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) { 00745 WARN("cmp_func is not a function\n"); 00746 if(cmp_func) 00747 jsdisp_release(cmp_func); 00748 return E_FAIL; 00749 } 00750 } 00751 00752 if(!length) { 00753 if(cmp_func) 00754 jsdisp_release(cmp_func); 00755 if(retv) { 00756 V_VT(retv) = VT_DISPATCH; 00757 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsthis); 00758 IDispatch_AddRef(V_DISPATCH(retv)); 00759 } 00760 return S_OK; 00761 } 00762 00763 vtab = heap_alloc_zero(length * sizeof(VARIANT)); 00764 if(vtab) { 00765 for(i=0; i<length; i++) { 00766 hres = jsdisp_get_idx(jsthis, i, vtab+i, ei, caller); 00767 if(hres == DISP_E_UNKNOWNNAME) { 00768 V_VT(vtab+i) = VT_EMPTY; 00769 hres = S_OK; 00770 } else if(FAILED(hres)) { 00771 WARN("Could not get elem %d: %08x\n", i, hres); 00772 break; 00773 } 00774 } 00775 }else { 00776 hres = E_OUTOFMEMORY; 00777 } 00778 00779 if(SUCCEEDED(hres)) { 00780 sorttab = heap_alloc(length*2*sizeof(VARIANT*)); 00781 if(!sorttab) 00782 hres = E_OUTOFMEMORY; 00783 } 00784 00785 /* merge-sort */ 00786 if(SUCCEEDED(hres)) { 00787 VARIANT *tmpv, **tmpbuf; 00788 INT cmp; 00789 00790 tmpbuf = sorttab + length; 00791 for(i=0; i < length; i++) 00792 sorttab[i] = vtab+i; 00793 00794 for(i=0; i < length/2; i++) { 00795 hres = sort_cmp(ctx, cmp_func, sorttab[2*i+1], sorttab[2*i], ei, caller, &cmp); 00796 if(FAILED(hres)) 00797 break; 00798 00799 if(cmp < 0) { 00800 tmpv = sorttab[2*i]; 00801 sorttab[2*i] = sorttab[2*i+1]; 00802 sorttab[2*i+1] = tmpv; 00803 } 00804 } 00805 00806 if(SUCCEEDED(hres)) { 00807 DWORD k, a, b, bend; 00808 00809 for(k=2; k < length; k *= 2) { 00810 for(i=0; i+k < length; i += 2*k) { 00811 a = b = 0; 00812 if(i+2*k <= length) 00813 bend = k; 00814 else 00815 bend = length - (i+k); 00816 00817 memcpy(tmpbuf, sorttab+i, k*sizeof(VARIANT*)); 00818 00819 while(a < k && b < bend) { 00820 hres = sort_cmp(ctx, cmp_func, tmpbuf[a], sorttab[i+k+b], ei, caller, &cmp); 00821 if(FAILED(hres)) 00822 break; 00823 00824 if(cmp < 0) { 00825 sorttab[i+a+b] = tmpbuf[a]; 00826 a++; 00827 }else { 00828 sorttab[i+a+b] = sorttab[i+k+b]; 00829 b++; 00830 } 00831 } 00832 00833 if(FAILED(hres)) 00834 break; 00835 00836 if(a < k) 00837 memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(VARIANT*)); 00838 } 00839 00840 if(FAILED(hres)) 00841 break; 00842 } 00843 } 00844 00845 for(i=0; SUCCEEDED(hres) && i < length; i++) 00846 hres = jsdisp_propput_idx(jsthis, i, sorttab[i], ei, caller); 00847 } 00848 00849 if(vtab) { 00850 for(i=0; i < length; i++) 00851 VariantClear(vtab+i); 00852 heap_free(vtab); 00853 } 00854 heap_free(sorttab); 00855 if(cmp_func) 00856 jsdisp_release(cmp_func); 00857 00858 if(FAILED(hres)) 00859 return hres; 00860 00861 if(retv) { 00862 V_VT(retv) = VT_DISPATCH; 00863 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(jsthis); 00864 IDispatch_AddRef(V_DISPATCH(retv)); 00865 } 00866 00867 return S_OK; 00868 } 00869 00870 /* ECMA-262 3rd Edition 15.4.4.12 */ 00871 static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00872 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 00873 { 00874 DWORD length, start=0, delete_cnt=0, argc, i, add_args = 0; 00875 DispatchEx *ret_array = NULL, *jsthis; 00876 VARIANT v; 00877 HRESULT hres = S_OK; 00878 00879 TRACE("\n"); 00880 00881 hres = get_length(ctx, vthis, ei, &jsthis, &length); 00882 if(FAILED(hres)) 00883 return hres; 00884 00885 argc = arg_cnt(dp); 00886 if(argc >= 1) { 00887 hres = to_integer(ctx, get_arg(dp,0), ei, &v); 00888 if(FAILED(hres)) 00889 return hres; 00890 00891 if(V_VT(&v) == VT_I4) { 00892 if(V_I4(&v) >= 0) 00893 start = min(V_I4(&v), length); 00894 else 00895 start = -V_I4(&v) > length ? 0 : length + V_I4(&v); 00896 }else { 00897 start = V_R8(&v) < 0.0 ? 0 : length; 00898 } 00899 } 00900 00901 if(argc >= 2) { 00902 hres = to_integer(ctx, get_arg(dp,1), ei, &v); 00903 if(FAILED(hres)) 00904 return hres; 00905 00906 if(V_VT(&v) == VT_I4) { 00907 if(V_I4(&v) > 0) 00908 delete_cnt = min(V_I4(&v), length-start); 00909 }else if(V_R8(&v) > 0.0) { 00910 delete_cnt = length-start; 00911 } 00912 00913 add_args = argc-2; 00914 } 00915 00916 if(retv) { 00917 hres = create_array(ctx, 0, &ret_array); 00918 if(FAILED(hres)) 00919 return hres; 00920 00921 for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) { 00922 hres = jsdisp_get_idx(jsthis, start+i, &v, ei, caller); 00923 if(hres == DISP_E_UNKNOWNNAME) 00924 hres = S_OK; 00925 else if(SUCCEEDED(hres)) 00926 hres = jsdisp_propput_idx(ret_array, i, &v, ei, caller); 00927 } 00928 00929 if(SUCCEEDED(hres)) { 00930 V_VT(&v) = VT_I4; 00931 V_I4(&v) = delete_cnt; 00932 00933 hres = jsdisp_propput_name(ret_array, lengthW, &v, ei, caller); 00934 } 00935 } 00936 00937 if(add_args < delete_cnt) { 00938 for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) { 00939 hres = jsdisp_get_idx(jsthis, i+delete_cnt, &v, ei, caller); 00940 if(hres == DISP_E_UNKNOWNNAME) 00941 hres = jsdisp_delete_idx(jsthis, i+add_args); 00942 else if(SUCCEEDED(hres)) 00943 hres = jsdisp_propput_idx(jsthis, i+add_args, &v, ei, caller); 00944 } 00945 00946 for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--) 00947 hres = jsdisp_delete_idx(jsthis, i-1); 00948 }else if(add_args > delete_cnt) { 00949 for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) { 00950 hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &v, ei, caller); 00951 if(hres == DISP_E_UNKNOWNNAME) 00952 hres = jsdisp_delete_idx(jsthis, i+add_args-1); 00953 else if(SUCCEEDED(hres)) 00954 hres = jsdisp_propput_idx(jsthis, i+add_args-1, &v, ei, caller); 00955 } 00956 } 00957 00958 for(i=0; SUCCEEDED(hres) && i < add_args; i++) 00959 hres = jsdisp_propput_idx(jsthis, start+i, get_arg(dp,i+2), ei, caller); 00960 00961 if(SUCCEEDED(hres)) { 00962 V_VT(&v) = VT_I4; 00963 V_I4(&v) = length-delete_cnt+add_args; 00964 hres = jsdisp_propput_name(jsthis, lengthW, &v, ei, caller); 00965 } 00966 00967 if(FAILED(hres)) { 00968 if(ret_array) 00969 jsdisp_release(ret_array); 00970 return hres; 00971 } 00972 00973 if(retv) { 00974 V_VT(retv) = VT_DISPATCH; 00975 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret_array); 00976 } 00977 return S_OK; 00978 } 00979 00980 /* ECMA-262 3rd Edition 15.4.4.2 */ 00981 static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 00982 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00983 { 00984 ArrayInstance *array; 00985 00986 TRACE("\n"); 00987 00988 array = array_this(jsthis); 00989 if(!array) 00990 return throw_type_error(ctx, ei, IDS_ARRAY_EXPECTED, NULL); 00991 00992 return array_join(ctx, &array->dispex, array->length, default_separatorW, retv, ei, sp); 00993 } 00994 00995 static HRESULT Array_toLocaleString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 00996 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 00997 { 00998 FIXME("\n"); 00999 return E_NOTIMPL; 01000 } 01001 01002 /* ECMA-262 3rd Edition 15.4.4.13 */ 01003 static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 01004 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 01005 { 01006 DispatchEx *jsthis; 01007 WCHAR buf[14], *buf_end, *str; 01008 DWORD argc, i, length; 01009 VARIANT var; 01010 DISPID id; 01011 HRESULT hres; 01012 01013 TRACE("\n"); 01014 01015 hres = get_length(ctx, vthis, ei, &jsthis, &length); 01016 if(FAILED(hres)) 01017 return hres; 01018 01019 argc = arg_cnt(dp); 01020 if(argc) { 01021 buf_end = buf + sizeof(buf)/sizeof(WCHAR)-1; 01022 *buf_end-- = 0; 01023 i = length; 01024 01025 while(i--) { 01026 str = idx_to_str(i, buf_end); 01027 01028 hres = jsdisp_get_id(jsthis, str, 0, &id); 01029 if(SUCCEEDED(hres)) { 01030 hres = jsdisp_propget(jsthis, id, &var, ei, caller); 01031 if(FAILED(hres)) 01032 return hres; 01033 01034 hres = jsdisp_propput_idx(jsthis, i+argc, &var, ei, caller); 01035 VariantClear(&var); 01036 }else if(hres == DISP_E_UNKNOWNNAME) { 01037 hres = IDispatchEx_DeleteMemberByDispID(vthis->u.dispex, id); 01038 } 01039 } 01040 01041 if(FAILED(hres)) 01042 return hres; 01043 } 01044 01045 for(i=0; i<argc; i++) { 01046 hres = jsdisp_propput_idx(jsthis, i, get_arg(dp,i), ei, caller); 01047 if(FAILED(hres)) 01048 return hres; 01049 } 01050 01051 if(argc) { 01052 length += argc; 01053 hres = set_length(jsthis, ei, length); 01054 if(FAILED(hres)) 01055 return hres; 01056 } 01057 01058 if(retv) { 01059 if(ctx->version < 2) { 01060 V_VT(retv) = VT_EMPTY; 01061 }else { 01062 V_VT(retv) = VT_I4; 01063 V_I4(retv) = length; 01064 } 01065 } 01066 return S_OK; 01067 } 01068 01069 static HRESULT Array_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, 01070 VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) 01071 { 01072 TRACE("\n"); 01073 01074 switch(flags) { 01075 case INVOKE_FUNC: 01076 return throw_type_error(ctx, ei, IDS_NOT_FUNC, NULL); 01077 case INVOKE_PROPERTYGET: 01078 return array_join(ctx, jsthis->u.jsdisp, array_from_vdisp(jsthis)->length, default_separatorW, retv, ei, sp); 01079 default: 01080 FIXME("unimplemented flags %x\n", flags); 01081 return E_NOTIMPL; 01082 } 01083 01084 return S_OK; 01085 } 01086 01087 static void Array_destructor(DispatchEx *dispex) 01088 { 01089 heap_free(dispex); 01090 } 01091 01092 static void Array_on_put(DispatchEx *dispex, const WCHAR *name) 01093 { 01094 ArrayInstance *array = (ArrayInstance*)dispex; 01095 const WCHAR *ptr = name; 01096 DWORD id = 0; 01097 01098 if(!isdigitW(*ptr)) 01099 return; 01100 01101 while(*ptr && isdigitW(*ptr)) { 01102 id = id*10 + (*ptr-'0'); 01103 ptr++; 01104 } 01105 01106 if(*ptr) 01107 return; 01108 01109 if(id >= array->length) 01110 array->length = id+1; 01111 } 01112 01113 static const builtin_prop_t Array_props[] = { 01114 {concatW, Array_concat, PROPF_METHOD|1}, 01115 {joinW, Array_join, PROPF_METHOD|1}, 01116 {lengthW, Array_length, 0}, 01117 {popW, Array_pop, PROPF_METHOD}, 01118 {pushW, Array_push, PROPF_METHOD|1}, 01119 {reverseW, Array_reverse, PROPF_METHOD}, 01120 {shiftW, Array_shift, PROPF_METHOD}, 01121 {sliceW, Array_slice, PROPF_METHOD|2}, 01122 {sortW, Array_sort, PROPF_METHOD|1}, 01123 {spliceW, Array_splice, PROPF_METHOD|2}, 01124 {toLocaleStringW, Array_toLocaleString, PROPF_METHOD}, 01125 {toStringW, Array_toString, PROPF_METHOD}, 01126 {unshiftW, Array_unshift, PROPF_METHOD|1}, 01127 }; 01128 01129 static const builtin_info_t Array_info = { 01130 JSCLASS_ARRAY, 01131 {NULL, Array_value, 0}, 01132 sizeof(Array_props)/sizeof(*Array_props), 01133 Array_props, 01134 Array_destructor, 01135 Array_on_put 01136 }; 01137 01138 static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, 01139 VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) 01140 { 01141 DispatchEx *obj; 01142 VARIANT *arg_var; 01143 DWORD i; 01144 HRESULT hres; 01145 01146 TRACE("\n"); 01147 01148 switch(flags) { 01149 case DISPATCH_METHOD: 01150 case DISPATCH_CONSTRUCT: { 01151 if(arg_cnt(dp) == 1 && V_VT((arg_var = get_arg(dp, 0))) == VT_I4) { 01152 if(V_I4(arg_var) < 0) 01153 return throw_range_error(ctx, ei, IDS_INVALID_LENGTH, NULL); 01154 01155 hres = create_array(ctx, V_I4(arg_var), &obj); 01156 if(FAILED(hres)) 01157 return hres; 01158 01159 V_VT(retv) = VT_DISPATCH; 01160 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj); 01161 return S_OK; 01162 } 01163 01164 hres = create_array(ctx, arg_cnt(dp), &obj); 01165 if(FAILED(hres)) 01166 return hres; 01167 01168 for(i=0; i < arg_cnt(dp); i++) { 01169 hres = jsdisp_propput_idx(obj, i, get_arg(dp, i), ei, caller); 01170 if(FAILED(hres)) 01171 break; 01172 } 01173 if(FAILED(hres)) { 01174 jsdisp_release(obj); 01175 return hres; 01176 } 01177 01178 V_VT(retv) = VT_DISPATCH; 01179 V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(obj); 01180 break; 01181 } 01182 default: 01183 FIXME("unimplemented flags: %x\n", flags); 01184 return E_NOTIMPL; 01185 } 01186 01187 return S_OK; 01188 } 01189 01190 static HRESULT alloc_array(script_ctx_t *ctx, DispatchEx *object_prototype, ArrayInstance **ret) 01191 { 01192 ArrayInstance *array; 01193 HRESULT hres; 01194 01195 array = heap_alloc_zero(sizeof(ArrayInstance)); 01196 if(!array) 01197 return E_OUTOFMEMORY; 01198 01199 if(object_prototype) 01200 hres = init_dispex(&array->dispex, ctx, &Array_info, object_prototype); 01201 else 01202 hres = init_dispex_from_constr(&array->dispex, ctx, &Array_info, ctx->array_constr); 01203 01204 if(FAILED(hres)) { 01205 heap_free(array); 01206 return hres; 01207 } 01208 01209 *ret = array; 01210 return S_OK; 01211 } 01212 01213 HRESULT create_array_constr(script_ctx_t *ctx, DispatchEx *object_prototype, DispatchEx **ret) 01214 { 01215 ArrayInstance *array; 01216 HRESULT hres; 01217 01218 static const WCHAR ArrayW[] = {'A','r','r','a','y',0}; 01219 01220 hres = alloc_array(ctx, object_prototype, &array); 01221 if(FAILED(hres)) 01222 return hres; 01223 01224 hres = create_builtin_function(ctx, ArrayConstr_value, ArrayW, NULL, PROPF_CONSTR|1, &array->dispex, ret); 01225 01226 jsdisp_release(&array->dispex); 01227 return hres; 01228 } 01229 01230 HRESULT create_array(script_ctx_t *ctx, DWORD length, DispatchEx **ret) 01231 { 01232 ArrayInstance *array; 01233 HRESULT hres; 01234 01235 hres = alloc_array(ctx, NULL, &array); 01236 if(FAILED(hres)) 01237 return hres; 01238 01239 array->length = length; 01240 01241 *ret = &array->dispex; 01242 return S_OK; 01243 } Generated on Sun May 27 2012 04:24:19 for ReactOS by
1.7.6.1
|