Enumerator is an MS extension.
This fixes installatiion of VyChat219.msi.
Signed-off-by: Andreas Maier <staubim(a)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