msxml3: IXMLDOMSchemaCollection/XMLSchemaCache backend.
Implemented on top of libxml's hash table.
This commit is contained in:
parent
8db0dd5335
commit
6e97fcf94e
|
@ -2,6 +2,7 @@
|
|||
* Schema cache implementation
|
||||
*
|
||||
* Copyright 2007 Huw Davies
|
||||
* Copyright 2010 Adam Martinson for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
@ -35,27 +37,193 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msxml);
|
||||
|
||||
/* We use a chained hashtable, which can hold any number of schemas
|
||||
* TODO: XDR schema support
|
||||
* TODO: grow/shrink hashtable depending on load factor
|
||||
* TODO: implement read-only where appropriate
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
/* This is just the number of buckets, should be prime */
|
||||
#define DEFAULT_HASHTABLE_SIZE 31
|
||||
|
||||
#ifdef HAVE_LIBXML2
|
||||
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include <libxml/schemasInternals.h>
|
||||
#include <libxml/hash.h>
|
||||
|
||||
static const xmlChar XSD_schema[] = "schema";
|
||||
static const xmlChar XSD_nsURI[] = "http://www.w3.org/2001/XMLSchema";
|
||||
static const xmlChar XDR_schema[] = "Schema";
|
||||
static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data";
|
||||
|
||||
/* Supported Types:
|
||||
* msxml3 - XDR only
|
||||
* msxml4 - XDR & XSD
|
||||
* msxml5 - XDR & XSD
|
||||
* mxsml6 - XSD only
|
||||
*/
|
||||
typedef enum _SCHEMA_TYPE {
|
||||
SCHEMA_TYPE_INVALID,
|
||||
SCHEMA_TYPE_XDR,
|
||||
SCHEMA_TYPE_XSD
|
||||
} SCHEMA_TYPE;
|
||||
|
||||
typedef struct _schema_cache
|
||||
{
|
||||
const struct IXMLDOMSchemaCollectionVtbl *lpVtbl;
|
||||
xmlHashTablePtr cache;
|
||||
LONG ref;
|
||||
} schema_t;
|
||||
} schema_cache;
|
||||
|
||||
static inline schema_t *impl_from_IXMLDOMSchemaCollection( IXMLDOMSchemaCollection *iface )
|
||||
typedef struct _cache_entry
|
||||
{
|
||||
return (schema_t *)((char*)iface - FIELD_OFFSET(schema_t, lpVtbl));
|
||||
SCHEMA_TYPE type;
|
||||
xmlSchemaPtr schema;
|
||||
xmlDocPtr doc;
|
||||
LONG ref;
|
||||
} cache_entry;
|
||||
|
||||
static LONG cache_entry_add_ref(cache_entry* entry)
|
||||
{
|
||||
LONG ref = InterlockedIncrement(&entry->ref);
|
||||
TRACE("%p new ref %d\n", entry, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_QueryInterface( IXMLDOMSchemaCollection *iface, REFIID riid, void** ppvObject )
|
||||
static LONG cache_entry_release(cache_entry* entry)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
LONG ref = InterlockedDecrement(&entry->ref);
|
||||
TRACE("%p new ref %d\n", entry, ref);
|
||||
|
||||
TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
|
||||
if (ref == 0)
|
||||
{
|
||||
if (entry->type == SCHEMA_TYPE_XSD)
|
||||
{
|
||||
xmldoc_release(entry->doc);
|
||||
entry->schema->doc = NULL;
|
||||
xmlSchemaFree(entry->schema);
|
||||
heap_free(entry);
|
||||
}
|
||||
else /* SCHEMA_TYPE_XDR */
|
||||
{
|
||||
xmldoc_release(entry->doc);
|
||||
heap_free(entry);
|
||||
}
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
if ( IsEqualIID( riid, &IID_IUnknown ) ||
|
||||
IsEqualIID( riid, &IID_IDispatch ) ||
|
||||
IsEqualIID( riid, &IID_IXMLDOMSchemaCollection ) )
|
||||
static inline schema_cache *impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection *iface)
|
||||
{
|
||||
return (schema_cache *)((char*)iface - FIELD_OFFSET(schema_cache, lpVtbl));
|
||||
}
|
||||
|
||||
static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema)
|
||||
{
|
||||
xmlNodePtr root;
|
||||
if (schema)
|
||||
root = xmlDocGetRootElement(schema);
|
||||
if (root && root->ns)
|
||||
{
|
||||
|
||||
if (xmlStrEqual(root->name, XDR_schema) &&
|
||||
xmlStrEqual(root->ns->href, XDR_nsURI))
|
||||
{
|
||||
return SCHEMA_TYPE_XDR;
|
||||
}
|
||||
else if (xmlStrEqual(root->name, XSD_schema) &&
|
||||
xmlStrEqual(root->ns->href, XSD_nsURI))
|
||||
{
|
||||
return SCHEMA_TYPE_XSD;
|
||||
}
|
||||
}
|
||||
return SCHEMA_TYPE_INVALID;
|
||||
}
|
||||
|
||||
static cache_entry* cache_entry_from_url(char const* url)
|
||||
{
|
||||
cache_entry* entry = heap_alloc(sizeof(cache_entry));
|
||||
xmlSchemaParserCtxtPtr spctx = xmlSchemaNewParserCtxt(url);
|
||||
entry->type = SCHEMA_TYPE_XSD;
|
||||
entry->ref = 0;
|
||||
if (spctx)
|
||||
{
|
||||
if((entry->schema = xmlSchemaParse(spctx)))
|
||||
{
|
||||
xmldoc_init(entry->schema->doc, &CLSID_DOMDocument40);
|
||||
entry->doc = entry->schema->doc;
|
||||
xmldoc_add_ref(entry->doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
heap_free(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
xmlSchemaFreeParserCtxt(spctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("schema for nsURI %s not found\n", wine_dbgstr_a(url));
|
||||
heap_free(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc)
|
||||
{
|
||||
cache_entry* entry = heap_alloc(sizeof(cache_entry));
|
||||
xmlSchemaParserCtxtPtr spctx;
|
||||
xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
|
||||
|
||||
entry->type = SCHEMA_TYPE_XSD;
|
||||
entry->ref = 0;
|
||||
spctx = xmlSchemaNewDocParserCtxt(new_doc);
|
||||
|
||||
if ((entry->schema = xmlSchemaParse(spctx)))
|
||||
{
|
||||
xmldoc_init(entry->schema->doc, &CLSID_DOMDocument40);
|
||||
entry->doc = entry->schema->doc;
|
||||
xmldoc_add_ref(entry->doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("failed to parse doc\n");
|
||||
xmlFreeDoc(new_doc);
|
||||
heap_free(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
xmlSchemaFreeParserCtxt(spctx);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc)
|
||||
{
|
||||
cache_entry* entry = heap_alloc(sizeof(cache_entry));
|
||||
xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
|
||||
|
||||
FIXME("XDR schema support not implemented\n");
|
||||
entry->type = SCHEMA_TYPE_XDR;
|
||||
entry->ref = 0;
|
||||
entry->schema = NULL;
|
||||
entry->doc = new_doc;
|
||||
xmldoc_init(entry->doc, &CLSID_DOMDocument30);
|
||||
xmldoc_add_ref(entry->doc);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection *iface, REFIID riid, void** ppvObject)
|
||||
{
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
|
||||
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
if ( IsEqualIID(riid, &IID_IUnknown) ||
|
||||
IsEqualIID(riid, &IID_IDispatch) ||
|
||||
IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) )
|
||||
{
|
||||
*ppvObject = iface;
|
||||
}
|
||||
|
@ -65,36 +233,42 @@ static HRESULT WINAPI schema_cache_QueryInterface( IXMLDOMSchemaCollection *ifac
|
|||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IXMLDOMSchemaCollection_AddRef( iface );
|
||||
IXMLDOMSchemaCollection_AddRef(iface);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI schema_cache_AddRef( IXMLDOMSchemaCollection *iface )
|
||||
static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection *iface)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
LONG ref = InterlockedIncrement( &This->ref );
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
LONG ref = InterlockedIncrement(&This->ref);
|
||||
TRACE("%p new ref %d\n", This, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static ULONG WINAPI schema_cache_Release( IXMLDOMSchemaCollection *iface )
|
||||
static void cache_free(void* data, xmlChar* name /* ignored */)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
LONG ref = InterlockedDecrement( &This->ref );
|
||||
cache_entry_release((cache_entry*)data);
|
||||
}
|
||||
|
||||
static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection *iface)
|
||||
{
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
LONG ref = InterlockedDecrement(&This->ref);
|
||||
TRACE("%p new ref %d\n", This, ref);
|
||||
|
||||
if ( ref == 0 )
|
||||
if (ref == 0)
|
||||
{
|
||||
heap_free( This );
|
||||
xmlHashFree(This->cache, cache_free);
|
||||
heap_free(This);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_GetTypeInfoCount( IXMLDOMSchemaCollection *iface, UINT* pctinfo )
|
||||
static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection *iface, UINT* pctinfo)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
|
||||
TRACE("(%p)->(%p)\n", This, pctinfo);
|
||||
|
||||
|
@ -103,10 +277,10 @@ static HRESULT WINAPI schema_cache_GetTypeInfoCount( IXMLDOMSchemaCollection *if
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_GetTypeInfo( IXMLDOMSchemaCollection *iface,
|
||||
UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
|
||||
static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection *iface,
|
||||
UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
|
||||
|
@ -116,14 +290,14 @@ static HRESULT WINAPI schema_cache_GetTypeInfo( IXMLDOMSchemaCollection *iface,
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_GetIDsOfNames( IXMLDOMSchemaCollection *iface,
|
||||
REFIID riid,
|
||||
LPOLESTR* rgszNames,
|
||||
UINT cNames,
|
||||
LCID lcid,
|
||||
DISPID* rgDispId )
|
||||
static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection *iface,
|
||||
REFIID riid,
|
||||
LPOLESTR* rgszNames,
|
||||
UINT cNames,
|
||||
LCID lcid,
|
||||
DISPID* rgDispId)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
ITypeInfo *typeinfo;
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -143,17 +317,17 @@ static HRESULT WINAPI schema_cache_GetIDsOfNames( IXMLDOMSchemaCollection *iface
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_Invoke( IXMLDOMSchemaCollection *iface,
|
||||
DISPID dispIdMember,
|
||||
REFIID riid,
|
||||
LCID lcid,
|
||||
WORD wFlags,
|
||||
DISPPARAMS* pDispParams,
|
||||
VARIANT* pVarResult,
|
||||
EXCEPINFO* pExcepInfo,
|
||||
UINT* puArgErr )
|
||||
static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection *iface,
|
||||
DISPID dispIdMember,
|
||||
REFIID riid,
|
||||
LCID lcid,
|
||||
WORD wFlags,
|
||||
DISPPARAMS* pDispParams,
|
||||
VARIANT* pVarResult,
|
||||
EXCEPINFO* pExcepInfo,
|
||||
UINT* puArgErr)
|
||||
{
|
||||
schema_t *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection(iface);
|
||||
ITypeInfo *typeinfo;
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -171,48 +345,138 @@ static HRESULT WINAPI schema_cache_Invoke( IXMLDOMSchemaCollection *iface,
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_add( IXMLDOMSchemaCollection *iface, BSTR uri, VARIANT var )
|
||||
static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection *iface, BSTR uri, VARIANT var)
|
||||
{
|
||||
FIXME("(%p)->(%s, var(vt %x)): stub\n", iface, debugstr_w(uri), V_VT(&var));
|
||||
schema_cache *This = impl_from_IXMLDOMSchemaCollection( iface );
|
||||
xmlChar* name = xmlChar_from_wchar(uri);
|
||||
TRACE("(%p)->(%s, var(vt %x))\n", This, debugstr_w(uri), V_VT(&var));
|
||||
|
||||
switch (V_VT(&var))
|
||||
{
|
||||
case VT_NULL:
|
||||
{
|
||||
xmlHashRemoveEntry(This->cache, name, cache_free);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_BSTR:
|
||||
{
|
||||
xmlChar* url = xmlChar_from_wchar(V_BSTR(&var));
|
||||
cache_entry* entry = cache_entry_from_url((char const*)url);
|
||||
heap_free(url);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
cache_entry_add_ref(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
heap_free(name);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
xmlHashRemoveEntry(This->cache, name, cache_free);
|
||||
xmlHashAddEntry(This->cache, name, entry);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_DISPATCH:
|
||||
{
|
||||
xmlDocPtr doc = NULL;
|
||||
cache_entry* entry;
|
||||
SCHEMA_TYPE type;
|
||||
IXMLDOMNode* domnode = NULL;
|
||||
IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
|
||||
|
||||
if (domnode)
|
||||
doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
|
||||
|
||||
if (!doc)
|
||||
{
|
||||
IXMLDOMNode_Release(domnode);
|
||||
heap_free(name);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
type = schema_type_from_xmlDocPtr(doc);
|
||||
|
||||
if (type == SCHEMA_TYPE_XSD)
|
||||
{
|
||||
entry = cache_entry_from_xsd_doc(doc);
|
||||
}
|
||||
else if (type == SCHEMA_TYPE_XDR)
|
||||
{
|
||||
entry = cache_entry_from_xdr_doc(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("invalid schema!\n");
|
||||
entry = NULL;
|
||||
}
|
||||
|
||||
IXMLDOMNode_Release(domnode);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
cache_entry_add_ref(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
heap_free(name);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
xmlHashRemoveEntry(This->cache, name, cache_free);
|
||||
xmlHashAddEntry(This->cache, name, entry);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
heap_free(name);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
heap_free(name);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_get( IXMLDOMSchemaCollection *iface, BSTR uri, IXMLDOMNode **node )
|
||||
static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection *iface, BSTR uri, IXMLDOMNode **node)
|
||||
{
|
||||
FIXME("stub\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_remove( IXMLDOMSchemaCollection *iface, BSTR uri )
|
||||
static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection *iface, BSTR uri)
|
||||
{
|
||||
FIXME("stub\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_get_length( IXMLDOMSchemaCollection *iface, LONG *length )
|
||||
static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection *iface, LONG *length)
|
||||
{
|
||||
FIXME("stub\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_get_namespaceURI( IXMLDOMSchemaCollection *iface, LONG index, BSTR *len )
|
||||
static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection *iface, LONG index, BSTR *len)
|
||||
{
|
||||
FIXME("stub\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_addCollection( IXMLDOMSchemaCollection *iface, IXMLDOMSchemaCollection *otherCollection )
|
||||
static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection *iface, IXMLDOMSchemaCollection *otherCollection)
|
||||
{
|
||||
FIXME("stub\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI schema_cache_get__newEnum( IXMLDOMSchemaCollection *iface, IUnknown **ppUnk )
|
||||
static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection *iface, IUnknown **ppUnk)
|
||||
{
|
||||
FIXME("stub\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/* TODO: validate? validateOnLoad property? */
|
||||
static const struct IXMLDOMSchemaCollectionVtbl schema_vtbl =
|
||||
{
|
||||
schema_cache_QueryInterface,
|
||||
|
@ -233,13 +497,25 @@ static const struct IXMLDOMSchemaCollectionVtbl schema_vtbl =
|
|||
|
||||
HRESULT SchemaCache_create(IUnknown *pUnkOuter, LPVOID *ppObj)
|
||||
{
|
||||
schema_t *schema = heap_alloc( sizeof (*schema) );
|
||||
schema_cache *schema = heap_alloc( sizeof (*schema) );
|
||||
if( !schema )
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
schema->lpVtbl = &schema_vtbl;
|
||||
schema->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
|
||||
schema->ref = 1;
|
||||
|
||||
*ppObj = &schema->lpVtbl;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
HRESULT SchemaCache_create(IUnknown *pUnkOuter, LPVOID *ppObj)
|
||||
{
|
||||
MESSAGE("This program tried to use a SchemaCache object, but\n"
|
||||
"libxml2 support was not present at compile time.\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue