Signed-off-by: Andreas Maier staubim@quantentunnel.de --- dlls/jscript/enumerator.c | 227 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 216 insertions(+), 11 deletions(-)
diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index aa7737ac52..a7cad81c8a 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -26,6 +26,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript);
typedef struct { jsdisp_t dispex; + BOOL atend; + /* IEnumVARIANT returned by _NewEnum */ + IEnumVARIANT *enumvar; + /* IEnumVARIANT current item */ + VARIANT* enumitm; } EnumeratorInstance;
static const WCHAR atEndW[] = {'a','t','E','n','d',0}; @@ -33,43 +38,156 @@ 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 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 HRESULT enumvar_get_next_item( + IEnumVARIANT* enumvar, VARIANT* enumitm, + BOOL* atend, jsval_t *r) +{ + HRESULT hres; + + /* not at end ... get next item */ + if (!(*atend)) + { + /* Assume valid variant */ + VariantClear(enumitm); + hres = IEnumVARIANT_Next(enumvar, 1, enumitm, NULL); + if (hres != S_OK) + { + VariantClear(enumitm); + *atend = TRUE; + } + } + + if (*atend) + { + if (r) + *r = jsval_undefined(); + return S_OK; + } + + if (r) + return variant_to_jsval(enumitm, r); + + return S_OK; +} + static void Enumerator_destructor(jsdisp_t *dispex) { + EnumeratorInstance *This; + TRACE("Enumerator_destructor\n");
+ This = enumerator_from_jsdisp(dispex); + + if (This->enumitm) + { + VariantClear(This->enumitm); + heap_free(This->enumitm); + } + heap_free(dispex); }
HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - TRACE("Enumerator_atEnd\n"); + EnumeratorInstance *This; + + This = enumerator_from_vdisp(jsthis);
- return E_NOTIMPL; + if (r) + *r = jsval_bool(This->atend); + + TRACE("Enumerator_atEnd %d\n", This->atend); + + 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; + HRESULT hres = E_FAIL; + TRACE("Enumerator_item\n");
- return E_NOTIMPL; + This = enumerator_from_vdisp(jsthis); + + if (This->enumvar) + { + hres = variant_to_jsval(This->enumitm, r); + } + else + { + if (r) + *r = jsval_undefined(); + hres = S_OK; + } + + return hres; }
HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + EnumeratorInstance *This; + HRESULT hres = E_FAIL; + TRACE("Enumerator_moveFirst\n");
- return E_NOTIMPL; + This = enumerator_from_vdisp(jsthis); + if (This->enumvar) + { + IEnumVARIANT_Reset(This->enumvar); + hres = enumvar_get_next_item(This->enumvar, This->enumitm, &This->atend, r); + } + else + { + if (r) + *r = jsval_undefined(); + hres = S_OK; + } + + return hres; }
HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + EnumeratorInstance *This; + HRESULT hres = E_FAIL; + TRACE("Enumerator_moveNext\n");
- return E_NOTIMPL; + This = enumerator_from_vdisp(jsthis); + + if (This->atend) + { + if (r) + *r = jsval_undefined(); + return S_OK; + } + if (This->enumvar) + { + hres = enumvar_get_next_item(This->enumvar, This->enumitm, &This->atend, r); + } + else + { + if (r) + *r = jsval_undefined(); + hres = S_OK; + } + + return hres; }
static const builtin_prop_t Enumerator_props[] = { @@ -101,16 +219,18 @@ static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD fl jsval_t *r) { jsdisp_t *obj; + jsval_t *arg0; HRESULT hres;
TRACE("EnumeratorConstr_value\n");
switch(flags) { case DISPATCH_CONSTRUCT: { - if (argc != 1) - return throw_syntax_error(ctx, JS_E_MISSING_ARG, NULL); + if (argc > 1) + return throw_syntax_error(ctx, JS_E_INVALIDARG, NULL);
- hres = create_enumerator(ctx, &argv[0], &obj); + arg0 = (argc == 1) ? &argv[0] : 0; + hres = create_enumerator(ctx, arg0, &obj); if(FAILED(hres)) return hres;
@@ -118,7 +238,7 @@ static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD fl break; } default: - FIXME("unimplemented flags: %x\n", flags); + ERR("unimplemented flags: %x\n", flags); return E_NOTIMPL; }
@@ -140,7 +260,8 @@ static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, E hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info, ctx->enumerator_constr);
- if(FAILED(hres)) { + if(FAILED(hres)) + { heap_free(enumerator); return hres; } @@ -180,11 +301,95 @@ HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret) { EnumeratorInstance *enumerator; HRESULT hres; + IDispatch *obj; + DISPPARAMS dispparams = {NULL, NULL, 0, 0}; + VARIANT varresult; + + BOOL atend = TRUE; + IEnumVARIANT *enumvar = NULL; + VARIANT *enumitm = NULL; + + memset(&varresult, 0, sizeof(VARIANT)); + VariantInit(&varresult); + + /* new Enumerator() */ + if (argv == NULL) + { + atend = TRUE; + } + else if(is_object_instance(*argv)) + { + obj = get_object(*argv); + + /* Try to get a IEnumVARIANT by _NewEnum */ + hres = IDispatch_Invoke(obj, + DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL, + DISPATCH_METHOD, &dispparams, &varresult, + NULL, NULL); + if (FAILED(hres)) + { + ERR("Enumerator: no DISPID_NEWENUM.\n"); + hres = E_INVALIDARG; + goto cleanuperr; + } + + if (V_VT(&varresult) == VT_DISPATCH) + { + hres = IUnknown_QueryInterface(V_DISPATCH(&varresult), + &IID_IEnumVARIANT, (void**)&enumvar); + } + else if (V_VT(&varresult) == VT_UNKNOWN) + { + hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult), + &IID_IEnumVARIANT, (void**)&enumvar); + } + else + { + ERR("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult)); + hres = E_INVALIDARG; + goto cleanuperr; + } + if (FAILED(hres)) + { + hres = E_INVALIDARG; + goto cleanuperr; + } + VariantClear(&varresult); + + enumitm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)); + if (!enumitm) + { + hres = E_OUTOFMEMORY; + goto cleanuperr; + } + VariantInit(enumitm); + + atend = FALSE; + enumvar_get_next_item(enumvar, enumitm, &atend, NULL); + } + else + { + ERR("I don't know how to handle this type!\n"); + hres = E_NOTIMPL; + goto cleanuperr; + }
hres = alloc_enumerator(ctx, NULL, &enumerator); if(FAILED(hres)) - return hres; + goto cleanuperr; + enumerator->atend = atend; + enumerator->enumvar = enumvar; + enumerator->enumitm = enumitm;
*ret = &enumerator->dispex; + return S_OK; +cleanuperr: + VariantClear(&varresult); + if (enumitm) + { + VariantClear(enumitm); + HeapFree(GetProcessHeap(), 0, enumitm); + } + return hres; } -- 2.11.0
Signed-off-by: Andreas Maier staubim@quantentunnel.de --- dlls/jscript/tests/api.js | 11 ++- dlls/jscript/tests/run.c | 198 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 205 insertions(+), 4 deletions(-)
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index f3d07f89f4..934a9be79e 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -58,8 +58,8 @@ testNoEnumerables("Function"); testNoEnumerables("Function.prototype"); testNoEnumerables("testNoEnumerates"); testNoEnumerables("VBArray"); -testNoEnumerables("new Enumerator([])"); -testNoEnumerables("Enumerator([])"); +testNoEnumerables("new Enumerator()"); +testNoEnumerables("Enumerator()");
ok(Object.propertyIsEnumerable("prototype") === false, "Object.prototype is enumerable"); ok(Math.propertyIsEnumerable("E") === false, "Math.E is enumerable"); @@ -343,7 +343,7 @@ ok(tmp === "[object Object]", "toString.call(this) = " + tmp); ok(tmp === "[object Object]", "toString.call(arguments) = " + tmp); tmp = Object.prototype.toString.call(new VBArray(createArray())); ok(tmp === "[object Object]", "toString.call(new VBArray()) = " + tmp); -(tmp = new Enumerator([])).f = Object.prototype.toString; +(tmp = new Enumerator()).f = Object.prototype.toString; ok(tmp.f() === "[object Object]", "tmp.f() = " + tmp.f());
function TSTestConstr() {} @@ -3009,4 +3009,9 @@ ok(tmp.toArray() == "2,3,12,13,22,23,32,33,42,43", "tmp.toArray() = " + tmp.toAr ok(createArray().toArray() == "2,3,12,13,22,23,32,33,42,43", "createArray.toArray()=" + createArray().toArray());
+obj = new Enumerator(); +ok(obj.atEnd(), "atEnd() = " + obj.atEnd()); +obj.moveFirst(); +ok(obj.atEnd(), "atEnd() = " + obj.atEnd()); + reportSuccess(); diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index aadb31700d..2cd1d3c7ce 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -106,6 +106,10 @@ DEFINE_EXPECT(testobj_noprop_d); DEFINE_EXPECT(testobj_onlydispid_d); DEFINE_EXPECT(testobj_onlydispid_i); DEFINE_EXPECT(testobj_notexists_d); +DEFINE_EXPECT(testobj_newenum); +DEFINE_EXPECT(enumvariant_next_0); +DEFINE_EXPECT(enumvariant_next_1); +DEFINE_EXPECT(enumvariant_reset); DEFINE_EXPECT(GetItemInfo_testVal); DEFINE_EXPECT(ActiveScriptSite_OnScriptError); DEFINE_EXPECT(invoke_func); @@ -144,6 +148,7 @@ DEFINE_EXPECT(BindHandler); #define DISPID_GLOBAL_TESTPROPPUTREF 0x101b #define DISPID_GLOBAL_GETSCRIPTSTATE 0x101c #define DISPID_GLOBAL_BINDEVENTHANDLER 0x101d +#define DISPID_GLOBAL_TESTENUMOBJ 0x101e
#define DISPID_GLOBAL_TESTPROPDELETE 0x2000 #define DISPID_GLOBAL_TESTNOPROPDELETE 0x2001 @@ -219,6 +224,97 @@ static void _test_grfdex(unsigned line, DWORD grfdex, DWORD expect) ok_(__FILE__,line)(grfdex == expect, "grfdex = %x, expected %x\n", grfdex, expect); }
+static HRESULT WINAPI EnumVARIANT_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if (IsEqualGUID(riid, &IID_IEnumVARIANT)) + *ppv = iface; + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI EnumVARIANT_AddRef(IEnumVARIANT *iface) +{ + return 2; +} + +static ULONG WINAPI EnumVARIANT_Release(IEnumVARIANT *iface) +{ + return 1; +} + +static int EnumVARIANT_index = 0; +static HRESULT WINAPI EnumVARIANT_Next( + IEnumVARIANT *This, + ULONG celt, + VARIANT *rgVar, + ULONG *pCeltFetched) +{ + ok(rgVar != NULL, "rgVar is NULL\n"); + ok(celt == 1, "celt = %d\n", celt); + ok(pCeltFetched == NULL, "pCeltFetched is not NULL\n"); + + if (!rgVar) + return S_FALSE; + + if (EnumVARIANT_index == 0) + { + CHECK_EXPECT(enumvariant_next_0); + V_VT(rgVar) = VT_I4; + V_I4(rgVar) = 123; + + if (pCeltFetched) + *pCeltFetched = 1; + EnumVARIANT_index++; + return S_OK; + } + + CHECK_EXPECT(enumvariant_next_1); + + if (pCeltFetched) + *pCeltFetched = 0; + return S_FALSE; + +} + +static HRESULT WINAPI EnumVARIANT_Skip( + IEnumVARIANT *This, + ULONG celt) +{ + ok(0, "EnumVariant_Skip: unexpected call\n"); + return E_NOTIMPL; +} +static HRESULT WINAPI EnumVARIANT_Reset( + IEnumVARIANT *This) +{ + CHECK_EXPECT(enumvariant_reset); + EnumVARIANT_index = 0; + return S_OK; +} + +static HRESULT WINAPI EnumVARIANT_Clone( + IEnumVARIANT *This, + IEnumVARIANT **ppEnum) +{ + ok(0, "EnumVariant_Clone: unexpected call\n"); + return E_NOTIMPL; +} + +static IEnumVARIANTVtbl testEnumVARIANTVtbl = { + EnumVARIANT_QueryInterface, + EnumVARIANT_AddRef, + EnumVARIANT_Release, + EnumVARIANT_Next, + EnumVARIANT_Skip, + EnumVARIANT_Reset, + EnumVARIANT_Clone +}; + +static IEnumVARIANT testEnumVARIANT = { &testEnumVARIANTVtbl }; + static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -320,6 +416,28 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown return E_NOTIMPL; }
+static HRESULT WINAPI testObj_Invoke(IDispatchEx *iface, DISPID id, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, UINT *puArgErr) +{ + switch(id) { + case DISPID_NEWENUM: + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(pei == NULL, "pei != NULL\n"); + + CHECK_EXPECT(testobj_newenum); + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch*)&testEnumVARIANT; + return S_OK; + } + + ok(0, "unexpected call %x\n", id); + return DISP_E_MEMBERNOTFOUND; +} + static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) { if(!strcmp_wa(bstrName, "prop")) { @@ -453,7 +571,7 @@ static IDispatchExVtbl testObjVtbl = { DispatchEx_GetTypeInfoCount, DispatchEx_GetTypeInfo, DispatchEx_GetIDsOfNames, - DispatchEx_Invoke, + testObj_Invoke, testObj_GetDispID, testObj_InvokeEx, testObj_DeleteMemberByName, @@ -466,6 +584,9 @@ static IDispatchExVtbl testObjVtbl = {
static IDispatchEx testObj = { &testObjVtbl };
+static VARIANT testEnumObj; +static BOOL testEnumObjValid = FALSE; + static HRESULT WINAPI dispexFunc_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *res, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -861,6 +982,11 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD return S_OK; }
+ if(!strcmp_wa(bstrName, "testEnumObj")) { + *pid = DISPID_GLOBAL_TESTENUMOBJ; + return S_OK; + } + if(strict_dispid_check && strcmp_wa(bstrName, "t")) ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName)); return DISP_E_UNKNOWNNAME; @@ -1365,6 +1491,54 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
return S_OK; } + case DISPID_GLOBAL_TESTENUMOBJ: + { + HRESULT hres; + + if (wFlags == (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF)) + { + ok(wFlags == (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF), "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(!pvarRes, "pvarRes != NULL\n"); + if ((pdp->rgvarg != NULL) && + (pdp->cArgs == 1) && + (pdp->cNamedArgs == 1) && + (pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT)) + { + if (!testEnumObjValid) + { + memset(&testEnumObj, 0, sizeof(VARIANT)); + testEnumObjValid = TRUE; + VariantInit(&testEnumObj); + } + else + VariantClear(&testEnumObj); + hres = VariantCopy(&testEnumObj, pdp->rgvarg); + ok(SUCCEEDED(hres), "VariantCopy failed!\n"); + } + } + else + { + ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + + if ((pvarRes != NULL) && (testEnumObjValid)) + { + hres = VariantCopy(pvarRes, &testEnumObj); + ok(SUCCEEDED(hres), "VariantCopy failed!\n"); + } + } + return S_OK; + } }
ok(0, "unexpected call %x\n", id); @@ -2682,6 +2856,28 @@ static BOOL run_tests(void) CHECK_CALLED(global_success_d); CHECK_CALLED(global_success_i);
+ EnumVARIANT_index = 0; + SET_EXPECT(testobj_newenum); + SET_EXPECT(enumvariant_next_0); + parse_script_a("new Enumerator(testObj);"); + CHECK_CALLED(testobj_newenum); + CHECK_CALLED(enumvariant_next_0); + + EnumVARIANT_index = 0; + SET_EXPECT(testobj_newenum); + SET_EXPECT(enumvariant_next_0); + SET_EXPECT(enumvariant_next_1); + parse_script_a("var testEnumObj = new Enumerator(testObj);" + "while (!testEnumObj.atEnd())" + "{" + " ok(testEnumObj.item() == 123, " + " "testEnumObj.item() = "+testEnumObj.item());" + " testEnumObj.moveNext();" + "}"); + CHECK_CALLED(testobj_newenum); + CHECK_CALLED(enumvariant_next_0); + CHECK_CALLED(enumvariant_next_1); + run_from_res("lang.js"); run_from_res("api.js"); run_from_res("regexp.js"); -- 2.11.0
Hi Andreas,
On 5/6/19 10:21 PM, Andreas Maier wrote:
case DISPID_GLOBAL_TESTENUMOBJ:
{
HRESULT hres;
if (wFlags == (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
{
ok(wFlags == (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF), "wFlags = %x\n", wFlags);
ok(pdp != NULL, "pdp == NULL\n");
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n");
ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs);
ok(!pvarRes, "pvarRes != NULL\n");
if ((pdp->rgvarg != NULL) &&
(pdp->cArgs == 1) &&
(pdp->cNamedArgs == 1) &&
(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT))
{
if (!testEnumObjValid)
{
memset(&testEnumObj, 0, sizeof(VARIANT));
testEnumObjValid = TRUE;
VariantInit(&testEnumObj);
}
else
VariantClear(&testEnumObj);
hres = VariantCopy(&testEnumObj, pdp->rgvarg);
ok(SUCCEEDED(hres), "VariantCopy failed!\n");
}
}
else
{
ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
ok(pdp != NULL, "pdp == NULL\n");
ok(!pdp->rgvarg, "rgvarg != NULL\n");
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
ok(pvarRes != NULL, "pvarRes == NULL\n");
if ((pvarRes != NULL) && (testEnumObjValid))
{
hres = VariantCopy(pvarRes, &testEnumObj);
ok(SUCCEEDED(hres), "VariantCopy failed!\n");
}
}
return S_OK;
}
Why do you need this? Note that if testNumObj would be not found in the host object, jscript will handle it for you.
Thanks,
Jacek
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51915
Your paranoid android.
=== debian9 (32 bit report) ===
jscript: run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057 run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057
=== debian9 (32 bit Chinese:China report) ===
jscript: run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057 run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057
=== debian9 (32 bit WoW report) ===
jscript: run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057 run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057
=== debian9 (64 bit WoW report) ===
jscript: run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057 run.c:1997: Test failed: expected global_success_d run.c:1998: Test failed: expected global_success_i run.c:2000: Test failed: parse_script failed: 80070057
Hi Andreas,
It's mostly looking good, but some details still need a bit more work.
On 5/6/19 10:21 PM, Andreas Maier wrote:
Signed-off-by: Andreas Maier staubim@quantentunnel.de
dlls/jscript/enumerator.c | 227 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 216 insertions(+), 11 deletions(-)
diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index aa7737ac52..a7cad81c8a 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -26,6 +26,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript);
typedef struct { jsdisp_t dispex;
- BOOL atend;
- /* IEnumVARIANT returned by _NewEnum */
- IEnumVARIANT *enumvar;
- /* IEnumVARIANT current item */
- VARIANT* enumitm;
There is no need to allocate enumitm (BTW, maybe call it just 'item'?) separately. You could just store the structure inside EnumeratorInstance. I would also suggest storing it as jsval_t. If you just set it to jsval_undefined() when you're at the end, it could simplify things even more.
} EnumeratorInstance;
static const WCHAR atEndW[] = {'a','t','E','n','d',0}; @@ -33,43 +38,156 @@ 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 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 HRESULT enumvar_get_next_item(
- IEnumVARIANT* enumvar, VARIANT* enumitm,
- BOOL* atend, jsval_t *r)
I expect that passing EnumeratorInstance pointer instead of its fields separately would make things easier.
+{
- HRESULT hres;
- /* not at end ... get next item */
- if (!(*atend))
- {
/* Assume valid variant */
VariantClear(enumitm);
hres = IEnumVARIANT_Next(enumvar, 1, enumitm, NULL);
if (hres != S_OK)
{
VariantClear(enumitm);
*atend = TRUE;
}
- }
- if (*atend)
- {
if (r)
*r = jsval_undefined();
return S_OK;
- }
- if (r)
return variant_to_jsval(enumitm, r);
- return S_OK;
+}
static void Enumerator_destructor(jsdisp_t *dispex) {
EnumeratorInstance *This;
TRACE("Enumerator_destructor\n");
This = enumerator_from_jsdisp(dispex);
if (This->enumitm)
{
VariantClear(This->enumitm);
heap_free(This->enumitm);
}
heap_free(dispex);
}
HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) {
- TRACE("Enumerator_atEnd\n");
- EnumeratorInstance *This;
- This = enumerator_from_vdisp(jsthis);
- return E_NOTIMPL;
- if (r)
*r = jsval_bool(This->atend);
- TRACE("Enumerator_atEnd %d\n", This->atend);
I missed it in already committed patch, but please don't add function names to debug traces. Wine will add it for you.
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;
HRESULT hres = E_FAIL;
TRACE("Enumerator_item\n");
- return E_NOTIMPL;
- This = enumerator_from_vdisp(jsthis);
You need to make sure that This is actually an enumerator instance. JavaScript allows passing arbitrary values as this with something like Enumerator.prototype.item.call(new Object());
See how it's handled in bool.c for an example (and don't worry about exact error exceptions, FIXME(); return E_NOTIMPL; is fine for the first iteration). Same applies to other functions.
- if (This->enumvar)
- {
hres = variant_to_jsval(This->enumitm, r);
- }
- else
- {
if (r)
*r = jsval_undefined();
hres = S_OK;
- }
- return hres;
If you store the value as I suggested, it could be just:
return r ? jsval_copy(This->item, r) : S_OK;
}
HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) {
- EnumeratorInstance *This;
- HRESULT hres = E_FAIL;
TRACE("Enumerator_moveFirst\n");
- return E_NOTIMPL;
- This = enumerator_from_vdisp(jsthis);
- if (This->enumvar)
- {
IEnumVARIANT_Reset(This->enumvar);
We should probably check for Reset() error.
hres = enumvar_get_next_item(This->enumvar, This->enumitm, &This->atend, r);
Does it really return the item value here? It would need a test, but I'd expect it to return undefined value.
}
else
{
if (r)
*r = jsval_undefined();
hres = S_OK;
}
return hres; }
HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) {
EnumeratorInstance *This;
HRESULT hres = E_FAIL;
TRACE("Enumerator_moveNext\n");
- return E_NOTIMPL;
- This = enumerator_from_vdisp(jsthis);
- if (This->atend)
- {
if (r)
*r = jsval_undefined();
return S_OK;
- }
- if (This->enumvar)
- {
hres = enumvar_get_next_item(This->enumvar, This->enumitm, &This->atend, r);
Same here, should it return the value?
@@ -180,11 +301,95 @@ HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret) { EnumeratorInstance *enumerator; HRESULT hres;
- IDispatch *obj;
- DISPPARAMS dispparams = {NULL, NULL, 0, 0};
- VARIANT varresult;
- BOOL atend = TRUE;
- IEnumVARIANT *enumvar = NULL;
- VARIANT *enumitm = NULL;
- memset(&varresult, 0, sizeof(VARIANT));
- VariantInit(&varresult);
- /* new Enumerator() */
- if (argv == NULL)
- {
atend = TRUE;
- }
- else if(is_object_instance(*argv))
- {
obj = get_object(*argv);
/* Try to get a IEnumVARIANT by _NewEnum */
hres = IDispatch_Invoke(obj,
DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, &varresult,
NULL, NULL);
if (FAILED(hres))
{
ERR("Enumerator: no DISPID_NEWENUM.\n");
hres = E_INVALIDARG;
goto cleanuperr;
}
if (V_VT(&varresult) == VT_DISPATCH)
{
hres = IUnknown_QueryInterface(V_DISPATCH(&varresult),
&IID_IEnumVARIANT, (void**)&enumvar);
}
else if (V_VT(&varresult) == VT_UNKNOWN)
{
hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult),
&IID_IEnumVARIANT, (void**)&enumvar);
}
Note that IDispatch inherits from IUnknown, so you could just handle them as a single case and use V_UNKNOWN.
Thanks,
Jacek