>From dad7036aff1602c66fee8e388e7000fb58c74259 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 24 Jan 2012 10:40:56 +0300 Subject: [PATCH 1/3] Put all defined document namespaces in collection --- dlls/msxml3/domdoc.c | 38 +++++++++++- dlls/msxml3/msxml_private.h | 5 +- dlls/msxml3/schema.c | 131 ++++++++++++++++++++++++++++++++----------- dlls/msxml3/tests/domdoc.c | 117 +++++++++++++++++++++++++------------- 4 files changed, 211 insertions(+), 80 deletions(-) diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 517b581..8aa1a21 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -149,6 +149,8 @@ struct domdoc /* events */ IDispatch *events[EVENTID_LAST]; + + IXMLDOMSchemaCollection2 *namespaces; }; static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v) @@ -350,6 +352,15 @@ static void free_properties(domdoc_properties* properties) } } +static void release_namespaces(domdoc *This) +{ + if (This->namespaces) + { + IXMLDOMSchemaCollection2_Release(This->namespaces); + This->namespaces = NULL; + } +} + /* links a "node.node) { priv_from_xmlDocPtr(get_doc(This))->properties = NULL; @@ -901,6 +914,7 @@ static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface ) for (eid = 0; eid < EVENTID_LAST; eid++) if (This->events[eid]) IDispatch_Release(This->events[eid]); + release_namespaces(This); heap_free(This); } @@ -2273,11 +2287,10 @@ static HRESULT WINAPI domdoc_loadXML( } } } + if(!xmldoc) xmldoc = xmlNewDoc(NULL); - xmldoc->_private = create_priv(); - hr2 = attach_xmldoc(This, xmldoc); if( FAILED(hr2) ) hr = hr2; @@ -2513,11 +2526,27 @@ static HRESULT WINAPI domdoc_get_namespaces( IXMLDOMSchemaCollection** collection ) { domdoc *This = impl_from_IXMLDOMDocument3( iface ); - FIXME("(%p)->(%p): stub\n", This, collection); + HRESULT hr; + + FIXME("(%p)->(%p): semi-stub\n", This, collection); if (!collection) return E_POINTER; - return E_NOTIMPL; + if (!This->namespaces) + { + hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces); + if (hr != S_OK) return hr; + + hr = cache_from_doc_ns(This->namespaces, &This->node); + if (hr != S_OK) + release_namespaces(This); + } + + if (This->namespaces) + return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces, + &IID_IXMLDOMSchemaCollection, (void**)collection); + + return hr; } static HRESULT WINAPI domdoc_get_schemas( @@ -3419,6 +3448,7 @@ HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document) doc->safeopt = 0; doc->bsc = NULL; doc->cp_list = NULL; + doc->namespaces = NULL; memset(doc->events, 0, sizeof(doc->events)); /* events connection points */ diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 6c9edfe..e51501b 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -345,8 +345,9 @@ extern HRESULT node_create_supporterrorinfo(const tid_t*,void**) DECLSPEC_HIDDEN extern HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document) DECLSPEC_HIDDEN; -extern HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree) DECLSPEC_HIDDEN; -extern XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node) DECLSPEC_HIDDEN; +extern HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2*, xmlNodePtr) DECLSPEC_HIDDEN; +extern XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2*, xmlNodePtr) DECLSPEC_HIDDEN; +extern HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2*, xmlnode*) DECLSPEC_HIDDEN; extern XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */) DECLSPEC_HIDDEN; extern XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */) DECLSPEC_HIDDEN; diff --git a/dlls/msxml3/schema.c b/dlls/msxml3/schema.c index 6913e35..c614d39 100644 --- a/dlls/msxml3/schema.c +++ b/dlls/msxml3/schema.c @@ -35,6 +35,7 @@ # include # include # include +# include #endif #include "windef.h" @@ -75,17 +76,21 @@ static xmlSchemaPtr datatypes_schema; static const WCHAR emptyW[] = {0}; -/* Supported Types: +/* Supported types: * msxml3 - XDR only * msxml4 - XDR & XSD * msxml5 - XDR & XSD * mxsml6 - XSD only + * + * CacheType_NS is a special type used for read-only collection build with + * IXMLDOMDocument2::namespaces() */ -typedef enum _SCHEMA_TYPE { - SCHEMA_TYPE_INVALID, - SCHEMA_TYPE_XDR, - SCHEMA_TYPE_XSD -} SCHEMA_TYPE; +typedef enum { + CacheEntryType_Invalid, + CacheEntryType_XDR, + CacheEntryType_XSD, + CacheEntryType_NS +} CacheEntryType; typedef struct { @@ -99,15 +104,15 @@ typedef struct VARIANT_BOOL validateOnLoad; } schema_cache; -typedef struct _cache_entry +typedef struct { - SCHEMA_TYPE type; + CacheEntryType type; xmlSchemaPtr schema; xmlDocPtr doc; LONG ref; } cache_entry; -typedef struct _cache_index_data +typedef struct { LONG index; BSTR* out; @@ -761,21 +766,21 @@ static LONG cache_entry_release(cache_entry* entry) if (ref == 0) { - if (entry->type == SCHEMA_TYPE_XSD) + if (entry->type == CacheEntryType_XSD) { xmldoc_release(entry->doc); entry->schema->doc = NULL; xmlSchemaFree(entry->schema); - heap_free(entry); } - else /* SCHEMA_TYPE_XDR */ + else if (entry->type == CacheEntryType_XDR) { xmldoc_release(entry->doc); xmldoc_release(entry->schema->doc); entry->schema->doc = NULL; xmlSchemaFree(entry->schema); - heap_free(entry); } + + heap_free(entry); } return ref; } @@ -785,7 +790,7 @@ static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaColl return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface); } -static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema) +static inline CacheEntryType cache_type_from_xmlDocPtr(xmlDocPtr schema) { xmlNodePtr root = NULL; if (schema) @@ -796,15 +801,15 @@ static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema) if (xmlStrEqual(root->name, XDR_schema) && xmlStrEqual(root->ns->href, XDR_nsURI)) { - return SCHEMA_TYPE_XDR; + return CacheEntryType_XDR; } else if (xmlStrEqual(root->name, XSD_schema) && xmlStrEqual(root->ns->href, XSD_nsURI)) { - return SCHEMA_TYPE_XSD; + return CacheEntryType_XSD; } } - return SCHEMA_TYPE_INVALID; + return CacheEntryType_Invalid; } static BOOL link_datatypes(xmlDocPtr schema) @@ -845,7 +850,7 @@ static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI /* TODO: if the nsURI is different from the default xmlns or targetNamespace, * do we need to do something special here? */ - entry->type = SCHEMA_TYPE_XSD; + entry->type = CacheEntryType_XSD; entry->ref = 0; spctx = xmlSchemaNewDocParserCtxt(new_doc); @@ -874,7 +879,7 @@ static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI link_datatypes(xsd_doc); - entry->type = SCHEMA_TYPE_XDR; + entry->type = CacheEntryType_XDR; entry->ref = 0; spctx = xmlSchemaNewDocParserCtxt(xsd_doc); @@ -906,7 +911,7 @@ static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXM xmlDocPtr doc = NULL; HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc); VARIANT_BOOL b = VARIANT_FALSE; - SCHEMA_TYPE type = SCHEMA_TYPE_INVALID; + CacheEntryType type = CacheEntryType_Invalid; if (hr != S_OK) { @@ -928,17 +933,17 @@ static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXM } } doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc; - type = schema_type_from_xmlDocPtr(doc); + type = cache_type_from_xmlDocPtr(doc); switch (type) { - case SCHEMA_TYPE_XSD: + case CacheEntryType_XSD: entry = cache_entry_from_xsd_doc(doc, nsURI, version); break; - case SCHEMA_TYPE_XDR: + case CacheEntryType_XDR: entry = cache_entry_from_xdr_doc(doc, nsURI, version); break; - case SCHEMA_TYPE_INVALID: + default: entry = NULL; FIXME("invalid schema\n"); break; @@ -948,6 +953,69 @@ static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXM return entry; } +static void cache_free(void* data, xmlChar* name /* ignored */) +{ + cache_entry_release((cache_entry*)data); +} + +/* This one adds all namespaces defined in document to a cache, without anything + associated with uri obviously. + Unfortunately namespace:: axis implementation in libxml2 differs from what we need, + it uses additional node type to describe namespace definition attribute while + in msxml it's expected to be a normal attribute - as a workaround document is + queried at libxml2 level here. */ +HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2 *iface, xmlnode *node) +{ + static const xmlChar query[] = "//*/namespace::*"; + schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface); + xmlXPathObjectPtr nodeset; + xmlXPathContextPtr ctxt; + + ctxt = xmlXPathNewContext(node->node->doc); + + nodeset = xmlXPathEvalExpression(query, ctxt); + xmlXPathFreeContext(ctxt); + + if (nodeset) + { + int pos = 0, len = xmlXPathNodeSetGetLength(nodeset->nodesetval); + + if (len == 0) return S_OK; + + while (pos < len) + { + xmlNodePtr node = xmlXPathNodeSetItem(nodeset->nodesetval, pos); + if (node->type == XML_NAMESPACE_DECL) + { + static const xmlChar defns[] = "http://www.w3.org/XML/1998/namespace"; + xmlNsPtr ns = (xmlNsPtr)node; + cache_entry *entry; + + /* filter out default uri */ + if (xmlStrEqual(ns->href, defns)) + { + pos++; + continue; + } + + entry = heap_alloc(sizeof(cache_entry)); + entry->type = CacheEntryType_NS; + entry->ref = 1; + entry->schema = NULL; + entry->doc = NULL; + + xmlHashRemoveEntry(This->cache, ns->href, cache_free); + xmlHashAddEntry(This->cache, ns->href, entry); + } + pos++; + } + + xmlXPathFreeObject(nodeset); + } + + return S_OK; +} + static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface, REFIID riid, void** ppvObject) { @@ -986,11 +1054,6 @@ static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface) return ref; } -static void cache_free(void* data, xmlChar* name /* ignored */) -{ - cache_entry_release((cache_entry*)data); -} - static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface) { schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface); @@ -1079,7 +1142,7 @@ static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri { xmlDocPtr doc = NULL; cache_entry* entry; - SCHEMA_TYPE type; + CacheEntryType type; IXMLDOMNode* domnode = NULL; IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode); @@ -1092,13 +1155,13 @@ static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri heap_free(name); return E_INVALIDARG; } - type = schema_type_from_xmlDocPtr(doc); + type = cache_type_from_xmlDocPtr(doc); - if (type == SCHEMA_TYPE_XSD) + if (type == CacheEntryType_XSD) { entry = cache_entry_from_xsd_doc(doc, name, This->version); } - else if (type == SCHEMA_TYPE_XDR) + else if (type == CacheEntryType_XDR) { entry = cache_entry_from_xdr_doc(doc, name, This->version); } @@ -1154,7 +1217,7 @@ static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri heap_free(name); /* TODO: this should be read-only */ - if (entry) + if (entry && entry->doc) return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node); *node = NULL; diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index a00f24a..df8e1cb 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -5536,7 +5536,9 @@ void test_XPath(void) IXMLDOMNodeList *list; IXMLDOMElement *elem; IXMLDOMAttribute *attr; + DOMNodeType type; HRESULT hr; + LONG len; BSTR str; doc = create_document(&IID_IXMLDOMDocument2); @@ -5566,6 +5568,28 @@ void test_XPath(void) EXPECT_HR(hr, S_OK); expect_list_and_release(list, "E2.D1"); +if (0) +{ + /* namespace:: axis test is disabled until namespace definitions + are supported as attribute nodes, currently it's another node type */ + hr = IXMLDOMDocument2_selectNodes(doc, _bstr_("/root/namespace::*"), &list); + EXPECT_HR(hr, S_OK); + len = -1; + hr = IXMLDOMNodeList_get_length(list, &len); + EXPECT_HR(hr, S_OK); + ok(len == 2, "got %d\n", len); + + hr = IXMLDOMNodeList_nextNode(list, &node); + EXPECT_HR(hr, S_OK); + type = NODE_INVALID; + hr = IXMLDOMNode_get_nodeType(node, &type); + EXPECT_HR(hr, S_OK); + ok(type == NODE_ATTRIBUTE, "got %d\n", type); + IXMLDOMNode_Release(node); + + IXMLDOMNodeList_Release(list); +} + ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//c"), &list)); expect_list_and_release(list, "E3.E1.E2.D1 E3.E2.E2.D1"); @@ -11280,7 +11304,7 @@ static void test_nodeValue(void) static const char namespacesA[] = "" -" " +" " " " " " " " @@ -11324,7 +11348,6 @@ static void test_get_namespaces(void) /* no document loaded */ collection = (void*)0xdeadbeef; hr = IXMLDOMDocument2_get_namespaces(doc, &collection); -todo_wine EXPECT_HR(hr, S_OK); if (hr != S_OK) { @@ -11377,6 +11400,7 @@ todo_wine V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = (IDispatch*)doc2; hr = IXMLDOMSchemaCollection_add(collection, _bstr_(xsd_schema1_uri), v); +todo_wine EXPECT_HR(hr, E_FAIL); hr = IXMLDOMSchemaCollection_get_namespaceURI(collection, 0, &s); @@ -11386,40 +11410,47 @@ todo_wine hr = IXMLDOMSchemaCollection_get_namespaceURI(collection, 1, &s); EXPECT_HR(hr, S_OK); +todo_wine ok(!lstrcmpW(s, _bstr_("http://blahblah.org")), "got %s\n", wine_dbgstr_w(s)); SysFreeString(s); s = (void*)0xdeadbeef; hr = IXMLDOMSchemaCollection_get_namespaceURI(collection, 2, &s); +todo_wine { EXPECT_HR(hr, E_FAIL); ok(s == (void*)0xdeadbeef, "got %p\n", s); +} /* enumerate */ enumv = (void*)0xdeadbeef; hr = IXMLDOMSchemaCollection_get__newEnum(collection, (IUnknown**)&enumv); +todo_wine EXPECT_HR(hr, S_OK); - ok(enumv != NULL, "got %p\n", enumv); + if (hr == S_OK) + { + ok(enumv != NULL, "got %p\n", enumv); - V_VT(&v) = VT_EMPTY; - hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); - EXPECT_HR(hr, S_OK); - ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); - ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); - VariantClear(&v); + V_VT(&v) = VT_EMPTY; + hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); + EXPECT_HR(hr, S_OK); + ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); - V_VT(&v) = VT_EMPTY; - hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); - EXPECT_HR(hr, S_OK); - ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); - ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blahblah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); - VariantClear(&v); + V_VT(&v) = VT_EMPTY; + hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); + EXPECT_HR(hr, S_OK); + ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blahblah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); - V_VT(&v) = VT_NULL; - hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); - EXPECT_HR(hr, S_FALSE); - ok(V_VT(&v) == VT_EMPTY, "got %d\n", V_VT(&v)); + V_VT(&v) = VT_NULL; + hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); + EXPECT_HR(hr, S_FALSE); + ok(V_VT(&v) == VT_EMPTY, "got %d\n", V_VT(&v)); - IEnumVARIANT_Release(enumv); + IEnumVARIANT_Release(enumv); + } IXMLDOMSchemaCollection_Release(collection); IXMLDOMDocument2_Release(doc); @@ -11435,7 +11466,6 @@ todo_wine /* no document loaded */ collection = (void*)0xdeadbeef; hr = IXMLDOMDocument2_get_namespaces(doc, &collection); -todo_wine EXPECT_HR(hr, S_OK); if (hr != S_OK) { @@ -11483,6 +11513,7 @@ todo_wine V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = (IDispatch*)doc2; hr = IXMLDOMSchemaCollection_add(collection, _bstr_(xsd_schema1_uri), v); +todo_wine EXPECT_HR(hr, E_FAIL); IXMLDOMSchemaCollection_Release(doc2); @@ -11493,40 +11524,46 @@ todo_wine hr = IXMLDOMSchemaCollection_get_namespaceURI(collection, 1, &s); EXPECT_HR(hr, S_OK); +todo_wine ok(!lstrcmpW(s, _bstr_("http://blahblah.org")), "got %s\n", wine_dbgstr_w(s)); SysFreeString(s); s = (void*)0xdeadbeef; hr = IXMLDOMSchemaCollection_get_namespaceURI(collection, 2, &s); +todo_wine { EXPECT_HR(hr, E_FAIL); ok(s == (void*)0xdeadbeef, "got %p\n", s); - +} /* enumerate */ enumv = (void*)0xdeadbeef; hr = IXMLDOMSchemaCollection_get__newEnum(collection, (IUnknown**)&enumv); +todo_wine EXPECT_HR(hr, S_OK); - ok(enumv != NULL, "got %p\n", enumv); + if (hr == S_OK) + { + ok(enumv != NULL, "got %p\n", enumv); - V_VT(&v) = VT_EMPTY; - hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); - EXPECT_HR(hr, S_OK); - ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); - ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); - VariantClear(&v); + V_VT(&v) = VT_EMPTY; + hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); + EXPECT_HR(hr, S_OK); + ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); - V_VT(&v) = VT_EMPTY; - hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); - EXPECT_HR(hr, S_OK); - ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); - ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blahblah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); - VariantClear(&v); + V_VT(&v) = VT_EMPTY; + hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); + EXPECT_HR(hr, S_OK); + ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), _bstr_("http://blahblah.org")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); - V_VT(&v) = VT_NULL; - hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); - EXPECT_HR(hr, S_FALSE); - ok(V_VT(&v) == VT_EMPTY, "got %d\n", V_VT(&v)); + V_VT(&v) = VT_NULL; + hr = IEnumVARIANT_Next(enumv, 1, &v, NULL); + EXPECT_HR(hr, S_FALSE); + ok(V_VT(&v) == VT_EMPTY, "got %d\n", V_VT(&v)); - IEnumVARIANT_Release(enumv); + IEnumVARIANT_Release(enumv); + } IXMLDOMSchemaCollection_Release(collection); IXMLDOMDocument2_Release(doc); free_bstrs(); -- 1.5.6.5