Hello again Nikolay and others, I'm back online. The first attachment is try 2 of the second patch, i.e. the one discussed in this thread. I hope it meets all of your concerns. I adjusted my plan slightly at this point:
Den 12-06-2012 13:55, Ulrik Dickow skrev: > Den 12-06-2012 13:21, Nikolay Sivov skrev: >> On 6/12/2012 11:55, Ulrik Dickow wrote: >>> Patch 2 of 2 from http://bugs.winehq.org/show_bug.cgi?id=26226 . >>> [...] >>> + /* Emit appropriate fixme or warning in case of unsupported or invalid >>> namespace. >>> [...] >> The question is more like what libxml2 thinks about that. If it follows >> w3c here which is likely the question will be - won't it break somewhere >> internally in libxml2 code if we hack it that way? > [...] > But maybe you are right that it is safer to return E_INVALIDARG, as I > did in an earlier version, to guard against future increased > intelligence in libxml2. Both of the applications in bug 26226 use the > correct W3C namespace, so they don't care. I'll change it back. The new patch returns E_NOTIMPL instead. That seems more appropriate to me, knowing that native msxml3 returns S_OK (like the first version of my patch) and that we will have to change it back if it turns out to break a real-life application. Evil apps that try to break us intentionally don't count :). The new patch gives exactly the same output for the tst-msxml_make_soap.c program as the old one. Consistent with this test, it also still succesfully fixes bug 26226 for BridgeCentral: BridgeCentral's SOAP requests again succeed perfectly. The new patch changes the output of the tst-msxml_xmlns_simple.c program. The new E_NOTIMPL behaviour actually made the original program crash because I failed to do proper error checking (see second attachment if you like, patch relative to the C attached to bugzilla). The new output of the fixed tst-msxml_xmlns_simple.c is in the third attachment. The differences to the old wine patch are in test 03 (only the FIXME text changed) and in test 04 (FAILures instead of ok, and now quite detailed FIXME texts instead of more general, invisible warnings). Of course, only the first attachment will be sent to wine-patches, and only if no objections appear here to prevent it. - Ulrik
From 7ae0d0678184b1a937d54d3256834c8f116c8665 Mon Sep 17 00:00:00 2001 From: Ulrik Dickow <[email protected]> Date: Sun, 24 Jun 2012 22:50:05 +0200 Subject: msxml3: Support xmlns[:*] attribute nodes intelligently. This resolves bug #26226. --- dlls/msxml3/domdoc.c | 46 ++++++++- dlls/msxml3/element.c | 125 +++++++++++++++++++---- dlls/msxml3/tests/domdoc.c | 243 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 378 insertions(+), 36 deletions(-) diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 5097ff6..7d7cd55 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -1862,6 +1862,10 @@ static HRESULT WINAPI domdoc_createNode( BSTR namespaceURI, IXMLDOMNode** node ) { + static const WCHAR xmlnsW[] = {'x','m','l','n','s',0}; + static const WCHAR xmlnscW[] = {'x','m','l','n','s',':'}; + static const WCHAR w3xmlns[] = { 'h','t','t','p',':','/','/', 'w','w','w','.','w','3','.', + 'o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0 }; domdoc *This = impl_from_IXMLDOMDocument3( iface ); DOMNodeType node_type; xmlNodePtr xmlnode; @@ -1875,9 +1879,6 @@ static HRESULT WINAPI domdoc_createNode( hr = get_node_type(Type, &node_type); if(FAILED(hr)) return hr; - if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT) - FIXME("nodes with namespaces currently not supported.\n"); - TRACE("node_type %d\n", node_type); /* exit earlier for types that need name */ @@ -1893,6 +1894,45 @@ static HRESULT WINAPI domdoc_createNode( break; } + /* Return early and/or emit appropriate fixme in case of unsupported or invalid namespace. + * Redefining the namespace for the reserved "xmlns" attribute or prefix is forbidden by + * W3C (http://www.w3.org/TR/xml-names/#ns-decl). This is enforced by the libxml2-based + * http://gdome2.cs.unibo.it/gtk-doc/gdome2-gdomeelement.html#GDOME-EL-SETATTRIBUTENS , + * but currently not directly by libxml2 itself, it seems. However, feeding the invalid + * combination into libxml2 may lead to strange behaviour later on, so we choose to return + * E_NOTIMPL immediately instead of taking a chance. Native msxml3 accepts anything (S_OK). + * We don't yet know of any (broken) application that would be hit by this. + */ + if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT) + { + if(node_type == NODE_ATTRIBUTE) + { + BOOL is_xmlns = (!strcmpW(name, xmlnsW) || /* name is "xmlns" OR */ + !strncmpW(name, xmlnscW, /* name begins with "xmlns:" */ + sizeof(xmlnscW)/sizeof(WCHAR))); + BOOL is_w3URI = !strcmpW(namespaceURI, w3xmlns); /* URI is the special W3C URI */ + + if(is_xmlns) + { + if(!is_w3URI) + { /* We deny this until some broken app pops up that really needs it. */ + FIXME("refuses to bind prefix \"xmlns\" to URI %s instead of %s\n", + debugstr_w(namespaceURI), debugstr_w(w3xmlns)); + return E_NOTIMPL; + } + } else if(is_w3URI) + { /* Can't imagine a non-hostile app with this level of brain damage. */ + FIXME("won't allow URI %s for attribute %s -- reserved for prefix \"xmlns\".\n", + debugstr_w(w3xmlns), debugstr_w(name)); + return E_NOTIMPL; + } + else /* Neither xmlns nor the reserved W3C xmlns URI */ + FIXME("attribute nodes with namespaces not yet fully supported.\n"); + } + else + FIXME("type %d nodes with namespaces currently not supported.\n", node_type); + } + xml_name = xmlchar_from_wchar(name); /* prevent empty href to be allocated */ href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL; diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c index 26bfd0c..4fb5fa3 100644 --- a/dlls/msxml3/element.c +++ b/dlls/msxml3/element.c @@ -1068,6 +1068,104 @@ static HRESULT WINAPI domelem_getAttribute( return hr; } +/* This function is a subset of xmlSearchNs in libxml2 tree/tree.c (C) [email protected]. + * Like xmlSearchNs, but restricted to search on the given node, not in parents or doc. + * That is, we just search for the given prefix in the list of namespace definitions on the + * given node (node->nsDef). (Looking at node->ns too would be redundant). + */ +static xmlNsPtr xml_search_ns_local(xmlNodePtr node, const xmlChar *pfix) +{ + xmlNsPtr cur; + + if (node == NULL || node->type != XML_ELEMENT_NODE) + return NULL; + + cur = node->nsDef; + while (cur != NULL) { + if ((cur->prefix == NULL) && (pfix == NULL) && + (cur->href != NULL)) + return(cur); + if ((cur->prefix != NULL) && (pfix != NULL) && + (cur->href != NULL) && + (xmlStrEqual(cur->prefix, pfix))) + return(cur); + cur = cur->next; + } + return NULL; +} + +static inline BOOL is_skippable_xlmns_attribute( + const xmlNodePtr element, + const xmlChar *name, + const xmlChar *value, + HRESULT *hr_ptr) +{ + /* Return TRUE if the parameter 'name' is a namespace definition attribute + * ("xmlns" or of the form "xmlns:PFIX") that denotes a prefix that is already + * associated with a non-empty namespace URI on this element locally. + * If this non-empty URI equals the 'value' parameter, + * then silently set *hr_ptr to S_OK (no conflict, skip redundant attribute), + * else set it to a non-OK status and emit a warning/fixme depending on prefix or not: + * xmlns:PFIX : set it to E_INVALIDARG and emit a WARNing (skip conflicting attribute) + * xmlns : set it to E_NOTIMPL and emit a FIXME (native strangely allows this). + * When FALSE is returned (not a skippable xmlns attribute), hr_ptr is not accessed. + * + * See also http://bugs.winehq.org/show_bug.cgi?id=26226 . + */ + static const xmlChar* xmlnsA = (const xmlChar*)"xmlns"; + xmlChar *xml_prefix, *pfix = NULL; /* name="xmlns:a" => (xml_prefix="xmlns", pfix="a") */ + xmlNsPtr ns; + + if ((pfix = xmlSplitQName2(name, &xml_prefix))) + { + if (!xmlStrEqual(xml_prefix, xmlnsA)) + { + xmlFree(xml_prefix); + xmlFree(pfix); + return FALSE; /* Attribute name had a prefix, but it was not "xmlns". */ + } + xmlFree(xml_prefix); /* We only need pfix from now on (non-null here, free later). */ + } + else + if (!xmlStrEqual(name, xmlnsA)) + return FALSE; /* Attribute name had no prefix and didn't equal "xmlns". */ + + /* pfix is now the namespace prefix to search for. NULL means the default namespace. */ + TRACE("pfix: %s\n", wine_dbgstr_a((const char *) pfix)); + + ns = xml_search_ns_local(element, pfix); + if (pfix) xmlFree(pfix); /* No longer needed, use ns->prefix instead. */ + + if (ns == NULL || ns->href == NULL) + return FALSE; /* Attribute name matched xmlns[:PFIX] but wasn't known, so don't skip. */ + + /* pfix already exists as a non-empty namespace, so attribute should be skipped (TRUE). + * Now decide whether it's a conflict/strangeness or just a redundancy. + */ + if (xmlStrEqual(ns->href, value)) + { + TRACE("skipping apparently redundant attribute\n"); + *hr_ptr = S_OK; /* Important that the application believes it succeeded. */ + } + else if (ns->prefix) + { + WARN("attribute %s attempts to change namespace URI for prefix %s from %s to %s\n", + debugstr_a((const char *) name), + debugstr_a((const char *) ns->prefix), + debugstr_a((const char *) ns->href), + debugstr_a((const char *) value)); + *hr_ptr = E_INVALIDARG; + } + else + { /* See related comment about "strange behaviour" and todo_wine'd test in tests/domdoc.c */ + FIXME("refuses to add xmlns=%s when element already has default namespace %s\n", + debugstr_a((const char *) value), + debugstr_a((const char *) ns->href)); + *hr_ptr = E_NOTIMPL; + } + return TRUE; +} + static HRESULT WINAPI domelem_setAttribute( IXMLDOMElement *iface, BSTR name, VARIANT value) @@ -1209,11 +1307,10 @@ static HRESULT WINAPI domelem_setAttributeNode( IXMLDOMAttribute** old) { domelem *This = impl_from_IXMLDOMElement( iface ); - static const WCHAR xmlnsW[] = {'x','m','l','n','s',0}; + xmlNodePtr element = get_element(This); xmlChar *name, *value; BSTR nameW, prefix; xmlnode *attr_node; - xmlAttrPtr attr; VARIANT valueW; HRESULT hr; @@ -1233,13 +1330,6 @@ static HRESULT WINAPI domelem_setAttributeNode( hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW); if (hr != S_OK) return hr; - /* adding xmlns attribute doesn't change a tree or existing namespace definition */ - if (!strcmpW(nameW, xmlnsW)) - { - SysFreeString(nameW); - return DISP_E_UNKNOWNNAME; - } - hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW); if (hr != S_OK) { @@ -1261,25 +1351,22 @@ static HRESULT WINAPI domelem_setAttributeNode( name = xmlchar_from_wchar(nameW); value = xmlchar_from_wchar(V_BSTR(&valueW)); + hr = E_FAIL; if (!name || !value) + hr = E_OUTOFMEMORY; + else if (!is_skippable_xlmns_attribute(element, name, value, &hr) && + xmlSetNsProp(element, NULL, name, value)) { - SysFreeString(nameW); - VariantClear(&valueW); - heap_free(name); - heap_free(value); - return E_OUTOFMEMORY; - } - - attr = xmlSetNsProp(get_element(This), NULL, name, value); - if (attr) attr_node->parent = (IXMLDOMNode*)iface; + hr = S_OK; + } SysFreeString(nameW); VariantClear(&valueW); heap_free(name); heap_free(value); - return attr ? S_OK : E_FAIL; + return hr; } static HRESULT WINAPI domelem_removeAttributeNode( diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index 0c9d65a..d2a13e0 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -7160,6 +7160,33 @@ static void test_testTransforms(void) free_bstrs(); } +/* Convenient helper function for creating an attribute node in a given namespace. + * Note: EXPECT_HR() should not be here, but in caller, to give optimal line number info. + */ +static HRESULT create_attribute_ns( + IXMLDOMDocument *doc, + const char *attr_name, + const char *nsURI, + IXMLDOMAttribute **attr_ptr) +{ + HRESULT hr; + VARIANT var; + IXMLDOMNode *node; + + *attr_ptr = NULL; + + V_VT(&var) = VT_I1; + V_I1(&var) = NODE_ATTRIBUTE; + + hr = IXMLDOMDocument_createNode(doc, var, _bstr_(attr_name), _bstr_(nsURI), &node); + if (hr == S_OK) + { + IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**) attr_ptr); + IXMLDOMNode_Release(node); + } + return hr; +} + struct namespaces_change_t { const CLSID *clsid; const char *name; @@ -7175,15 +7202,18 @@ static const struct namespaces_change_t namespaces_change_test_data[] = { { 0 } }; +/* create namespace on element and try to alter namespace after that */ static void test_namespaces_change(void) { + static const char *xmlnsURI = "http://www.w3.org/2000/xmlns/"; const struct namespaces_change_t *class_ptr = namespaces_change_test_data; while (class_ptr->clsid) { IXMLDOMDocument *doc = NULL; - IXMLDOMElement *elem = NULL; + IXMLDOMElement *elem1 = NULL, *elem2 = NULL; IXMLDOMNode *node = NULL; + IXMLDOMAttribute *attr; VARIANT var; HRESULT hr; @@ -7201,36 +7231,221 @@ static void test_namespaces_change(void) V_VT(&var) = VT_I2; V_I2(&var) = NODE_ELEMENT; - hr = IXMLDOMDocument_createNode(doc, var, _bstr_("ns:elem"), _bstr_("ns/uri"), &node); + hr = IXMLDOMDocument_createNode(doc, var, _bstr_("ns:elem1"), _bstr_("ns/uri"), &node); EXPECT_HR(hr, S_OK); hr = IXMLDOMDocument_appendChild(doc, node, NULL); EXPECT_HR(hr, S_OK); - hr = IXMLDOMDocument_get_documentElement(doc, &elem); + hr = IXMLDOMDocument_get_documentElement(doc, &elem1); EXPECT_HR(hr, S_OK); - /* try same prefix, different uri */ - V_VT(&var) = VT_BSTR; - V_BSTR(&var) = _bstr_("ns/uri2"); + IXMLDOMNode_Release(node); - hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var); + /* try same prefix, different uri, via setAttribute */ + hr = IXMLDOMElement_setAttribute(elem1, _bstr_("xmlns:ns"), _variantbstr_("ns/uri2")); EXPECT_HR(hr, E_INVALIDARG); - /* try same prefix and uri */ - V_VT(&var) = VT_BSTR; - V_BSTR(&var) = _bstr_("ns/uri"); + /* try same prefix and uri, via setAttribute */ + hr = IXMLDOMElement_setAttribute(elem1, _bstr_("xmlns:ns"), _variantbstr_("ns/uri")); + EXPECT_HR(hr, S_OK); - hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var); + /* check xml so far */ + hr = IXMLDOMElement_get_xml(elem1, &str); EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_("<ns:elem1 xmlns:ns=\"ns/uri\"/>")), "got element %s for %s\n", + wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); - hr = IXMLDOMElement_get_xml(elem, &str); + /* try same prefix, different uri, via setAttributeNode */ + hr = create_attribute_ns(doc, "xmlns:ns", xmlnsURI, &attr); EXPECT_HR(hr, S_OK); - ok(!lstrcmpW(str, _bstr_("<ns:elem xmlns:ns=\"ns/uri\"/>")), "got element %s for %s\n", + + hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("ns/uri2")); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_setAttributeNode(elem1, attr, NULL); + EXPECT_HR(hr, E_INVALIDARG); + + IXMLDOMAttribute_Release(attr); + + /* try same prefix and uri, via setAttributeNode */ + hr = create_attribute_ns(doc, "xmlns:ns", xmlnsURI, &attr); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("ns/uri")); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_setAttributeNode(elem1, attr, NULL); + EXPECT_HR(hr, S_OK); + + IXMLDOMAttribute_Release(attr); + + /* check xml again (should be unchanged) */ + hr = IXMLDOMElement_get_xml(elem1, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_("<ns:elem1 xmlns:ns=\"ns/uri\"/>")), "got element %s for %s\n", wine_dbgstr_w(str), class_ptr->name); SysFreeString(str); - IXMLDOMElement_Release(elem); + /* Create elem2 as child element without explicit namespace, and then test that rebinding + * "ns" via setAttributeNode is ok (parents shouldn't be searched for a conflict). + */ + V_VT(&var) = VT_I2; + V_I2(&var) = NODE_ELEMENT; + + hr = IXMLDOMDocument_createNode(doc, var, _bstr_("elem2"), NULL, &node); + EXPECT_HR(hr, S_OK); + + IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**) &elem2); + IXMLDOMNode_Release(node); + + hr = IXMLDOMElement_appendChild(elem1, (IXMLDOMNode*)elem2, NULL); + EXPECT_HR(hr, S_OK); + + hr = create_attribute_ns(doc, "xmlns:ns", xmlnsURI, &attr); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("ns2")); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_setAttributeNode(elem2, attr, NULL); + EXPECT_HR(hr, S_OK); + + IXMLDOMAttribute_Release(attr); + + /* check final xml */ + hr = IXMLDOMElement_get_xml(elem1, &str); + EXPECT_HR(hr, S_OK); + + /* Unfortunately wine currently inserts whitespace, while native doesn't. + * Shouldn't matter in the vast majority of apps, so relevant to test for the alternative too. + */ + ok((!lstrcmpW(str, _bstr_("<ns:elem1 xmlns:ns=\"ns/uri\"><elem2 xmlns:ns=\"ns2\"/></ns:elem1>")) || + !lstrcmpW(str, _bstr_("<ns:elem1 xmlns:ns=\"ns/uri\">\r\n\t<elem2 xmlns:ns=\"ns2\"/>\r\n</ns:elem1>"))), + "got element %s for %s\n", wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + IXMLDOMElement_Release(elem1); + IXMLDOMElement_Release(elem2); + + /* Now test NULL prefix (default namespace), via setAttributeNode, on two new elements. */ + elem1 = NULL; + elem2 = NULL; + + /* 1. test when element is created with empty namespace (parent element here). */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("elem1"), &elem1); + EXPECT_HR(hr, S_OK); + + hr = create_attribute_ns(doc, "xmlns", xmlnsURI, &attr); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("ns/uri1")); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_setAttributeNode(elem1, attr, NULL); + EXPECT_HR(hr, S_OK); + + IXMLDOMAttribute_Release(attr); + + /* check xml so far */ + hr = IXMLDOMElement_get_xml(elem1, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_("<elem1 xmlns=\"ns/uri1\"/>")), "got element %s for %s\n", + wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + /* On native, get_namespaceURI still returns empty now. So do we. */ + hr = IXMLDOMElement_get_namespaceURI(elem1, &str); + EXPECT_HR(hr, S_FALSE); + ok((str == NULL), "expected NULL, got %s for %s\n", wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + /* 2. test when element is created with non-empty namespace (child element here). */ + V_VT(&var) = VT_I2; + V_I2(&var) = NODE_ELEMENT; + + hr = IXMLDOMDocument_createNode(doc, var, _bstr_("elem2"), _bstr_("ns/uri1"), &node); + EXPECT_HR(hr, S_OK); + + IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**) &elem2); + IXMLDOMNode_Release(node); + + hr = IXMLDOMElement_appendChild(elem1, (IXMLDOMNode*)elem2, NULL); + EXPECT_HR(hr, S_OK); + + /* get_xml depends on context, for top node it omits child namespace attribute, + * but at child level it's still returned. Also true on native (before + * setAttributeNode on child) that the child namespace is suppressed by the parent + * setAttributeNode, even with NULL get_namespaceURI on parent. + */ + hr = IXMLDOMElement_get_xml(elem1, &str); + EXPECT_HR(hr, S_OK); + todo_wine ok(!lstrcmpW(str, _bstr_("<elem1 xmlns=\"ns/uri1\"><elem2/></elem1>")), + "got element %s for %s\n", wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + hr = IXMLDOMElement_get_xml(elem2, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_("<elem2 xmlns=\"ns/uri1\"/>")), "got element %s for %s\n", + wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + /* 2a. try different uri, via setAttributeNode. Native allows this, resulting in + * different URI's from get_xml versus get_namespaceURI (like above, where get...URI empty). + * Don't know of any apps that depend on this strange behaviour, so maybe remain todo forever? + */ + hr = create_attribute_ns(doc, "xmlns", xmlnsURI, &attr); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("ns/uri2")); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_setAttributeNode(elem2, attr, NULL); + todo_wine EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_get_xml(elem2, &str); + EXPECT_HR(hr, S_OK); + todo_wine ok(!lstrcmpW(str, _bstr_("<elem2 xmlns=\"ns/uri2\"/>")), "got element %s for %s\n", + wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + /* On native, get_namespaceURI still returns ns/uri1 now. So do we. */ + hr = IXMLDOMElement_get_namespaceURI(elem2, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_("ns/uri1")), "expected ns/uri1, got %s for %s\n", + wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + /* 2b. try same uri, via setAttributeNode (should be accepted without extra xml) */ + hr = create_attribute_ns(doc, "xmlns", xmlnsURI, &attr); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("ns/uri1")); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMElement_setAttributeNode(elem2, attr, NULL); + EXPECT_HR(hr, S_OK); + + /* After setAttributeNode, the child xmlns becomes visible from the parent on native too + * (or rather: it still shows the attribute xmlns instead of the element namespace, + * but here they happen to be identical). + */ + hr = IXMLDOMElement_get_xml(elem1, &str); + EXPECT_HR(hr, S_OK); + todo_wine ok(!lstrcmpW(str, _bstr_("<elem1 xmlns=\"ns/uri1\"><elem2 xmlns=\"ns/uri1\"/></elem1>")), + "got element %s for %s\n", wine_dbgstr_w(str), class_ptr->name); + /* Unfortunately wine currently inserts whitespace, while native doesn't. + * Shouldn't matter in the vast majority of apps, so relevant to test for the alternative too. + */ + ok((!lstrcmpW(str, _bstr_("<elem1 xmlns=\"ns/uri1\"><elem2 xmlns=\"ns/uri1\"/></elem1>")) || + !lstrcmpW(str, _bstr_("<elem1 xmlns=\"ns/uri1\">\r\n\t<elem2 xmlns=\"ns/uri1\"/>\r\n</elem1>"))), + "got element %s for %s\n", wine_dbgstr_w(str), class_ptr->name); + SysFreeString(str); + + IXMLDOMElement_Release(elem1); + IXMLDOMElement_Release(elem2); + IXMLDOMDocument_Release(doc); free_bstrs(); -- 1.7.7.6
From 855eaf4edf9d26ef4cf4f04ad4aa81eb69e365ad Mon Sep 17 00:00:00 2001 From: Ulrik Dickow <[email protected]> Date: Sun, 24 Jun 2012 22:02:38 +0200 Subject: xmlns_simple: Avoid crashing on undefined or null attribute node. --- tst-msxml_xmlns_simple.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tst-msxml_xmlns_simple.c b/tst-msxml_xmlns_simple.c index 44c6b91..b3d300a 100644 --- a/tst-msxml_xmlns_simple.c +++ b/tst-msxml_xmlns_simple.c @@ -123,6 +123,8 @@ static HRESULT create_attribute_ns( VARIANT var; IXMLDOMNode *node; + *attr_ptr = NULL; + V_VT(&var) = VT_I4; // VT_I1 often used, but I4 seen in trace, so use that now V_I4(&var) = NODE_ATTRIBUTE; @@ -251,8 +253,8 @@ static void test_xmlns_uri(IXMLDOMDocument *doc, const char *name, const char *n { IXMLDOMAttribute *attr_node; - create_attribute_ns(doc, name, nsURI, &attr_node); - IXMLDOMAttribute_Release(attr_node); + if (create_attribute_ns(doc, name, nsURI, &attr_node) == S_OK) + IXMLDOMAttribute_Release(attr_node); } -- 1.7.7.6
TST_MSXML_1_1-1-g855eaf4 søn jun 24 22:03:26 CEST 2012 CoInitialize successful! ok <-- CoCreateInstance (...DOMDocument...) ================================ Test 01 ====================================== ok <-- createNode (type = NODE_ELEMENT, name = "elem1", nsURI = "urn:ns1") ok <-- createNode (type = NODE_ELEMENT, name = "elem2", nsURI = "urn:ns1") ok <-- appendChild (elem1, elem2, NULL) dbgstr(elem1) = L"<elem1 xmlns=\"urn:ns1\">\r\n\t<elem2 xmlns=\"urn:ns1\"/>\r\n</elem1>" dbgstr(elem2) = L"<elem2 xmlns=\"urn:ns1\"/>" ================================ Test 02 ====================================== ok <-- createNode (type = NODE_ELEMENT, name = "pre:foo", nsURI = "urn:ns1") ok <-- createNode (type = NODE_ELEMENT, name = "pre:bar", nsURI = "urn:ns2") ok <-- appendChild (pre:foo, pre:bar, NULL) dbgstr(pre:foo) = L"<pre:foo xmlns:pre=\"urn:ns1\">\r\n\t<pre:bar xmlns:pre=\"urn:ns2\"/>\r\n</pre:foo>" ok <-- createElement (name = "pre:baz") ok <-- appendChild (pre:foo, pre:baz, NULL) FAIL <-- setAttribute (attr = "xmlns:pre", value = "urn:ns3" dbgstr(pre:foo) = L"<pre:foo xmlns:pre=\"urn:ns1\">\r\n\t<pre:bar xmlns:pre=\"urn:ns2\"/>\r\n\t<pre:baz/>\r\n</pre:foo>" ================================ Test 03 ====================================== ok <-- createNode (type = NODE_ELEMENT, name = "parent", nsURI = "") False <-- get_namespaceURI (parent, returned (null)) ok <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns", nsURI = "http://www.w3.org/2000/xmlns/") ok <-- put_nodeValue (value = "urn:ns4") fixme:msxml:domelem_setAttributeNode (0x131870)->(0x1302b4 0x32fd8c): semi-stub ok <-- setAttributeNode False <-- get_namespaceURI (parent, returned (null)) ok <-- createNode (type = NODE_ELEMENT, name = "child", nsURI = "urn:ns4") ok <-- get_namespaceURI (child, returned L"urn:ns4") ok <-- appendChild (parent, child, NULL) dbgstr(parent) = L"<parent xmlns=\"urn:ns4\">\r\n\t<child xmlns=\"urn:ns4\"/>\r\n</parent>" dbgstr(child) = L"<child xmlns=\"urn:ns4\"/>" ------------------------------------------------------------------- ok <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns", nsURI = "http://www.w3.org/2000/xmlns/") ok <-- put_nodeValue (value = "urn:ns5") fixme:msxml:domelem_setAttributeNode (0x12fd70)->(0x12fef4 0x32fd8c): semi-stub fixme:msxml:is_skippable_xlmns_attribute refuses to add xmlns="urn:ns5" when element already has default namespace "urn:ns4" FAIL <-- setAttributeNode dbgstr(parent) = L"<parent xmlns=\"urn:ns4\">\r\n\t<child xmlns=\"urn:ns4\"/>\r\n</parent>" dbgstr(child) = L"<child xmlns=\"urn:ns4\"/>" ok <-- get_namespaceURI (child, returned L"urn:ns4") ok <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns", nsURI = "http://www.w3.org/2000/xmlns/") ok <-- put_nodeValue (value = "urn:ns4") fixme:msxml:domelem_setAttributeNode (0x12fd70)->(0x13208c 0x32fd8c): semi-stub ok <-- setAttributeNode dbgstr(parent) = L"<parent xmlns=\"urn:ns4\">\r\n\t<child xmlns=\"urn:ns4\"/>\r\n</parent>" ================================ Test 04 ====================================== ok <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns", nsURI = "http://www.w3.org/2000/xmlns/") ok <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns:foo", nsURI = "http://www.w3.org/2000/xmlns/") fixme:msxml:domdoc_createNode refuses to bind prefix "xmlns" to URI L"http://www.w3.org/2000/xmlns" instead of L"http://www.w3.org/2000/xmlns/" FAIL <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns", nsURI = "http://www.w3.org/2000/xmlns") fixme:msxml:domdoc_createNode refuses to bind prefix "xmlns" to URI L"http://www.w3.org/2000/xmlns" instead of L"http://www.w3.org/2000/xmlns/" FAIL <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns:foo", nsURI = "http://www.w3.org/2000/xmlns") fixme:msxml:domdoc_createNode refuses to bind prefix "xmlns" to URI L"http://www.winehq.org/" instead of L"http://www.w3.org/2000/xmlns/" FAIL <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns", nsURI = "http://www.winehq.org/") fixme:msxml:domdoc_createNode refuses to bind prefix "xmlns" to URI L"http://www.winehq.org/" instead of L"http://www.w3.org/2000/xmlns/" FAIL <-- createNode (type = NODE_ATTRIBUTE, attr = "xmlns:foo", nsURI = "http://www.winehq.org/") fixme:msxml:domdoc_createNode won't allow URI L"http://www.w3.org/2000/xmlns/" for attribute L"myprefix" -- reserved for prefix "xmlns". FAIL <-- createNode (type = NODE_ATTRIBUTE, attr = "myprefix", nsURI = "http://www.w3.org/2000/xmlns/") fixme:msxml:domdoc_createNode won't allow URI L"http://www.w3.org/2000/xmlns/" for attribute L"gnus:gnats" -- reserved for prefix "xmlns". FAIL <-- createNode (type = NODE_ATTRIBUTE, attr = "gnus:gnats", nsURI = "http://www.w3.org/2000/xmlns/") fixme:msxml:domdoc_createNode attribute nodes with namespaces not yet fully supported. ok <-- createNode (type = NODE_ATTRIBUTE, attr = "myprefix", nsURI = "http://www.w3.org/2000/xmlns") fixme:msxml:domdoc_createNode attribute nodes with namespaces not yet fully supported. ok <-- createNode (type = NODE_ATTRIBUTE, attr = "gnus:gnats", nsURI = "http://www.w3.org/2000/xmlns") søn jun 24 22:03:26 CEST 2012
signature.asc
Description: OpenPGP digital signature
