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

array.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 doxygen 1.7.6.1

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