From 74f18d968ffb75a307932879810ecf87b4c9f915 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Thu, 24 May 2007 11:12:19 -0700 Subject: [PATCH] msxml3: Add initial implementation of IXMLElement and IXMLElementCollection. --- dlls/msxml3/Makefile.in | 3 +- dlls/msxml3/msxml_private.h | 2 + dlls/msxml3/xmlelem.c | 725 ++++++++++++++++++++++++++++++++++++ 3 files changed, 729 insertions(+), 1 deletion(-) create mode 100644 dlls/msxml3/xmlelem.c diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in index c888e236170..870034df9e8 100644 --- a/dlls/msxml3/Makefile.in +++ b/dlls/msxml3/Makefile.in @@ -24,7 +24,8 @@ C_SRCS = \ regsvr.c \ schema.c \ text.c \ - uuid.c + uuid.c \ + xmlelem.c RC_SRCS = version.rc diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 39aaa00eaf4..74f061a437d 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -63,5 +63,7 @@ extern IXMLDOMParseError *create_parseError( LONG code, BSTR url, BSTR reason, B LONG line, LONG linepos, LONG filepos ); extern HRESULT DOMDocument_create( IUnknown *pUnkOuter, LPVOID *ppObj ); extern HRESULT SchemaCache_create( IUnknown *pUnkOuter, LPVOID *ppObj ); +extern HRESULT XMLElement_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj ); +extern HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj ); #endif /* __MSXML_PRIVATE__ */ diff --git a/dlls/msxml3/xmlelem.c b/dlls/msxml3/xmlelem.c new file mode 100644 index 00000000000..b4fa1e7dafa --- /dev/null +++ b/dlls/msxml3/xmlelem.c @@ -0,0 +1,725 @@ +/* + * XML Element implementation + * + * Copyright 2007 James Hawkins + * + * 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 +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "msxml2.h" +#include "ocidl.h" + +#include "wine/debug.h" + +#include "msxml_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msxml); + +#ifdef HAVE_LIBXML2 + +/********************************************************************** + * IXMLElement + */ +typedef struct _xmlelem +{ + const IXMLElementVtbl *lpVtbl; + LONG ref; + xmlNodePtr node; +} xmlelem; + +static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface) +{ + return (xmlelem *)((char*)iface - FIELD_OFFSET(xmlelem, lpVtbl)); +} + +static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject) +{ + xmlelem *This = impl_from_IXMLElement(iface); + + TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IXMLElement)) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + IXMLElement_AddRef(iface); + + return S_OK; +} + +static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface) +{ + xmlelem *This = impl_from_IXMLElement(iface); + TRACE("%p\n", This); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI xmlelem_Release(IXMLElement *iface) +{ + xmlelem *This = impl_from_IXMLElement(iface); + LONG ref; + + TRACE("%p\n", This); + + ref = InterlockedDecrement(&This->ref); + if (ref == 0) + { + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo, + LCID lcid, ITypeInfo** ppTInfo) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid, + LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgDispId) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS* pDispParams, VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static inline BSTR str_dup_upper(BSTR str) +{ + INT len = (lstrlenW(str) + 1) * sizeof(WCHAR); + BSTR p = SysAllocStringLen(NULL, len); + if (p) + { + memcpy(p, str, len); + CharUpperW(p); + } + return p; +} + +static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p) +{ + xmlelem *This = impl_from_IXMLElement(iface); + BSTR temp; + + TRACE("(%p, %p)\n", iface, p); + + if (!p) + return E_INVALIDARG; + + temp = bstr_from_xmlChar(This->node->name); + *p = str_dup_upper(temp); + SysFreeString(temp); + + TRACE("returning %s\n", debugstr_w(*p)); + + return S_OK; +} + +static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p) +{ + FIXME("(%p, %p): stub\n", iface, p); + + if (!p) + return E_INVALIDARG; + + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent) +{ + xmlelem *This = impl_from_IXMLElement(iface); + + TRACE("(%p, %p)\n", iface, parent); + + if (!parent) + return E_INVALIDARG; + + *parent = NULL; + + if (!This->node->parent) + return S_FALSE; + + return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent); +} + +static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName, + VARIANT PropertyValue) +{ + xmlelem *This = impl_from_IXMLElement(iface); + xmlChar *name, *value; + xmlAttrPtr attr; + + TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName)); + + if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR) + return E_INVALIDARG; + + name = xmlChar_from_wchar(strPropertyName); + value = xmlChar_from_wchar(V_BSTR(&PropertyValue)); + attr = xmlSetProp(This->node, name, value); + + HeapFree(GetProcessHeap(), 0, name); + HeapFree(GetProcessHeap(), 0, value); + return (attr) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR strPropertyName, + VARIANT *PropertyValue) +{ + xmlelem *This = impl_from_IXMLElement(iface); + xmlChar *val = NULL, *name; + xmlAttrPtr ptr; + + TRACE("(%p, %s, %p)\n", iface, debugstr_w(strPropertyName), PropertyValue); + + if (!PropertyValue) + return E_INVALIDARG; + + VariantClear(PropertyValue); + V_BSTR(PropertyValue) = NULL; + + if (!strPropertyName) + return E_INVALIDARG; + + name = xmlChar_from_wchar(strPropertyName); + ptr = This->node->properties; + while (ptr) + { + if (!lstrcmpiA((LPSTR)name, (LPSTR)ptr->name)) + { + val = xmlNodeListGetString(ptr->doc, ptr->children, 1); + break; + } + + ptr = ptr->next; + } + + if (val) + { + V_VT(PropertyValue) = VT_BSTR; + V_BSTR(PropertyValue) = bstr_from_xmlChar(val); + } + + HeapFree(GetProcessHeap(), 0, name); + xmlFree(val); + TRACE("returning %s\n", debugstr_w(V_BSTR(PropertyValue))); + return (val) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName) +{ + xmlelem *This = impl_from_IXMLElement(iface); + xmlChar *name; + xmlAttrPtr attr; + int res; + HRESULT hr = S_FALSE; + + TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName)); + + if (!strPropertyName) + return E_INVALIDARG; + + name = xmlChar_from_wchar(strPropertyName); + attr = xmlHasProp(This->node, name); + if (!attr) + goto done; + + res = xmlRemoveProp(attr); + + if (res == 0) + hr = S_OK; + +done: + HeapFree(GetProcessHeap(), 0, name); + return hr; +} + +static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p) +{ + xmlelem *This = impl_from_IXMLElement(iface); + + TRACE("(%p, %p)\n", iface, p); + + if (!p) + return E_INVALIDARG; + + return XMLElementCollection_create((IUnknown *)iface, This->node->children, (LPVOID *)p); +} + +static long type_libxml_to_msxml(xmlElementType type) +{ + switch (type) + { + case XML_ELEMENT_NODE: + return XMLELEMTYPE_ELEMENT; + case XML_TEXT_NODE: + return XMLELEMTYPE_TEXT; + case XML_COMMENT_NODE: + return XMLELEMTYPE_COMMENT; + case XML_DOCUMENT_NODE: + return XMLELEMTYPE_DOCUMENT; + case XML_DTD_NODE: + return XMLELEMTYPE_DTD; + case XML_PI_NODE: + return XMLELEMTYPE_PI; + default: + break; + } + + return XMLELEMTYPE_OTHER; +} + +static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, long *p) +{ + xmlelem *This = impl_from_IXMLElement(iface); + + TRACE("(%p, %p)\n", This, p); + + if (!p) + return E_INVALIDARG; + + *p = type_libxml_to_msxml(This->node->type); + TRACE("returning %ld\n", *p); + return S_OK; +} + +static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p) +{ + xmlelem *This = impl_from_IXMLElement(iface); + xmlChar *content; + + TRACE("(%p, %p)\n", iface, p); + + if (!p) + return E_INVALIDARG; + + content = xmlNodeGetContent(This->node); + *p = bstr_from_xmlChar(content); + TRACE("returning %s\n", debugstr_w(*p)); + return S_OK; +} + +static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p) +{ + xmlelem *This = impl_from_IXMLElement(iface); + xmlChar *content; + + TRACE("(%p, %s)\n", iface, debugstr_w(p)); + + /* FIXME: test which types can be used */ + if (This->node->type == XML_ELEMENT_NODE) + return E_NOTIMPL; + + content = xmlChar_from_wchar(p); + xmlNodeSetContent(This->node, content); + return S_OK; +} + +static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem, + long lIndex, long lreserved) +{ + xmlelem *This = impl_from_IXMLElement(iface); + xmlelem *childElem = impl_from_IXMLElement(pChildElem); + xmlNodePtr child; + + TRACE("(%p, %p, %ld, %ld)\n", iface, pChildElem, lIndex, lreserved); + + if (lIndex == 0) + child = xmlAddChild(This->node, childElem->node); + else + child = xmlAddNextSibling(This->node, childElem->node->last); + + return (child) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem) +{ + FIXME("(%p, %p): stub\n", iface, pChildElem); + return E_NOTIMPL; +} + +static const struct IXMLElementVtbl xmlelem_vtbl = +{ + xmlelem_QueryInterface, + xmlelem_AddRef, + xmlelem_Release, + xmlelem_GetTypeInfoCount, + xmlelem_GetTypeInfo, + xmlelem_GetIDsOfNames, + xmlelem_Invoke, + xmlelem_get_tagName, + xmlelem_put_tagName, + xmlelem_get_parent, + xmlelem_setAttribute, + xmlelem_getAttribute, + xmlelem_removeAttribute, + xmlelem_get_children, + xmlelem_get_type, + xmlelem_get_text, + xmlelem_put_text, + xmlelem_addChild, + xmlelem_removeChild +}; + +HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj) +{ + xmlelem *elem; + + TRACE("(%p,%p)\n", pUnkOuter, ppObj); + + if (!ppObj) + return E_INVALIDARG; + + *ppObj = NULL; + + elem = HeapAlloc(GetProcessHeap(), 0, sizeof (*elem)); + if(!elem) + return E_OUTOFMEMORY; + + elem->lpVtbl = &xmlelem_vtbl; + elem->ref = 1; + elem->node = node; + + *ppObj = &elem->lpVtbl; + + TRACE("returning iface %p\n", *ppObj); + return S_OK; +} + +/************************************************************************ + * IXMLElementCollection + */ +typedef struct _xmlelem_collection +{ + const IXMLElementCollectionVtbl *lpVtbl; + const IEnumVARIANTVtbl *lpvtblIEnumVARIANT; + LONG ref; + LONG length; + xmlNodePtr node; + + /* IEnumVARIANT members */ + xmlNodePtr current; +} xmlelem_collection; + +static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface) +{ + return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpVtbl)); +} + +static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface) +{ + return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpvtblIEnumVARIANT)); +} + +static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject) +{ + xmlelem_collection *This = impl_from_IXMLElementCollection(iface); + + TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IXMLElementCollection)) + { + *ppvObject = iface; + } + else if (IsEqualGUID(riid, &IID_IEnumVARIANT)) + { + *ppvObject = (IEnumVARIANT *)&(This->lpvtblIEnumVARIANT); + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + IXMLElementCollection_AddRef(iface); + + return S_OK; +} + +static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface) +{ + xmlelem_collection *This = impl_from_IXMLElementCollection(iface); + TRACE("%p\n", This); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface) +{ + xmlelem_collection *This = impl_from_IXMLElementCollection(iface); + LONG ref; + + TRACE("%p\n", This); + + ref = InterlockedDecrement(&This->ref); + if (ref == 0) + { + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo, + LCID lcid, ITypeInfo** ppTInfo) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid, + LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgDispId) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS* pDispParams, VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, long v) +{ + TRACE("(%p, %ld)\n", iface, v); + return E_FAIL; +} + +static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, long *p) +{ + xmlelem_collection *This = impl_from_IXMLElementCollection(iface); + + TRACE("(%p, %p)\n", iface, p); + + if (!p) + return E_INVALIDARG; + + *p = This->length; + return S_OK; +} + +static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk) +{ + xmlelem_collection *This = impl_from_IXMLElementCollection(iface); + + TRACE("(%p, %p)\n", iface, ppUnk); + + if (!ppUnk) + return E_INVALIDARG; + + *ppUnk = (IUnknown *)This; + IUnknown_AddRef(*ppUnk); + return S_OK; +} + +static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1, + VARIANT var2, IDispatch **ppDisp) +{ + xmlelem_collection *This = impl_from_IXMLElementCollection(iface); + xmlNodePtr ptr = This->node; + int index, i; + + TRACE("(%p, %p)\n", iface, ppDisp); + + if (!ppDisp) + return E_INVALIDARG; + + *ppDisp = NULL; + + index = V_I4(&var1); + if (index < 0) + return E_INVALIDARG; + if (index >= This->length) + return E_FAIL; + + for (i = 0; i < index; i++) + ptr = ptr->next; + + return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp); +} + +static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl = +{ + xmlelem_collection_QueryInterface, + xmlelem_collection_AddRef, + xmlelem_collection_Release, + xmlelem_collection_GetTypeInfoCount, + xmlelem_collection_GetTypeInfo, + xmlelem_collection_GetIDsOfNames, + xmlelem_collection_Invoke, + xmlelem_collection_put_length, + xmlelem_collection_get_length, + xmlelem_collection_get__newEnum, + xmlelem_collection_item +}; + +/************************************************************************ + * xmlelem_collection implementation of IEnumVARIANT. + */ +static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface( + IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj) +{ + xmlelem_collection *this = impl_from_IEnumVARIANT(iface); + return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj); +} + +static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef( + IEnumVARIANT *iface) +{ + xmlelem_collection *this = impl_from_IEnumVARIANT(iface); + return IXMLDocument_AddRef((IXMLDocument *)this); +} + +static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release( + IEnumVARIANT *iface) +{ + xmlelem_collection *this = impl_from_IEnumVARIANT(iface); + return IXMLDocument_Release((IXMLDocument *)this); +} + +static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next( + IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + xmlelem_collection *This = impl_from_IEnumVARIANT(iface); + xmlNodePtr ptr = This->current; + + TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, pCeltFetched); + + if (!rgVar) + return E_INVALIDARG; + + /* FIXME: handle celt */ + if (pCeltFetched) + *pCeltFetched = 1; + + This->current = This->current->next; + + V_VT(rgVar) = VT_DISPATCH; + return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar)); +} + +static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip( + IEnumVARIANT *iface, ULONG celt) +{ + FIXME("(%p, %d): stub\n", iface, celt); + return E_NOTIMPL; +} + +static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset( + IEnumVARIANT *iface) +{ + xmlelem_collection *This = impl_from_IEnumVARIANT(iface); + This->current = This->node; + return S_OK; +} + +static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone( + IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + FIXME("(%p, %p): stub\n", iface, ppEnum); + return E_NOTIMPL; +} + +static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl = +{ + xmlelem_collection_IEnumVARIANT_QueryInterface, + xmlelem_collection_IEnumVARIANT_AddRef, + xmlelem_collection_IEnumVARIANT_Release, + xmlelem_collection_IEnumVARIANT_Next, + xmlelem_collection_IEnumVARIANT_Skip, + xmlelem_collection_IEnumVARIANT_Reset, + xmlelem_collection_IEnumVARIANT_Clone +}; + +HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj) +{ + xmlelem_collection *collection; + xmlNodePtr ptr; + + TRACE("(%p,%p)\n", pUnkOuter, ppObj); + + *ppObj = NULL; + + if (!node) + return S_FALSE; + + collection = HeapAlloc(GetProcessHeap(), 0, sizeof (*collection)); + if(!collection) + return E_OUTOFMEMORY; + + collection->lpVtbl = &xmlelem_collection_vtbl; + collection->lpvtblIEnumVARIANT = &xmlelem_collection_IEnumVARIANTvtbl; + collection->ref = 1; + collection->length = 0; + collection->node = node; + collection->current = node; + + ptr = node; + while (ptr) + { + collection->length++; + ptr = ptr->next; + } + + *ppObj = &collection->lpVtbl; + + TRACE("returning iface %p\n", *ppObj); + return S_OK; +} + +#endif