Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/msxml3/tests/domdoc.c | 129 +++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+)
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index 35fa42a6d1..ffb9e1462d 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -12830,6 +12830,134 @@ todo_wine { IXMLDOMDocument2_Release(doc); }
+typedef struct _namespace_as_attribute_t { + const GUID *guid; + const char *clsid; + const char *xmlns_uri; + BOOL todo; +} namespace_as_attribute_t; + +static const namespace_as_attribute_t namespace_as_attribute_test_data[] = { + { &CLSID_DOMDocument, "CLSID_DOMDocument", "", FALSE }, + { &CLSID_DOMDocument2, "CLSID_DOMDocument2", "", FALSE }, + { &CLSID_DOMDocument26, "CLSID_DOMDocument26", "", FALSE }, + { &CLSID_DOMDocument30, "CLSID_DOMDocument30", "", FALSE }, + { &CLSID_DOMDocument40, "CLSID_DOMDocument40", "", FALSE }, + { &CLSID_DOMDocument60, "CLSID_DOMDocument60", "http://www.w3.org/2000/xmlns/", TRUE }, + { 0 } +}; + +void test_namespaces_as_attributes(void) +{ + const namespace_as_attribute_t *entry = namespace_as_attribute_test_data; + static const char ns_as_attr_doc[] = { + "<?xml version=\"1.0\"?>" + "<a ns:b="b attr" d="d attr" xmlns:ns="nshref" />" + }; + static const char *names[] = { "ns:b", "d", "xmlns:ns" }; + static const char *prefixes[] = { "ns", NULL, "xmlns" }; + static const char *basenames[] = { "b", "d", "ns" }; + static const char *uris[] = { "nshref", NULL, "" }; + static const char *texts[] = { "b attr", "d attr", "nshref" }; + IXMLDOMNamedNodeMap *map; + IXMLDOMDocument *doc; + IXMLDOMNode *node; + IXMLDOMNode *item; + VARIANT_BOOL b; + HRESULT hr; + BSTR str; + LONG len; + LONG i; + + while (entry->guid) + { + if (!is_clsid_supported(entry->guid, &IID_IXMLDOMDocument2)) + { + entry++; + continue; + } + + hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDOMDocument2, (void**)&doc); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMDocument_loadXML(doc, _bstr_(ns_as_attr_doc), &b); + EXPECT_HR(hr, S_OK); + + node = NULL; + hr = IXMLDOMDocument_selectSingleNode(doc, _bstr_("a"), &node); + EXPECT_HR(hr, S_OK); + + hr = IXMLDOMNode_get_attributes(node, &map); + EXPECT_HR(hr, S_OK); + + len = -1; + hr = IXMLDOMNamedNodeMap_get_length(map, &len); + EXPECT_HR(hr, S_OK); + todo_wine ok(len == 3, "got %d\n", len); + + for (i = 0; i < len; i++) + { + item = NULL; + hr = IXMLDOMNamedNodeMap_get_item(map, i, &item); + EXPECT_HR(hr, S_OK); + + str = NULL; + hr = IXMLDOMNode_get_nodeName(item, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_(names[i])), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + str = NULL; + hr = IXMLDOMNode_get_prefix(item, &str); + if (prefixes[i]) + { + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_(prefixes[i])), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + } + else + EXPECT_HR(hr, S_FALSE); + + str = NULL; + hr = IXMLDOMNode_get_baseName(item, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_(basenames[i])), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + str = NULL; + hr = IXMLDOMNode_get_namespaceURI(item, &str); + if (uris[i]) + { + EXPECT_HR(hr, S_OK); + if (prefixes[i] && !strcmp(prefixes[i], "xmlns")) + todo_wine_if(entry->todo) + ok(!lstrcmpW(str, _bstr_(entry->xmlns_uri)), "got %s\n", wine_dbgstr_w(str)); + else + ok(!lstrcmpW(str, _bstr_(uris[i])), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + } + else + EXPECT_HR(hr, S_FALSE); + + str = NULL; + hr = IXMLDOMNode_get_text(item, &str); + EXPECT_HR(hr, S_OK); + ok(!lstrcmpW(str, _bstr_(texts[i])), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + IXMLDOMNode_Release(item); + } + + IXMLDOMNamedNodeMap_Release(map); + IXMLDOMNode_Release(node); + IXMLDOMDocument_Release(doc); + + entry++; + } + free_bstrs(); +} + START_TEST(domdoc) { HRESULT hr; @@ -12914,6 +13042,7 @@ START_TEST(domdoc) test_merging_text(); test_transformNodeToObject(); test_normalize_attribute_values(); + test_namespaces_as_attributes();
test_xsltemplate(); test_xsltext();
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/msxml3/nodemap.c | 123 ++++++++++++++++++++++++++++++++++++- dlls/msxml3/tests/domdoc.c | 2 +- 2 files changed, 122 insertions(+), 3 deletions(-)
diff --git a/dlls/msxml3/nodemap.c b/dlls/msxml3/nodemap.c index a9fef4769d..b35fd34103 100644 --- a/dlls/msxml3/nodemap.c +++ b/dlls/msxml3/nodemap.c @@ -39,6 +39,7 @@ #include "msxml_private.h"
#include "wine/debug.h" +#include "wine/list.h"
#ifdef HAVE_LIBXML2
@@ -54,10 +55,17 @@ typedef struct xmlNodePtr node; LONG iterator; IEnumVARIANT *enumvariant; + struct list nsattrs;
const struct nodemap_funcs *funcs; } xmlnodemap;
+typedef struct +{ + struct list entry; + xmlAttrPtr attr; +} nsattr_entry; + static HRESULT nodemap_get_item(IUnknown *iface, LONG index, VARIANT *item) { V_VT(item) = VT_DISPATCH; @@ -140,9 +148,20 @@ static ULONG WINAPI xmlnodemap_Release( TRACE("(%p)->(%d)\n", This, ref); if ( ref == 0 ) { + nsattr_entry *nsattr; + struct list *head; + xmlnode_release( This->node ); xmldoc_release( This->node->doc ); if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant); + while ((head = list_head( &This->nsattrs ))) + { + list_remove( head ); + nsattr = LIST_ENTRY( head, nsattr_entry, entry ); + xmlFreeNs( nsattr->attr->ns ); + xmlFreeProp( nsattr->attr ); + heap_free( nsattr ); + } heap_free( This ); }
@@ -224,16 +243,102 @@ static HRESULT WINAPI xmlnodemap_removeNamedItem( return This->funcs->remove_named_item(This->node, name, namedItem); }
+static HRESULT copy_ns_as_attrs(xmlnodemap *This) +{ + xmlNsPtr ns; + xmlNsPtr cur; + xmlAttrPtr prop; + nsattr_entry *entry; + + cur = This->node->nsDef; + while (cur) + { + entry = heap_alloc(sizeof(*entry)); + if (!entry) + return E_OUTOFMEMORY; + + ns = xmlNewNs(NULL, BAD_CAST "http://www.w3.org/2000/xmlns/", BAD_CAST "xmlns"); + if (!ns) + { + heap_free(entry); + return E_OUTOFMEMORY; + } + + prop = xmlNewNsProp(NULL, ns, cur->prefix, cur->href); + if (!prop) + { + xmlFreeNs(ns); + heap_free(entry); + return E_OUTOFMEMORY; + } + + prop->doc = This->node->doc; + entry->attr = prop; + list_add_tail(&This->nsattrs, &entry->entry); + + cur = cur->next; + } + + return S_OK; +} + static HRESULT WINAPI xmlnodemap_get_item( IXMLDOMNamedNodeMap *iface, LONG index, IXMLDOMNode** item) { + HRESULT hr; + xmlAttrPtr cur; + struct list *ptr; + nsattr_entry *nsattr; xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
TRACE("(%p)->(%d %p)\n", This, index, item);
- return This->funcs->get_item(This->node, index, item); + hr = This->funcs->get_item(This->node, index, item); + if (hr != S_FALSE) + return hr; + + ptr = list_head(&This->nsattrs); + if (!ptr) + { + if (!This->node->nsDef) + return S_FALSE; + + if (This->node->nsDef) + { + hr = copy_ns_as_attrs(This); + if (FAILED(hr)) + return hr; + } + + ptr = list_head(&This->nsattrs); + if (!ptr) + return FALSE; + } + + if (This->node->properties) + { + --index; + cur = This->node->properties; + while (cur->next) + { + --index; + cur = cur->next; + } + } + + if (index < 0) + return S_FALSE; + + while (index--) + ptr = list_next(ptr, ptr); + + nsattr = LIST_ENTRY(ptr, nsattr_entry, entry); + cur = nsattr->attr; + *item = create_node((xmlNodePtr) cur); + + return S_OK; }
static HRESULT WINAPI xmlnodemap_get_length( @@ -241,10 +346,23 @@ static HRESULT WINAPI xmlnodemap_get_length( LONG *length) { xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface ); + xmlNsPtr cur; + HRESULT hr;
TRACE("(%p)->(%p)\n", This, length);
- return This->funcs->get_length(This->node, length); + hr = This->funcs->get_length(This->node, length); + if (FAILED(hr)) + return hr; + + cur = This->node->nsDef; + while (cur) + { + ++*length; + cur = cur->next; + } + + return S_OK; }
static HRESULT WINAPI xmlnodemap_getQualifiedItem( @@ -447,6 +565,7 @@ IXMLDOMNamedNodeMap *create_nodemap(xmlNodePtr node, const struct nodemap_funcs This->ref = 1; This->iterator = 0; This->enumvariant = NULL; + list_init(&This->nsattrs); This->funcs = funcs;
init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNamedNodeMap_iface, &xmlnodemap_dispex); diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index ffb9e1462d..667feaa244 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -12894,7 +12894,7 @@ void test_namespaces_as_attributes(void) len = -1; hr = IXMLDOMNamedNodeMap_get_length(map, &len); EXPECT_HR(hr, S_OK); - todo_wine ok(len == 3, "got %d\n", len); + ok(len == 3, "got %d\n", len);
for (i = 0; i < len; i++) {
On 08/26/2018 07:27 PM, Daniel Lehman wrote:
static HRESULT WINAPI xmlnodemap_get_item( IXMLDOMNamedNodeMap *iface, LONG index, IXMLDOMNode** item) {
HRESULT hr;
xmlAttrPtr cur;
struct list *ptr;
nsattr_entry *nsattr; xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
TRACE("(%p)->(%d %p)\n", This, index, item);
- return This->funcs->get_item(This->node, index, item);
- hr = This->funcs->get_item(This->node, index, item);
- if (hr != S_FALSE)
return hr;
- ptr = list_head(&This->nsattrs);
- if (!ptr)
- {
if (!This->node->nsDef)
return S_FALSE;
if (This->node->nsDef)
{
hr = copy_ns_as_attrs(This);
if (FAILED(hr))
return hr;
}
ptr = list_head(&This->nsattrs);
if (!ptr)
return FALSE;
- }
- if (This->node->properties)
- {
--index;
cur = This->node->properties;
while (cur->next)
{
--index;
cur = cur->next;
}
- }
- if (index < 0)
return S_FALSE;
- while (index--)
ptr = list_next(ptr, ptr);
- nsattr = LIST_ENTRY(ptr, nsattr_entry, entry);
- cur = nsattr->attr;
- *item = create_node((xmlNodePtr) cur);
- return S_OK; }
This only applies to elements, so such fixup should happen there, not in generic nodemap method.
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/msxml3/attribute.c | 8 +++++++- dlls/msxml3/domdoc.c | 5 +++++ dlls/msxml3/msxml_private.h | 1 + dlls/msxml3/tests/domdoc.c | 14 ++++++-------- 4 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/dlls/msxml3/attribute.c b/dlls/msxml3/attribute.c index 637615b341..146d846597 100644 --- a/dlls/msxml3/attribute.c +++ b/dlls/msxml3/attribute.c @@ -44,6 +44,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
static const xmlChar xmlns[] = "xmlns"; +static const xmlChar xmlnsURI[] = "http://www.w3.org/2000/xmlns/";
typedef struct _domattr { @@ -559,7 +560,12 @@ static HRESULT WINAPI domattr_get_namespaceURI( if (xmlStrEqual(This->node.node->name, xmlns)) *p = bstr_from_xmlChar(xmlns); else if (xmlStrEqual(ns->prefix, xmlns)) - *p = SysAllocStringLen(NULL, 0); + { + if (xmldoc_version(This->node.node->doc) == MSXML6) + *p = bstr_from_xmlChar(xmlnsURI); + else + *p = SysAllocStringLen(NULL, 0); + } else if (ns->href) *p = bstr_from_xmlChar(ns->href); } diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 0b917c1302..445caaee69 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -396,6 +396,11 @@ xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc) return node; }
+MSXML_VERSION xmldoc_version(xmlDocPtr doc) +{ + return properties_from_xmlDocPtr(doc)->version; +} + BOOL is_preserving_whitespace(xmlNodePtr node) { domdoc_properties* properties = NULL; diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 94ef66b23d..aa9706defb 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -284,6 +284,7 @@ extern HRESULT xmldoc_add_orphan( xmlDocPtr doc, xmlNodePtr node ) DECLSPEC_HIDD extern HRESULT xmldoc_remove_orphan( xmlDocPtr doc, xmlNodePtr node ) DECLSPEC_HIDDEN; extern void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node) DECLSPEC_HIDDEN; extern xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc) DECLSPEC_HIDDEN; +extern MSXML_VERSION xmldoc_version( xmlDocPtr doc ) DECLSPEC_HIDDEN;
extern HRESULT XMLElement_create( xmlNodePtr node, LPVOID *ppObj, BOOL own ) DECLSPEC_HIDDEN;
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index 667feaa244..527a62b687 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -12834,16 +12834,15 @@ typedef struct _namespace_as_attribute_t { const GUID *guid; const char *clsid; const char *xmlns_uri; - BOOL todo; } namespace_as_attribute_t;
static const namespace_as_attribute_t namespace_as_attribute_test_data[] = { - { &CLSID_DOMDocument, "CLSID_DOMDocument", "", FALSE }, - { &CLSID_DOMDocument2, "CLSID_DOMDocument2", "", FALSE }, - { &CLSID_DOMDocument26, "CLSID_DOMDocument26", "", FALSE }, - { &CLSID_DOMDocument30, "CLSID_DOMDocument30", "", FALSE }, - { &CLSID_DOMDocument40, "CLSID_DOMDocument40", "", FALSE }, - { &CLSID_DOMDocument60, "CLSID_DOMDocument60", "http://www.w3.org/2000/xmlns/", TRUE }, + { &CLSID_DOMDocument, "CLSID_DOMDocument", "" }, + { &CLSID_DOMDocument2, "CLSID_DOMDocument2", "" }, + { &CLSID_DOMDocument26, "CLSID_DOMDocument26", "" }, + { &CLSID_DOMDocument30, "CLSID_DOMDocument30", "" }, + { &CLSID_DOMDocument40, "CLSID_DOMDocument40", "" }, + { &CLSID_DOMDocument60, "CLSID_DOMDocument60", "http://www.w3.org/2000/xmlns/" }, { 0 } };
@@ -12931,7 +12930,6 @@ void test_namespaces_as_attributes(void) { EXPECT_HR(hr, S_OK); if (prefixes[i] && !strcmp(prefixes[i], "xmlns")) - todo_wine_if(entry->todo) ok(!lstrcmpW(str, _bstr_(entry->xmlns_uri)), "got %s\n", wine_dbgstr_w(str)); else ok(!lstrcmpW(str, _bstr_(uris[i])), "got %s\n", wine_dbgstr_w(str));
On 08/26/2018 07:27 PM, Daniel Lehman wrote:
static const xmlChar xmlns[] = "xmlns"; +static const xmlChar xmlnsURI[] ="http://www.w3.org/2000/xmlns/";
typedef struct _domattr { @@ -559,7 +560,12 @@ static HRESULT WINAPI domattr_get_namespaceURI( if (xmlStrEqual(This->node.node->name, xmlns)) *p = bstr_from_xmlChar(xmlns); else if (xmlStrEqual(ns->prefix, xmlns))
*p = SysAllocStringLen(NULL, 0);
{
if (xmldoc_version(This->node.node->doc) == MSXML6)
*p = bstr_from_xmlChar(xmlnsURI);
else
*p = SysAllocStringLen(NULL, 0);
} else if (ns->href) *p = bstr_from_xmlChar(ns->href); }
This could be WCHAR constant to avoid conversion, defined in the method body, if it's not used anywhere else.