From: Phiality <bakreski03@gmail.com> The original ES5+ patches unconditionally converted METHOD|PROPERTYGET to PROPERTYGET, which broke applications that call methods with arguments (e.g., Adobe installer calling error handlers). Fix by checking cArgs: when arguments are passed, it's a method call and should use DISPATCH_METHOD. Only when no arguments are passed should we use the ES5+ behavior of preferring DISPATCH_PROPERTYGET for property access. Also adds XMLSerializer test in dom.js and CDATA wrapping test in domdoc.c. --- dlls/jscript/dispex.c | 16 ++++++--- dlls/mshtml/dispex.c | 1 + dlls/mshtml/tests/dom.js | 35 ++++++++++++++++++ dlls/msxml3/tests/domdoc.c | 73 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 4 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index f39a8cd4b12..1d24808033e 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2136,10 +2136,18 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI if(pspCaller) IServiceProvider_AddRef(pspCaller); + if(wFlags == (DISPATCH_METHOD | DISPATCH_PROPERTYGET)) { + /* When called with arguments, it's a method call - always use DISPATCH_METHOD. + * When called without arguments, use version to decide: pre-ES5 calls methods, + * ES5+ gets property values. This preserves compatibility with callers that + * invoke methods with arguments while fixing property access behavior in ES5+. */ + if(pdp->cArgs > 0) + wFlags = DISPATCH_METHOD; + else + wFlags = (This->ctx->version < SCRIPTLANGUAGEVERSION_ES5) ? DISPATCH_METHOD : DISPATCH_PROPERTYGET; + } + switch(wFlags) { - case DISPATCH_METHOD|DISPATCH_PROPERTYGET: - wFlags = DISPATCH_METHOD; - /* fall through */ case DISPATCH_METHOD: case DISPATCH_CONSTRUCT: { jsval_t *argv, buf[6], r; @@ -2712,7 +2720,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns jsdisp_release(jsdisp); flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - if(ret && argc) + if(ret && argc && (!jsdisp || ctx->version < SCRIPTLANGUAGEVERSION_ES5)) flags |= DISPATCH_PROPERTYGET; dp.cArgs = argc; diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 0af89aca630..a6b8afb0543 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -868,6 +868,7 @@ static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS return This->info->vtbl->value(This, lcid, flags, params, res, ei, caller); switch(flags) { + case DISPATCH_PROPERTYGET | DISPATCH_METHOD: case DISPATCH_PROPERTYGET: V_VT(res) = VT_BSTR; hres = dispex_to_string(This, &V_BSTR(res)); diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index 92c1deb64d3..14ca1e8e3c8 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -1170,3 +1170,38 @@ sync_test("document.open", function() { doc.close(); ok(doc.onclick === f, "doc.onclick != f"); }); + +sync_test("XMLSerializer", function() { + var serializer = new XMLSerializer(); + ok(serializer !== null, "XMLSerializer constructor returned null"); + ok(typeof serializer === "object", "XMLSerializer is not an object"); + + /* Test serializeToString with a simple element */ + var div = document.createElement("div"); + div.id = "testdiv"; + div.innerHTML = "test content"; + + var result = serializer.serializeToString(div); + ok(typeof result === "string", "serializeToString did not return a string"); + ok(result.length > 0, "serializeToString returned empty string"); + ok(result.indexOf("testdiv") !== -1, "serialized string does not contain id: " + result); + ok(result.indexOf("test content") !== -1, "serialized string does not contain content: " + result); + + /* Test with nested elements */ + var container = document.createElement("div"); + var child = document.createElement("span"); + child.textContent = "nested"; + container.appendChild(child); + + result = serializer.serializeToString(container); + ok(result.indexOf("span") !== -1, "serialized string does not contain span tag: " + result); + ok(result.indexOf("nested") !== -1, "serialized string does not contain nested text: " + result); + + /* Test with attributes */ + var elem = document.createElement("input"); + elem.type = "text"; + elem.value = "test value"; + + result = serializer.serializeToString(elem); + ok(result.indexOf("input") !== -1, "serialized string does not contain input tag: " + result); +}); diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index a08506fad9b..5163b96e60e 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -14357,6 +14357,78 @@ static void test_indent(void) SysFreeString(str); } +static void test_embedded_xml_declaration(void) +{ + IXMLDOMDocument *doc; + IXMLDOMElement *elem; + VARIANT_BOOL b; + HRESULT hr; + + /* Test XML with embedded <?xml?> declaration inside an element. + * Windows MSXML tolerates this but libxml2 rejects it. + * The implementation wraps such content in CDATA to make it parse. */ + static const char embedded_xml_str[] = + "<?xml version=\"1.0\"?>" + "<root>" + " <xmldata><?xml version=\"1.0\"?><nested>content</nested></xmldata>" + "</root>"; + + /* Test with xml:space preserved content containing XML declaration */ + static const char embedded_xml_space_str[] = + "<?xml version=\"1.0\"?>" + "<root xml:space=\"preserve\">" + " <?xml version=\"1.0\"?><data>test</data>" + "</root>"; + + /* Test normal XML without embedded declarations (should still work) */ + static const char normal_xml_str[] = + "<?xml version=\"1.0\"?>" + "<root><child>text</child></root>"; + + doc = NULL; + hr = CoCreateInstance(&CLSID_DOMDocument2, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDOMDocument, (void**)&doc); + if (hr != S_OK) + { + win_skip("DOMDocument2 not available, skipping embedded XML tests\n"); + return; + } + + /* Test 1: Normal XML should parse fine */ + b = VARIANT_FALSE; + hr = IXMLDOMDocument_loadXML(doc, _bstr_(normal_xml_str), &b); + ok(hr == S_OK, "loadXML failed: %#lx\n", hr); + ok(b == VARIANT_TRUE, "failed to load normal XML\n"); + + hr = IXMLDOMDocument_get_documentElement(doc, &elem); + ok(hr == S_OK, "get_documentElement failed: %#lx\n", hr); + if (elem) + IXMLDOMElement_Release(elem); + + /* Test 2: XML with embedded declaration in element content */ + b = VARIANT_FALSE; + hr = IXMLDOMDocument_loadXML(doc, _bstr_(embedded_xml_str), &b); + ok(hr == S_OK, "loadXML with embedded XML declaration failed: %#lx\n", hr); + ok(b == VARIANT_TRUE, "failed to load XML with embedded declaration\n"); + + if (b == VARIANT_TRUE) + { + hr = IXMLDOMDocument_get_documentElement(doc, &elem); + ok(hr == S_OK, "get_documentElement failed: %#lx\n", hr); + if (elem) + IXMLDOMElement_Release(elem); + } + + /* Test 3: XML with embedded declaration and xml:space */ + b = VARIANT_FALSE; + hr = IXMLDOMDocument_loadXML(doc, _bstr_(embedded_xml_space_str), &b); + ok(hr == S_OK, "loadXML with embedded XML and xml:space failed: %#lx\n", hr); + ok(b == VARIANT_TRUE, "failed to load XML with embedded declaration and xml:space\n"); + + IXMLDOMDocument_Release(doc); + free_bstrs(); +} + static DWORD WINAPI new_thread(void *arg) { HRESULT hr = CoInitialize(NULL); @@ -14460,6 +14532,7 @@ START_TEST(domdoc) test_xsltemplate(); test_xsltext(); test_max_element_depth_values(); + test_embedded_xml_declaration(); if (is_clsid_supported(&CLSID_MXNamespaceManager40, &IID_IMXNamespaceManager)) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10025