/* * IMXNamespaceManager implementation * * Copyright 2011-2012 Nikolay Sivov for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define COBJMACROS #include "config.h" #include #ifdef HAVE_LIBXML2 # include # include # include #endif #include "windef.h" #include "winbase.h" #include "winuser.h" #include "ole2.h" #include "msxml6.h" #include "msxml_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msxml); struct ns { BSTR prefix; BSTR uri; }; struct nscontext { struct list entry; struct ns *ns; int count; int max_alloc; }; #define DEFAULT_PREFIX_ALLOC_COUNT 16 static const WCHAR xmlW[] = {'x','m','l',0}; static const WCHAR xmluriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g', '/','X','M','L','/','1','9','9','8','/','n','a','m','e','s','p','a','c','e',0}; typedef struct { DispatchEx dispex; IMXNamespaceManager IMXNamespaceManager_iface; IVBMXNamespaceManager IVBMXNamespaceManager_iface; LONG ref; struct list ctxts; VARIANT_BOOL override; } namespacemanager; static inline namespacemanager *impl_from_IMXNamespaceManager( IMXNamespaceManager *iface ) { return CONTAINING_RECORD(iface, namespacemanager, IMXNamespaceManager_iface); } static inline namespacemanager *impl_from_IVBMXNamespaceManager( IVBMXNamespaceManager *iface ) { return CONTAINING_RECORD(iface, namespacemanager, IVBMXNamespaceManager_iface); } static HRESULT declare_prefix(namespacemanager *This, const WCHAR *prefix, const WCHAR *uri) { struct nscontext *ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry); static const WCHAR emptyW[] = {0}; struct ns *ns; int i; if (ctxt->count == ctxt->max_alloc) { ctxt->max_alloc *= 2; ctxt->ns = heap_realloc(ctxt->ns, ctxt->max_alloc*sizeof(*ctxt->ns)); } if (!prefix) prefix = emptyW; ns = NULL; for (i = 0; i < ctxt->count; i++) if (!strcmpW(ctxt->ns[i].prefix, prefix)) { ns = &ctxt->ns[i]; break; } if (ns) { if (This->override == VARIANT_TRUE) { SysFreeString(ns->uri); ns->uri = SysAllocString(uri); return S_FALSE; } else return E_FAIL; } else { ctxt->ns[ctxt->count].prefix = SysAllocString(prefix); ctxt->ns[ctxt->count].uri = SysAllocString(uri); ctxt->count++; } return S_OK; } /* returned stored pointer, caller needs to copy it */ static HRESULT get_declared_prefix_idx(const struct nscontext *ctxt, LONG index, BSTR *prefix) { *prefix = NULL; if (index >= ctxt->count || index < 0) return E_FAIL; if (index > 0) index = ctxt->count - index; *prefix = ctxt->ns[index].prefix; return S_OK; } /* returned stored pointer, caller needs to copy it */ static HRESULT get_declared_prefix_uri(const struct list *ctxts, const WCHAR *uri, BSTR *prefix) { struct nscontext *ctxt; LIST_FOR_EACH_ENTRY(ctxt, ctxts, struct nscontext, entry) { int i; for (i = 0; i < ctxt->count; i++) if (!strcmpW(ctxt->ns[i].uri, uri)) { *prefix = ctxt->ns[i].prefix; return S_OK; } } *prefix = NULL; return E_FAIL; } static HRESULT get_uri_from_prefix(const struct nscontext *ctxt, const WCHAR *prefix, BSTR *uri) { int i; for (i = 0; i < ctxt->count; i++) if (!strcmpW(ctxt->ns[i].prefix, prefix)) { *uri = ctxt->ns[i].uri; return S_OK; } *uri = NULL; return S_FALSE; } static struct nscontext* alloc_ns_context(void) { struct nscontext *ctxt; ctxt = heap_alloc(sizeof(*ctxt)); if (!ctxt) return NULL; ctxt->count = 0; ctxt->max_alloc = DEFAULT_PREFIX_ALLOC_COUNT; ctxt->ns = heap_alloc(ctxt->max_alloc*sizeof(*ctxt->ns)); if (!ctxt->ns) { heap_free(ctxt); return NULL; } /* first allocated prefix is always 'xml' */ ctxt->ns[0].prefix = SysAllocString(xmlW); ctxt->ns[0].uri = SysAllocString(xmluriW); ctxt->count++; if (!ctxt->ns[0].prefix || !ctxt->ns[0].uri) { heap_free(ctxt->ns); heap_free(ctxt); return NULL; } return ctxt; } static void free_ns_context(struct nscontext *ctxt) { int i; for (i = 0; i < ctxt->count; i++) { SysFreeString(ctxt->ns[i].prefix); SysFreeString(ctxt->ns[i].uri); } heap_free(ctxt->ns); heap_free(ctxt); } static HRESULT WINAPI namespacemanager_QueryInterface(IMXNamespaceManager *iface, REFIID riid, void **ppvObject) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_QueryInterface(&This->IVBMXNamespaceManager_iface, riid, ppvObject); } static ULONG WINAPI namespacemanager_AddRef(IMXNamespaceManager *iface) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_AddRef(&This->IVBMXNamespaceManager_iface); } static ULONG WINAPI namespacemanager_Release(IMXNamespaceManager *iface) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_Release(&This->IVBMXNamespaceManager_iface); } static HRESULT WINAPI namespacemanager_putAllowOverride(IMXNamespaceManager *iface, VARIANT_BOOL override) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_put_allowOverride(&This->IVBMXNamespaceManager_iface, override); } static HRESULT WINAPI namespacemanager_getAllowOverride(IMXNamespaceManager *iface, VARIANT_BOOL *override) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_get_allowOverride(&This->IVBMXNamespaceManager_iface, override); } static HRESULT WINAPI namespacemanager_reset(IMXNamespaceManager *iface) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_reset(&This->IVBMXNamespaceManager_iface); } static HRESULT WINAPI namespacemanager_pushContext(IMXNamespaceManager *iface) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_pushContext(&This->IVBMXNamespaceManager_iface); } static HRESULT WINAPI namespacemanager_pushNodeContext(IMXNamespaceManager *iface, IXMLDOMNode *node, VARIANT_BOOL deep) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_pushNodeContext(&This->IVBMXNamespaceManager_iface, node, deep); } static HRESULT WINAPI namespacemanager_popContext(IMXNamespaceManager *iface) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); return IVBMXNamespaceManager_popContext(&This->IVBMXNamespaceManager_iface); } static HRESULT WINAPI namespacemanager_declarePrefix(IMXNamespaceManager *iface, const WCHAR *prefix, const WCHAR *namespaceURI) { static const WCHAR xmlnsW[] = {'x','m','l','n','s',0}; namespacemanager *This = impl_from_IMXNamespaceManager( iface ); TRACE("(%p)->(%s %s)\n", This, debugstr_w(prefix), debugstr_w(namespaceURI)); if (prefix && (!strcmpW(prefix, xmlW) || !strcmpW(prefix, xmlnsW) || !namespaceURI)) return E_INVALIDARG; return declare_prefix(This, prefix, namespaceURI); } static HRESULT WINAPI namespacemanager_getDeclaredPrefix(IMXNamespaceManager *iface, LONG index, WCHAR *prefix, int *prefix_len) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); struct nscontext *ctxt; HRESULT hr; BSTR prfx; TRACE("(%p)->(%d %p %p)\n", This, index, prefix, prefix_len); if (!prefix_len) return E_POINTER; ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry); hr = get_declared_prefix_idx(ctxt, index, &prfx); if (hr != S_OK) return hr; if (prefix) { if (*prefix_len < (INT)SysStringLen(prfx)) return E_XML_BUFFERTOOSMALL; strcpyW(prefix, prfx); } *prefix_len = SysStringLen(prfx); return S_OK; } static HRESULT WINAPI namespacemanager_getPrefix(IMXNamespaceManager *iface, const WCHAR *uri, LONG index, WCHAR *prefix, int *prefix_len) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); HRESULT hr; BSTR prfx; TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_w(uri), index, prefix, prefix_len); if (!uri || !*uri || !prefix_len) return E_INVALIDARG; hr = get_declared_prefix_uri(&This->ctxts, uri, &prfx); if (hr == S_OK) { /* TODO: figure out what index argument is for */ if (index) return E_FAIL; if (prefix) { if (*prefix_len < (INT)SysStringLen(prfx)) return E_XML_BUFFERTOOSMALL; strcpyW(prefix, prfx); } *prefix_len = SysStringLen(prfx); TRACE("prefix=%s\n", debugstr_w(prfx)); } return hr; } static HRESULT WINAPI namespacemanager_getURI(IMXNamespaceManager *iface, const WCHAR *prefix, IXMLDOMNode *node, WCHAR *uri, int *uri_len) { namespacemanager *This = impl_from_IMXNamespaceManager( iface ); struct nscontext *ctxt; HRESULT hr; BSTR urib; TRACE("(%p)->(%s %p %p %p)\n", This, debugstr_w(prefix), node, uri, uri_len); if (!prefix) return E_INVALIDARG; if (!uri_len) return E_POINTER; if (node) { FIXME("namespaces from DOM node not supported\n"); return E_NOTIMPL; } ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry); hr = get_uri_from_prefix(ctxt, prefix, &urib); if (hr == S_OK) { if (uri) { if (*uri_len < (INT)SysStringLen(urib)) return E_XML_BUFFERTOOSMALL; strcpyW(uri, urib); } } else if (uri) *uri = 0; *uri_len = SysStringLen(urib); return hr; } static const struct IMXNamespaceManagerVtbl MXNamespaceManagerVtbl = { namespacemanager_QueryInterface, namespacemanager_AddRef, namespacemanager_Release, namespacemanager_putAllowOverride, namespacemanager_getAllowOverride, namespacemanager_reset, namespacemanager_pushContext, namespacemanager_pushNodeContext, namespacemanager_popContext, namespacemanager_declarePrefix, namespacemanager_getDeclaredPrefix, namespacemanager_getPrefix, namespacemanager_getURI }; static HRESULT WINAPI vbnamespacemanager_QueryInterface(IVBMXNamespaceManager *iface, REFIID riid, void **obj) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); if ( IsEqualGUID( riid, &IID_IMXNamespaceManager) || IsEqualGUID( riid, &IID_IUnknown) ) { *obj = &This->IMXNamespaceManager_iface; } else if ( IsEqualGUID( riid, &IID_IVBMXNamespaceManager) || IsEqualGUID( riid, &IID_IDispatch) ) { *obj = &This->IVBMXNamespaceManager_iface; } else if (dispex_query_interface(&This->dispex, riid, obj)) { return *obj ? S_OK : E_NOINTERFACE; } else { TRACE("Unsupported interface %s\n", debugstr_guid(riid)); *obj = NULL; return E_NOINTERFACE; } IVBMXNamespaceManager_AddRef( iface ); return S_OK; } static ULONG WINAPI vbnamespacemanager_AddRef(IVBMXNamespaceManager *iface) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); ULONG ref = InterlockedIncrement( &This->ref ); TRACE("(%p)->(%u)\n", This, ref ); return ref; } static ULONG WINAPI vbnamespacemanager_Release(IVBMXNamespaceManager *iface) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); ULONG ref = InterlockedDecrement( &This->ref ); TRACE("(%p)->(%u)\n", This, ref ); if ( ref == 0 ) { struct nscontext *ctxt, *ctxt2; LIST_FOR_EACH_ENTRY_SAFE(ctxt, ctxt2, &This->ctxts, struct nscontext, entry) { list_remove(&ctxt->entry); free_ns_context(ctxt); } heap_free( This ); } return ref; } static HRESULT WINAPI vbnamespacemanager_GetTypeInfoCount(IVBMXNamespaceManager *iface, UINT *pctinfo) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); } static HRESULT WINAPI vbnamespacemanager_GetTypeInfo(IVBMXNamespaceManager *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); } static HRESULT WINAPI vbnamespacemanager_GetIDsOfNames(IVBMXNamespaceManager *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); } static HRESULT WINAPI vbnamespacemanager_Invoke(IVBMXNamespaceManager *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } static HRESULT WINAPI vbnamespacemanager_put_allowOverride(IVBMXNamespaceManager *iface, VARIANT_BOOL override) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); TRACE("(%p)->(%d)\n", This, override); This->override = override; return S_OK; } static HRESULT WINAPI vbnamespacemanager_get_allowOverride(IVBMXNamespaceManager *iface, VARIANT_BOOL *override) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); TRACE("(%p)->(%p)\n", This, override); if (!override) return E_POINTER; *override = This->override; return S_OK; } static HRESULT WINAPI vbnamespacemanager_reset(IVBMXNamespaceManager *iface) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI vbnamespacemanager_pushContext(IVBMXNamespaceManager *iface) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); struct nscontext *ctxt; TRACE("(%p)\n", This); ctxt = alloc_ns_context(); if (!ctxt) return E_OUTOFMEMORY; list_add_head(&This->ctxts, &ctxt->entry); return S_OK; } static HRESULT WINAPI vbnamespacemanager_pushNodeContext(IVBMXNamespaceManager *iface, IXMLDOMNode *node, VARIANT_BOOL deep) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); FIXME("(%p)->(%p %d): stub\n", This, node, deep); return E_NOTIMPL; } static HRESULT WINAPI vbnamespacemanager_popContext(IVBMXNamespaceManager *iface) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); const struct list *next; struct nscontext *ctxt; TRACE("(%p)\n", This); next = list_next(&This->ctxts, list_head(&This->ctxts)); if (!next) return E_FAIL; ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry); list_remove(list_head(&This->ctxts)); free_ns_context(ctxt); return S_OK; } static HRESULT WINAPI vbnamespacemanager_declarePrefix(IVBMXNamespaceManager *iface, BSTR prefix, BSTR namespaceURI) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); return IMXNamespaceManager_declarePrefix(&This->IMXNamespaceManager_iface, prefix, namespaceURI); } static HRESULT WINAPI vbnamespacemanager_getDeclaredPrefixes(IVBMXNamespaceManager *iface, IMXNamespacePrefixes** prefixes) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); FIXME("(%p)->(%p): stub\n", This, prefixes); return E_NOTIMPL; } static HRESULT WINAPI vbnamespacemanager_getPrefixes(IVBMXNamespaceManager *iface, BSTR namespaceURI, IMXNamespacePrefixes** prefixes) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), prefixes); return E_NOTIMPL; } static HRESULT WINAPI vbnamespacemanager_getURI(IVBMXNamespaceManager *iface, BSTR prefix, VARIANT* uri) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(prefix), uri); return E_NOTIMPL; } static HRESULT WINAPI vbnamespacemanager_getURIFromNode(IVBMXNamespaceManager *iface, BSTR prefix, IXMLDOMNode *node, VARIANT *uri) { namespacemanager *This = impl_from_IVBMXNamespaceManager( iface ); FIXME("(%p)->(%s %p %p): stub\n", This, debugstr_w(prefix), node, uri); return E_NOTIMPL; } static const struct IVBMXNamespaceManagerVtbl VBMXNamespaceManagerVtbl = { vbnamespacemanager_QueryInterface, vbnamespacemanager_AddRef, vbnamespacemanager_Release, vbnamespacemanager_GetTypeInfoCount, vbnamespacemanager_GetTypeInfo, vbnamespacemanager_GetIDsOfNames, vbnamespacemanager_Invoke, vbnamespacemanager_put_allowOverride, vbnamespacemanager_get_allowOverride, vbnamespacemanager_reset, vbnamespacemanager_pushContext, vbnamespacemanager_pushNodeContext, vbnamespacemanager_popContext, vbnamespacemanager_declarePrefix, vbnamespacemanager_getDeclaredPrefixes, vbnamespacemanager_getPrefixes, vbnamespacemanager_getURI, vbnamespacemanager_getURIFromNode }; static const tid_t namespacemanager_iface_tids[] = { IVBMXNamespaceManager_tid, 0 }; static dispex_static_data_t namespacemanager_dispex = { NULL, IVBMXNamespaceManager_tid, NULL, namespacemanager_iface_tids }; HRESULT MXNamespaceManager_create(void **obj) { namespacemanager *This; struct nscontext *ctxt; TRACE("(%p)\n", obj); This = heap_alloc( sizeof (*This) ); if( !This ) return E_OUTOFMEMORY; This->IMXNamespaceManager_iface.lpVtbl = &MXNamespaceManagerVtbl; This->IVBMXNamespaceManager_iface.lpVtbl = &VBMXNamespaceManagerVtbl; This->ref = 1; init_dispex(&This->dispex, (IUnknown*)&This->IVBMXNamespaceManager_iface, &namespacemanager_dispex); list_init(&This->ctxts); ctxt = alloc_ns_context(); if (!ctxt) { heap_free(This); return E_OUTOFMEMORY; } list_add_head(&This->ctxts, &ctxt->entry); This->override = VARIANT_TRUE; *obj = &This->IMXNamespaceManager_iface; TRACE("returning iface %p\n", *obj); return S_OK; }