2 * XML Element implementation
4 * Copyright 2007 James Hawkins
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/debug.h"
35 #include "msxml_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
41 static HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
43 /**********************************************************************
46 typedef struct _xmlelem
48 IXMLElement IXMLElement_iface;
54 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
56 return CONTAINING_RECORD(iface, xmlelem, IXMLElement_iface);
59 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
61 xmlelem *This = impl_from_IXMLElement(iface);
63 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
65 if (IsEqualGUID(riid, &IID_IUnknown) ||
66 IsEqualGUID(riid, &IID_IXMLElement))
72 FIXME("interface %s not implemented\n", debugstr_guid(riid));
76 IXMLElement_AddRef(iface);
81 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
83 xmlelem *This = impl_from_IXMLElement(iface);
85 return InterlockedIncrement(&This->ref);
88 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
90 xmlelem *This = impl_from_IXMLElement(iface);
95 ref = InterlockedDecrement(&This->ref);
98 if (This->own) xmlFreeNode(This->node);
105 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
107 xmlelem *This = impl_from_IXMLElement(iface);
109 TRACE("(%p)->(%p)\n", This, pctinfo);
116 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
117 LCID lcid, ITypeInfo** ppTInfo)
119 xmlelem *This = impl_from_IXMLElement(iface);
122 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
124 hr = get_typeinfo(IXMLElement_tid, ppTInfo);
129 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
130 LPOLESTR* rgszNames, UINT cNames,
131 LCID lcid, DISPID* rgDispId)
133 xmlelem *This = impl_from_IXMLElement(iface);
137 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
140 if(!rgszNames || cNames == 0 || !rgDispId)
143 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
146 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
147 ITypeInfo_Release(typeinfo);
153 static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
154 REFIID riid, LCID lcid, WORD wFlags,
155 DISPPARAMS* pDispParams, VARIANT* pVarResult,
156 EXCEPINFO* pExcepInfo, UINT* puArgErr)
158 xmlelem *This = impl_from_IXMLElement(iface);
162 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
163 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
165 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
168 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLElement_iface, dispIdMember, wFlags, pDispParams,
169 pVarResult, pExcepInfo, puArgErr);
170 ITypeInfo_Release(typeinfo);
176 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
178 xmlelem *This = impl_from_IXMLElement(iface);
180 TRACE("(%p)->(%p)\n", This, p);
185 *p = bstr_from_xmlChar(This->node->name);
186 CharUpperBuffW(*p, SysStringLen(*p));
188 TRACE("returning %s\n", debugstr_w(*p));
193 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
195 xmlelem *This = impl_from_IXMLElement(iface);
197 FIXME("(%p)->(%s): stub\n", This, debugstr_w(p));
205 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
207 xmlelem *This = impl_from_IXMLElement(iface);
209 TRACE("(%p)->(%p)\n", This, parent);
216 if (!This->node->parent)
219 return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent, FALSE);
222 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
223 VARIANT PropertyValue)
225 xmlelem *This = impl_from_IXMLElement(iface);
226 xmlChar *name, *value;
229 TRACE("(%p)->(%s %s)\n", This, debugstr_w(strPropertyName), debugstr_variant(&PropertyValue));
231 if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
234 name = xmlChar_from_wchar(strPropertyName);
235 value = xmlChar_from_wchar(V_BSTR(&PropertyValue));
236 attr = xmlSetProp(This->node, name, value);
240 return (attr) ? S_OK : S_FALSE;
243 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name,
246 static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 };
247 xmlelem *This = impl_from_IXMLElement(iface);
250 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(name), value);
256 V_BSTR(value) = NULL;
261 /* case for xml:lang attribute */
262 if (!lstrcmpiW(name, xmllangW))
265 ns = xmlSearchNs(This->node->doc, This->node, (xmlChar*)"xml");
266 val = xmlGetNsProp(This->node, (xmlChar*)"lang", ns->href);
273 xml_name = xmlChar_from_wchar(name);
274 attr = This->node->properties;
279 attr_name = bstr_from_xmlChar(attr->name);
280 if (!lstrcmpiW(name, attr_name))
282 val = xmlNodeListGetString(attr->doc, attr->children, 1);
283 SysFreeString(attr_name);
288 SysFreeString(attr_name);
296 V_VT(value) = VT_BSTR;
297 V_BSTR(value) = bstr_from_xmlChar(val);
301 TRACE("returning %s\n", debugstr_w(V_BSTR(value)));
302 return (val) ? S_OK : S_FALSE;
305 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
307 xmlelem *This = impl_from_IXMLElement(iface);
311 HRESULT hr = S_FALSE;
313 TRACE("(%p)->(%s)\n", This, debugstr_w(strPropertyName));
315 if (!strPropertyName)
318 name = xmlChar_from_wchar(strPropertyName);
319 attr = xmlHasProp(This->node, name);
323 res = xmlRemoveProp(attr);
333 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
335 xmlelem *This = impl_from_IXMLElement(iface);
337 TRACE("(%p)->(%p)\n", This, p);
342 return XMLElementCollection_create((IUnknown *)iface, This->node, (LPVOID *)p);
345 static LONG type_libxml_to_msxml(xmlElementType type)
349 case XML_ELEMENT_NODE:
350 return XMLELEMTYPE_ELEMENT;
352 return XMLELEMTYPE_TEXT;
353 case XML_COMMENT_NODE:
354 return XMLELEMTYPE_COMMENT;
355 case XML_DOCUMENT_NODE:
356 return XMLELEMTYPE_DOCUMENT;
358 return XMLELEMTYPE_DTD;
360 return XMLELEMTYPE_PI;
365 return XMLELEMTYPE_OTHER;
368 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
370 xmlelem *This = impl_from_IXMLElement(iface);
372 TRACE("(%p)->(%p)\n", This, p);
377 *p = type_libxml_to_msxml(This->node->type);
378 TRACE("returning %d\n", *p);
382 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
384 xmlelem *This = impl_from_IXMLElement(iface);
387 TRACE("(%p)->(%p)\n", This, p);
392 content = xmlNodeGetContent(This->node);
393 *p = bstr_from_xmlChar(content);
394 TRACE("returning %s\n", debugstr_w(*p));
400 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
402 xmlelem *This = impl_from_IXMLElement(iface);
405 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
407 /* FIXME: test which types can be used */
408 if (This->node->type == XML_ELEMENT_NODE)
411 content = xmlChar_from_wchar(p);
412 xmlNodeSetContent(This->node, content);
419 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
420 LONG lIndex, LONG lreserved)
422 xmlelem *This = impl_from_IXMLElement(iface);
423 xmlelem *childElem = impl_from_IXMLElement(pChildElem);
426 TRACE("(%p)->(%p %d %d)\n", This, pChildElem, lIndex, lreserved);
429 child = xmlAddChild(This->node, childElem->node);
431 child = xmlAddNextSibling(This->node, childElem->node->last);
433 /* parent is responsible for child data */
434 if (child) childElem->own = FALSE;
436 return (child) ? S_OK : S_FALSE;
439 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
441 xmlelem *This = impl_from_IXMLElement(iface);
442 xmlelem *childElem = impl_from_IXMLElement(pChildElem);
444 TRACE("(%p)->(%p)\n", This, childElem);
449 /* only supported for This is childElem parent case */
450 if (This->node != childElem->node->parent)
453 xmlUnlinkNode(childElem->node);
454 /* standalone element now */
455 childElem->own = TRUE;
460 static const struct IXMLElementVtbl xmlelem_vtbl =
462 xmlelem_QueryInterface,
465 xmlelem_GetTypeInfoCount,
467 xmlelem_GetIDsOfNames,
472 xmlelem_setAttribute,
473 xmlelem_getAttribute,
474 xmlelem_removeAttribute,
475 xmlelem_get_children,
483 HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj, BOOL own)
487 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
494 elem = heap_alloc(sizeof (*elem));
496 return E_OUTOFMEMORY;
498 elem->IXMLElement_iface.lpVtbl = &xmlelem_vtbl;
503 *ppObj = &elem->IXMLElement_iface;
505 TRACE("returning iface %p\n", *ppObj);
509 /************************************************************************
510 * IXMLElementCollection
512 typedef struct _xmlelem_collection
514 IXMLElementCollection IXMLElementCollection_iface;
515 IEnumVARIANT IEnumVARIANT_iface;
520 /* IEnumVARIANT members */
522 } xmlelem_collection;
524 static inline LONG xmlelem_collection_updatelength(xmlelem_collection *collection)
526 xmlNodePtr ptr = collection->node->children;
528 collection->length = 0;
531 collection->length++;
534 return collection->length;
537 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
539 return CONTAINING_RECORD(iface, xmlelem_collection, IXMLElementCollection_iface);
542 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
544 return CONTAINING_RECORD(iface, xmlelem_collection, IEnumVARIANT_iface);
547 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
549 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
551 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
553 if (IsEqualGUID(riid, &IID_IUnknown) ||
554 IsEqualGUID(riid, &IID_IXMLElementCollection))
558 else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
560 *ppvObject = &This->IEnumVARIANT_iface;
564 FIXME("interface %s not implemented\n", debugstr_guid(riid));
565 return E_NOINTERFACE;
568 IXMLElementCollection_AddRef(iface);
573 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
575 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
576 TRACE("(%p)\n", This);
577 return InterlockedIncrement(&This->ref);
580 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
582 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
585 TRACE("(%p)\n", This);
587 ref = InterlockedDecrement(&This->ref);
596 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
602 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
603 LCID lcid, ITypeInfo** ppTInfo)
609 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
610 LPOLESTR* rgszNames, UINT cNames,
611 LCID lcid, DISPID* rgDispId)
617 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
618 REFIID riid, LCID lcid, WORD wFlags,
619 DISPPARAMS* pDispParams, VARIANT* pVarResult,
620 EXCEPINFO* pExcepInfo, UINT* puArgErr)
626 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
628 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
629 TRACE("(%p)->(%d)\n", This, v);
633 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
635 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
637 TRACE("(%p)->(%p)\n", This, p);
642 *p = xmlelem_collection_updatelength(This);
646 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
648 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
650 TRACE("(%p)->(%p)\n", This, ppUnk);
655 *ppUnk = (IUnknown *)This;
656 IUnknown_AddRef(*ppUnk);
660 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
661 VARIANT var2, IDispatch **ppDisp)
663 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
664 xmlNodePtr ptr = This->node->children;
667 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&var1), debugstr_variant(&var2), ppDisp);
678 xmlelem_collection_updatelength(This);
679 if (index >= This->length)
682 for (i = 0; i < index; i++)
685 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp, FALSE);
688 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
690 xmlelem_collection_QueryInterface,
691 xmlelem_collection_AddRef,
692 xmlelem_collection_Release,
693 xmlelem_collection_GetTypeInfoCount,
694 xmlelem_collection_GetTypeInfo,
695 xmlelem_collection_GetIDsOfNames,
696 xmlelem_collection_Invoke,
697 xmlelem_collection_put_length,
698 xmlelem_collection_get_length,
699 xmlelem_collection_get__newEnum,
700 xmlelem_collection_item
703 /************************************************************************
704 * xmlelem_collection implementation of IEnumVARIANT.
706 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
707 IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
709 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
710 return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
713 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
716 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
717 return IXMLDocument_AddRef((IXMLDocument *)this);
720 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
723 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
724 return IXMLDocument_Release((IXMLDocument *)this);
727 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
728 IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *fetched)
730 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
731 xmlNodePtr ptr = This->current;
733 TRACE("(%p)->(%d %p %p)\n", This, celt, rgVar, fetched);
738 /* FIXME: handle celt */
743 This->current = This->current->next;
746 V_VT(rgVar) = VT_EMPTY;
747 if (fetched) *fetched = 0;
751 V_VT(rgVar) = VT_DISPATCH;
752 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE);
755 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
756 IEnumVARIANT *iface, ULONG celt)
758 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
759 FIXME("(%p)->(%d): stub\n", This, celt);
763 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
766 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
767 TRACE("(%p)\n", This);
768 This->current = This->node->children;
772 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
773 IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
775 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
776 FIXME("(%p)->(%p): stub\n", This, ppEnum);
780 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
782 xmlelem_collection_IEnumVARIANT_QueryInterface,
783 xmlelem_collection_IEnumVARIANT_AddRef,
784 xmlelem_collection_IEnumVARIANT_Release,
785 xmlelem_collection_IEnumVARIANT_Next,
786 xmlelem_collection_IEnumVARIANT_Skip,
787 xmlelem_collection_IEnumVARIANT_Reset,
788 xmlelem_collection_IEnumVARIANT_Clone
791 static HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
793 xmlelem_collection *collection;
795 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
802 collection = heap_alloc(sizeof (*collection));
804 return E_OUTOFMEMORY;
806 collection->IXMLElementCollection_iface.lpVtbl = &xmlelem_collection_vtbl;
807 collection->IEnumVARIANT_iface.lpVtbl = &xmlelem_collection_IEnumVARIANTvtbl;
809 collection->length = 0;
810 collection->node = node;
811 collection->current = node->children;
812 xmlelem_collection_updatelength(collection);
814 *ppObj = &collection->IXMLElementCollection_iface;
816 TRACE("returning iface %p\n", *ppObj);