| /* |
| * 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 <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "ole2.h" |
| #include "msxml6.h" |
| #include "ocidl.h" |
| |
| #include "wine/debug.h" |
| |
| #include "msxml_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msxml); |
| |
| #ifdef HAVE_LIBXML2 |
| |
| static HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj ); |
| |
| /********************************************************************** |
| * IXMLElement |
| */ |
| typedef struct _xmlelem |
| { |
| const IXMLElementVtbl *lpVtbl; |
| LONG ref; |
| xmlNodePtr node; |
| BOOL own; |
| } 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) |
| { |
| if (This->own) xmlFreeNode(This->node); |
| heap_free(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo) |
| { |
| xmlelem *This = impl_from_IXMLElement(iface); |
| |
| TRACE("(%p)->(%p)\n", This, pctinfo); |
| |
| *pctinfo = 1; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo, |
| LCID lcid, ITypeInfo** ppTInfo) |
| { |
| xmlelem *This = impl_from_IXMLElement(iface); |
| HRESULT hr; |
| |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(IXMLElement_tid, ppTInfo); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid, |
| LPOLESTR* rgszNames, UINT cNames, |
| LCID lcid, DISPID* rgDispId) |
| { |
| xmlelem *This = impl_from_IXMLElement(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, |
| lcid, rgDispId); |
| |
| if(!rgszNames || cNames == 0 || !rgDispId) |
| return E_INVALIDARG; |
| |
| hr = get_typeinfo(IXMLElement_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember, |
| REFIID riid, LCID lcid, WORD wFlags, |
| DISPPARAMS* pDispParams, VARIANT* pVarResult, |
| EXCEPINFO* pExcepInfo, UINT* puArgErr) |
| { |
| xmlelem *This = impl_from_IXMLElement(iface); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IXMLElement_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams, |
| pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p) |
| { |
| xmlelem *This = impl_from_IXMLElement(iface); |
| |
| TRACE("(%p, %p)\n", iface, p); |
| |
| if (!p) |
| return E_INVALIDARG; |
| |
| *p = bstr_from_xmlChar(This->node->name); |
| CharUpperBuffW(*p, SysStringLen(*p)); |
| |
| 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, FALSE); |
| } |
| |
| 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); |
| |
| heap_free(name); |
| heap_free(value); |
| return (attr) ? S_OK : S_FALSE; |
| } |
| |
| static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name, |
| VARIANT *value) |
| { |
| static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 }; |
| xmlelem *This = impl_from_IXMLElement(iface); |
| xmlChar *val = NULL; |
| |
| TRACE("(%p, %s, %p)\n", iface, debugstr_w(name), value); |
| |
| if (!value) |
| return E_INVALIDARG; |
| |
| VariantInit(value); |
| V_BSTR(value) = NULL; |
| |
| if (!name) |
| return E_INVALIDARG; |
| |
| /* case for xml:lang attribute */ |
| if (!lstrcmpiW(name, xmllangW)) |
| { |
| xmlNsPtr ns; |
| ns = xmlSearchNs(This->node->doc, This->node, (xmlChar*)"xml"); |
| val = xmlGetNsProp(This->node, (xmlChar*)"lang", ns->href); |
| } |
| else |
| { |
| xmlAttrPtr attr; |
| xmlChar *xml_name; |
| |
| xml_name = xmlChar_from_wchar(name); |
| attr = This->node->properties; |
| while (attr) |
| { |
| BSTR attr_name; |
| |
| attr_name = bstr_from_xmlChar(attr->name); |
| if (!lstrcmpiW(name, attr_name)) |
| { |
| val = xmlNodeListGetString(attr->doc, attr->children, 1); |
| SysFreeString(attr_name); |
| break; |
| } |
| |
| attr = attr->next; |
| SysFreeString(attr_name); |
| } |
| |
| heap_free(xml_name); |
| } |
| |
| if (val) |
| { |
| V_VT(value) = VT_BSTR; |
| V_BSTR(value) = bstr_from_xmlChar(val); |
| } |
| |
| xmlFree(val); |
| TRACE("returning %s\n", debugstr_w(V_BSTR(value))); |
| 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: |
| heap_free(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, (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 %d\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)); |
| |
| xmlFree(content); |
| 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); |
| |
| heap_free(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, %d, %d)\n", iface, pChildElem, lIndex, lreserved); |
| |
| if (lIndex == 0) |
| child = xmlAddChild(This->node, childElem->node); |
| else |
| child = xmlAddNextSibling(This->node, childElem->node->last); |
| |
| /* parent is responsible for child data */ |
| if (child) childElem->own = FALSE; |
| |
| return (child) ? S_OK : S_FALSE; |
| } |
| |
| static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem) |
| { |
| xmlelem *This = impl_from_IXMLElement(iface); |
| xmlelem *childElem = impl_from_IXMLElement(pChildElem); |
| |
| TRACE("(%p, %p)\n", This, childElem); |
| |
| if (!pChildElem) |
| return E_INVALIDARG; |
| |
| /* only supported for This is childElem parent case */ |
| if (This->node != childElem->node->parent) |
| return E_INVALIDARG; |
| |
| xmlUnlinkNode(childElem->node); |
| /* standalone element now */ |
| childElem->own = TRUE; |
| |
| return S_OK; |
| } |
| |
| 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, BOOL own) |
| { |
| xmlelem *elem; |
| |
| TRACE("(%p,%p)\n", pUnkOuter, ppObj); |
| |
| if (!ppObj) |
| return E_INVALIDARG; |
| |
| *ppObj = NULL; |
| |
| elem = heap_alloc(sizeof (*elem)); |
| if(!elem) |
| return E_OUTOFMEMORY; |
| |
| elem->lpVtbl = &xmlelem_vtbl; |
| elem->ref = 1; |
| elem->node = node; |
| elem->own = own; |
| |
| *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 LONG xmlelem_collection_updatelength(xmlelem_collection *collection) |
| { |
| xmlNodePtr ptr = collection->node->children; |
| |
| collection->length = 0; |
| while (ptr) |
| { |
| collection->length++; |
| ptr = ptr->next; |
| } |
| return collection->length; |
| } |
| |
| 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 = &(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) |
| { |
| heap_free(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, %d)\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 = xmlelem_collection_updatelength(This); |
| 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->children; |
| 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; |
| |
| xmlelem_collection_updatelength(This); |
| if (index >= This->length) |
| return E_FAIL; |
| |
| for (i = 0; i < index; i++) |
| ptr = ptr->next; |
| |
| return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp, FALSE); |
| } |
| |
| 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 *fetched) |
| { |
| xmlelem_collection *This = impl_from_IEnumVARIANT(iface); |
| xmlNodePtr ptr = This->current; |
| |
| TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, fetched); |
| |
| if (!rgVar) |
| return E_INVALIDARG; |
| |
| /* FIXME: handle celt */ |
| if (fetched) |
| *fetched = 1; |
| |
| if (This->current) |
| This->current = This->current->next; |
| else |
| { |
| V_VT(rgVar) = VT_EMPTY; |
| if (fetched) *fetched = 0; |
| return S_FALSE; |
| } |
| |
| V_VT(rgVar) = VT_DISPATCH; |
| return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE); |
| } |
| |
| 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->children; |
| 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 |
| }; |
| |
| static HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj) |
| { |
| xmlelem_collection *collection; |
| |
| TRACE("(%p,%p)\n", pUnkOuter, ppObj); |
| |
| *ppObj = NULL; |
| |
| if (!node->children) |
| return S_FALSE; |
| |
| collection = heap_alloc(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->children; |
| xmlelem_collection_updatelength(collection); |
| |
| *ppObj = &collection->lpVtbl; |
| |
| TRACE("returning iface %p\n", *ppObj); |
| return S_OK; |
| } |
| |
| #endif |