Enumerator is an MS extension. This fixes installatiion of VyChat219.msi.
Signed-off-by: Andreas Maier staubim@quantentunnel.de --- dlls/jscript/Makefile.in | 1 + dlls/jscript/enumerator.c | 455 +++++++++++++++++++++++++++++++++++++++++++++ dlls/jscript/global.c | 18 +- dlls/jscript/jscript.h | 10 + dlls/jscript/jsglobal.idl | 3 - dlls/jscript/tests/rsrc.rc | 3 + dlls/jscript/tests/run.c | 1 + 7 files changed, 480 insertions(+), 11 deletions(-) create mode 100644 dlls/jscript/enumerator.c
diff --git a/dlls/jscript/Makefile.in b/dlls/jscript/Makefile.in index 34ed193742..1cc58a5ed6 100644 --- a/dlls/jscript/Makefile.in +++ b/dlls/jscript/Makefile.in @@ -10,6 +10,7 @@ C_SRCS = \ decode.c \ dispex.c \ engine.c \ + enumerator.c \ error.c \ function.c \ global.c \ diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c new file mode 100644 index 0000000000..bd05cdf4da --- /dev/null +++ b/dlls/jscript/enumerator.c @@ -0,0 +1,455 @@ +/* + * Copyright 2019 Andreas Maier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include <math.h> +#include <assert.h> + +#include "jscript.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(jscript); + +#define DATATYPE_ARRAY 0 +#define DATATYPE_STRINGLIST 1 +#define DATATYPE_DRIVECOLLECTION 2 + +typedef struct { + jsdisp_t dispex; + + int index; + int length; + int datatype; + /* constructor with jsarray e.g. ["A","B"] */ + jsdisp_t *array; + /* constructor with stringlist-interface + methods Items and Count are available. + e.g. StringList or IDriveCollection-Interface */ + IDispatch *stringlist; +} EnumeratorInstance; + +static const WCHAR atEndW[] = {'a','t','E','n','d',0}; +static const WCHAR itemW[] = {'i','t','e','m',0}; +static const WCHAR moveFirstW[] = {'m','o','v','e','F','i','r','s','t',0}; +static const WCHAR moveNextW[] = {'m','o','v','e','N','e','x','t',0}; + +static EXCEPINFO excepinfo; +static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult) +{ + OLECHAR *name = NULL; + DISPID dispid; + HRESULT hr; + UINT i; + UINT len; + + memset(pVarResult, 0, sizeof(VARIANT)); + VariantInit(pVarResult); + + len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 ); + name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) ); + if (!name) return E_FAIL; + MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len ); + hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); + HeapFree(GetProcessHeap(), 0, name); + if (FAILED(hr)) + return hr; + + memset(&excepinfo, 0, sizeof(excepinfo)); + hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL); + + if ((hr == S_OK) && (vtResult != VT_EMPTY)) + hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult); + + for (i=0; i<pDispParams->cArgs; i++) + VariantClear(&pDispParams->rgvarg[i]); + + return hr; +} + +static HRESULT Dispatch_ItemAllocStr(IDispatch *pStringList, int iIndex, LPWSTR *szString) +{ + VARIANT varresult; + VARIANTARG vararg[1]; + DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; + UINT charCount; + HRESULT hr; + + *szString = NULL; + + VariantInit(&vararg[0]); + V_VT(&vararg[0]) = VT_I4; + V_I4(&vararg[0]) = iIndex; + + hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); + if (FAILED(hr)) + goto CLEANUP; + + charCount = SysStringLen(V_BSTR(&varresult)) + 1; + *szString = (LPWSTR)malloc(charCount * sizeof(WCHAR)); + if (!(*szString)) + { + hr = ERROR_OUTOFMEMORY; + goto CLEANUP; + } + if (!lstrcpynW(*szString, V_BSTR(&varresult), charCount)) + { + hr = E_FAIL; + goto CLEANUP; + } +CLEANUP: + VariantClear(&varresult); + if (FAILED(hr)) + { + free(*szString); + *szString = NULL; + } + return hr; +} + +static HRESULT Dispatch_Count(IDispatch *pStringList, int *pCount) +{ + VARIANT varresult; + DISPPARAMS dispparams = {NULL, NULL, 0, 0}; + HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); + *pCount = V_I4(&varresult); + VariantClear(&varresult); + return hr; +} + +static inline EnumeratorInstance *enumerator_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, EnumeratorInstance, dispex); +} + +static inline EnumeratorInstance *enumerator_from_vdisp(vdisp_t *vdisp) +{ + return enumerator_from_jsdisp(vdisp->u.jsdisp); +} + +static inline void enum_set_item_result(EnumeratorInstance *This, jsval_t *r) +{ + HRESULT hres; + WCHAR* item; + + if (!r) + return; + + if ((This->index < 0) || + (This->index >= This->length)) + { + *r = jsval_undefined(); + return; + } + + switch (This->datatype) + { + case DATATYPE_ARRAY: + { + hres = jsdisp_get_idx(This->array, This->index, r); + if (FAILED(hres)) + *r = jsval_undefined(); + break; + } + case DATATYPE_STRINGLIST: + { + hres = Dispatch_ItemAllocStr(This->stringlist, This->index, &item); + if (FAILED(hres)) + { + TRACE("item %d <failed>\n", This->index); + *r = jsval_undefined(); + } else + { + TRACE("item %d %s\n", This->index, debugstr_w(item)); + *r = jsval_string(jsstr_alloc(item)); + free(item); + } + break; + } + case DATATYPE_DRIVECOLLECTION: + { + FIXME("getitem for drivecollection not implemented!\n"); + *r = jsval_undefined(); + break; + } + default: + { + *r = jsval_undefined(); + } + } +} + +static void Enumerator_destructor(jsdisp_t *dispex) +{ + EnumeratorInstance *This; + + This = enumerator_from_jsdisp(dispex); + if (This->array) + jsdisp_release(This->array); + if (This->stringlist) + IDispatch_Release(This->stringlist); + + TRACE("Enumerator_destructor\n"); + + heap_free(dispex); +} + +HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + EnumeratorInstance *This; + + This = enumerator_from_vdisp(jsthis); + + if (r) + *r = jsval_bool(This->index >= This->length); + + TRACE("Enumerator_atEnd %i %i\n", This->length, This->index); + + return S_OK; +} + +HRESULT Enumerator_item(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + EnumeratorInstance *This; + + TRACE("Enumerator_item\n"); + + This = enumerator_from_vdisp(jsthis); + + enum_set_item_result(This, r); + + return S_OK; +} + +HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + EnumeratorInstance *This; + + TRACE("Enumerator_moveFirst\n"); + + This = enumerator_from_vdisp(jsthis); + This->index = 0; + + enum_set_item_result(This, r); + + return S_OK; +} + +HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + EnumeratorInstance *This; + + This = enumerator_from_vdisp(jsthis); + + TRACE("Enumerator_moveNext\n"); + + if (This->index < This->length) + This->index++; + + enum_set_item_result(This, r); + + + return S_OK; +} + +static const builtin_prop_t Enumerator_props[] = { + {atEndW, Enumerator_atEnd, PROPF_METHOD}, + {itemW, Enumerator_item, PROPF_METHOD}, + {moveFirstW, Enumerator_moveFirst, PROPF_METHOD}, + {moveNextW, Enumerator_moveNext, PROPF_METHOD}, +}; + +static const builtin_info_t Enumerator_info = { + JSCLASS_OBJECT, + {NULL, NULL, 0}, + ARRAY_SIZE(Enumerator_props), + Enumerator_props, + NULL, + NULL +}; + +static const builtin_info_t EnumeratorInst_info = { + JSCLASS_OBJECT, + {NULL, NULL, 0, NULL}, + 0, + NULL, + Enumerator_destructor, + NULL +}; + +static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + jsdisp_t *obj; + HRESULT hres; + + TRACE("EnumeratorConstr_value\n"); + + switch(flags) { + case DISPATCH_CONSTRUCT: { + if (argc != 1) + return throw_syntax_error(ctx, JS_E_MISSING_ARG, NULL); + + hres = create_enumerator(ctx, &argv[0], &obj); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(obj); + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret) +{ + EnumeratorInstance *enumerator; + HRESULT hres; + + enumerator = heap_alloc_zero(sizeof(EnumeratorInstance)); + if(!enumerator) + return E_OUTOFMEMORY; + + if(object_prototype) + hres = init_dispex(&enumerator->dispex, ctx, &Enumerator_info, object_prototype); + else + hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info, + ctx->enumerator_constr); + + if(FAILED(hres)) { + heap_free(enumerator); + return hres; + } + + *ret = enumerator; + return S_OK; +} + +static const builtin_info_t EnumeratorConstr_info = { + JSCLASS_FUNCTION, + DEFAULT_FUNCTION_VALUE, + 0, + NULL, + NULL, + NULL +}; + +HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) +{ + EnumeratorInstance *enumerator; + HRESULT hres; + static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0}; + + hres = alloc_enumerator(ctx, object_prototype, &enumerator); + if(FAILED(hres)) + return hres; + + hres = create_builtin_constructor(ctx, EnumeratorConstr_value, + EnumeratorW, &EnumeratorConstr_info, + PROPF_CONSTR|1, &enumerator->dispex, ret); + jsdisp_release(&enumerator->dispex); + + return hres; +} + +HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret) +{ + EnumeratorInstance *enumerator; + HRESULT hres; + IDispatch *dummy; + IDispatch *obj = NULL; + + int jsdatatype = -1; + int jslength = 0; + jsdisp_t *jsarray = NULL; + IDispatch *jsstringlist = NULL; + + if(is_object_instance(*argv)) + { + obj = get_object(*argv); + jsarray = iface_to_jsdisp(obj); + if ((jsarray) && + (is_class(jsarray, JSCLASS_ARRAY))) + { + TRACE("array\n"); + jsdatatype = DATATYPE_ARRAY; + jslength = array_get_length(jsarray); + } + else + { + if (jsarray) + jsdisp_release(jsarray); + /* check if its a stringlist or drivecollection */ + if (SUCCEEDED(IDispatch_QueryInterface(obj, &IID_StringList, (void*)&dummy))) + { + TRACE("Enumerator: stringlist\n"); + jsdatatype = DATATYPE_STRINGLIST; + } + else if (SUCCEEDED(IDispatch_QueryInterface(obj, &IID_IDriveCollection, (void*)&dummy))) + { + TRACE("Enumerator: drivecollection\n"); + jsdatatype = DATATYPE_DRIVECOLLECTION; + } + else + { + FIXME("Enumerator: unexpected type!\n"); + return E_INVALIDARG; + } + + hres = Dispatch_Count(obj, &jslength); + if (FAILED(hres)) + { + ERR("Dispatch_Count failed %d\n", hres); + return -1; + } + TRACE("Count %i\n", jslength); + + jsstringlist = obj; + } + } + else + { + FIXME("type not implemented!\n"); + return E_NOTIMPL; + } + + hres = alloc_enumerator(ctx, NULL, &enumerator); + if(FAILED(hres)) + return hres; + + if (jsstringlist) + IDispatch_AddRef(jsstringlist); + enumerator->index = 0; + enumerator->length = jslength; + enumerator->datatype = jsdatatype; + enumerator->array = jsarray; + enumerator->stringlist = jsstringlist; + + *ret = &enumerator->dispex; + return S_OK; +} diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 33de641483..61a756be0e 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -113,13 +113,6 @@ static WCHAR int_to_char(int i) return 'A'+i-10; }
-static HRESULT JSGlobal_Enumerator(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, - jsval_t *r) -{ - FIXME("\n"); - return E_NOTIMPL; -} - static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -942,7 +935,6 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W
static const builtin_prop_t JSGlobal_props[] = { {CollectGarbageW, JSGlobal_CollectGarbage, PROPF_METHOD}, - {EnumeratorW, JSGlobal_Enumerator, PROPF_METHOD|7}, {_GetObjectW, JSGlobal_GetObject, PROPF_METHOD|2}, {ScriptEngineW, JSGlobal_ScriptEngine, PROPF_METHOD}, {ScriptEngineBuildVersionW, JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD}, @@ -1019,6 +1011,16 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres;
+ hres = create_enumerator_constr(ctx, object_prototype, &ctx->enumerator_constr); + if(FAILED(hres)) + return hres; + + /* Enumerator is a MS extension */ + hres = jsdisp_define_data_property(ctx->global, EnumeratorW, PROPF_WRITABLE, + jsval_obj(ctx->enumerator_constr)); + if(FAILED(hres)) + return hres; + hres = init_error_constr(ctx, object_prototype); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 2af5b598bd..de539b77b1 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -326,6 +326,7 @@ HRESULT create_bool(script_ctx_t*,BOOL,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_number(script_ctx_t*,double,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_vbarray(script_ctx_t*,SAFEARRAY*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_json(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; +HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret) DECLSPEC_HIDDEN;
typedef enum { NO_HINT, @@ -436,6 +437,7 @@ struct _script_ctx_t { jsdisp_t *array_constr; jsdisp_t *bool_constr; jsdisp_t *date_constr; + jsdisp_t *enumerator_constr; jsdisp_t *error_constr; jsdisp_t *eval_error_constr; jsdisp_t *range_error_constr; @@ -468,6 +470,7 @@ HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_bool_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_date_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT init_error_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN; +HRESULT create_enumerator_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_number_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_object_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_regexp_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; @@ -590,3 +593,10 @@ static inline void unlock_module(void) { InterlockedDecrement(&module_ref); } + +/* Stringlist_xxx-functions borrowed from wintest (msi) + * FIXME: share it to avoid code duplication ... + */ +/* all these interface have the same item and count-property :-) */ +DEFINE_GUID(IID_StringList, 0x000C1095, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +DEFINE_GUID(IID_IDriveCollection, 0xc7c3f5a1, 0x88a3, 0x11d0, 0xab, 0xcb, 0x00, 0xa0, 0xc9, 0x0f, 0xff, 0xc0); diff --git a/dlls/jscript/jsglobal.idl b/dlls/jscript/jsglobal.idl index b8604e99f2..7e0c1a30cf 100644 --- a/dlls/jscript/jsglobal.idl +++ b/dlls/jscript/jsglobal.idl @@ -74,9 +74,6 @@ library JSGlobal [id(DISPID_GLOBAL_VBARRAY)] VARIANT VBArray();
- [id(DISPID_GLOBAL_ENUMERATOR)] - VARIANT Enumerator(); - [id(DISPID_GLOBAL_ESCAPE)] VARIANT escape(VARIANT String);
diff --git a/dlls/jscript/tests/rsrc.rc b/dlls/jscript/tests/rsrc.rc index d9ee6b23ae..b130df294a 100644 --- a/dlls/jscript/tests/rsrc.rc +++ b/dlls/jscript/tests/rsrc.rc @@ -25,6 +25,9 @@ cc.js 40 "cc.js" /* @makedep: lang.js */ lang.js 40 "lang.js"
+/* @makedep: extension.js */ +extension.js 40 "extension.js" + /* @makedep: regexp.js */ regexp.js 40 "regexp.js"
diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index aadb31700d..9e92a418f1 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -2684,6 +2684,7 @@ static BOOL run_tests(void)
run_from_res("lang.js"); run_from_res("api.js"); + run_from_res("extension.js"); run_from_res("regexp.js"); run_from_res("cc.js");
-- 2.11.0