xref: /reactos/dll/win32/msxml3/xmlelem.c (revision 8a978a17)
1 /*
2  * XML Element implementation
3  *
4  * Copyright 2007 James Hawkins
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #define COBJMACROS
22 
23 #include "config.h"
24 
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 #endif
30 
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "msxml6.h"
36 #include "ocidl.h"
37 
38 #include "wine/debug.h"
39 
40 #include "msxml_private.h"
41 
42 #ifdef HAVE_LIBXML2
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
45 
46 static HRESULT XMLElementCollection_create( xmlNodePtr node, LPVOID *ppObj );
47 
48 /**********************************************************************
49  * IXMLElement
50  */
51 typedef struct _xmlelem
52 {
53     IXMLElement IXMLElement_iface;
54     LONG ref;
55     xmlNodePtr node;
56     BOOL own;
57 } xmlelem;
58 
59 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
60 {
61     return CONTAINING_RECORD(iface, xmlelem, IXMLElement_iface);
62 }
63 
64 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
65 {
66     xmlelem *This = impl_from_IXMLElement(iface);
67 
68     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
69 
70     if (IsEqualGUID(riid, &IID_IUnknown)  ||
71         IsEqualGUID(riid, &IID_IDispatch) ||
72         IsEqualGUID(riid, &IID_IXMLElement))
73     {
74         *ppvObject = iface;
75     }
76     else
77     {
78         FIXME("interface %s not implemented\n", debugstr_guid(riid));
79         *ppvObject = NULL;
80         return E_NOINTERFACE;
81     }
82 
83     IXMLElement_AddRef(iface);
84 
85     return S_OK;
86 }
87 
88 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
89 {
90     xmlelem *This = impl_from_IXMLElement(iface);
91     TRACE("%p\n", This);
92     return InterlockedIncrement(&This->ref);
93 }
94 
95 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
96 {
97     xmlelem *This = impl_from_IXMLElement(iface);
98     LONG ref;
99 
100     TRACE("%p\n", This);
101 
102     ref = InterlockedDecrement(&This->ref);
103     if (ref == 0)
104     {
105         if (This->own) xmlFreeNode(This->node);
106         heap_free(This);
107     }
108 
109     return ref;
110 }
111 
112 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
113 {
114     xmlelem *This = impl_from_IXMLElement(iface);
115 
116     TRACE("(%p)->(%p)\n", This, pctinfo);
117 
118     *pctinfo = 1;
119 
120     return S_OK;
121 }
122 
123 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
124                                           LCID lcid, ITypeInfo** ppTInfo)
125 {
126     xmlelem *This = impl_from_IXMLElement(iface);
127     HRESULT hr;
128 
129     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
130 
131     hr = get_typeinfo(IXMLElement_tid, ppTInfo);
132 
133     return hr;
134 }
135 
136 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
137                                             LPOLESTR* rgszNames, UINT cNames,
138                                             LCID lcid, DISPID* rgDispId)
139 {
140     xmlelem *This = impl_from_IXMLElement(iface);
141     ITypeInfo *typeinfo;
142     HRESULT hr;
143 
144     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
145           lcid, rgDispId);
146 
147     if(!rgszNames || cNames == 0 || !rgDispId)
148         return E_INVALIDARG;
149 
150     hr = get_typeinfo(IXMLElement_tid, &typeinfo);
151     if(SUCCEEDED(hr))
152     {
153         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
154         ITypeInfo_Release(typeinfo);
155     }
156 
157     return hr;
158 }
159 
160 static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
161                                      REFIID riid, LCID lcid, WORD wFlags,
162                                      DISPPARAMS* pDispParams, VARIANT* pVarResult,
163                                      EXCEPINFO* pExcepInfo, UINT* puArgErr)
164 {
165     xmlelem *This = impl_from_IXMLElement(iface);
166     ITypeInfo *typeinfo;
167     HRESULT hr;
168 
169     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
170           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
171 
172     hr = get_typeinfo(IXMLElement_tid, &typeinfo);
173     if(SUCCEEDED(hr))
174     {
175         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLElement_iface, dispIdMember, wFlags, pDispParams,
176                 pVarResult, pExcepInfo, puArgErr);
177         ITypeInfo_Release(typeinfo);
178     }
179 
180     return hr;
181 }
182 
183 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
184 {
185     xmlelem *This = impl_from_IXMLElement(iface);
186 
187     TRACE("(%p)->(%p)\n", This, p);
188 
189     if (!p)
190         return E_INVALIDARG;
191 
192     if (*This->node->name) {
193         *p = bstr_from_xmlChar(This->node->name);
194         CharUpperBuffW(*p, SysStringLen(*p));
195     }else {
196         *p = NULL;
197     }
198 
199     TRACE("returning %s\n", debugstr_w(*p));
200 
201     return S_OK;
202 }
203 
204 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
205 {
206     xmlelem *This = impl_from_IXMLElement(iface);
207 
208     FIXME("(%p)->(%s): stub\n", This, debugstr_w(p));
209 
210     if (!p)
211         return E_INVALIDARG;
212 
213     return E_NOTIMPL;
214 }
215 
216 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
217 {
218     xmlelem *This = impl_from_IXMLElement(iface);
219 
220     TRACE("(%p)->(%p)\n", This, parent);
221 
222     if (!parent)
223         return E_INVALIDARG;
224 
225     *parent = NULL;
226 
227     if (!This->node->parent)
228         return S_FALSE;
229 
230     return XMLElement_create(This->node->parent, (LPVOID *)parent, FALSE);
231 }
232 
233 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
234                                             VARIANT PropertyValue)
235 {
236     xmlelem *This = impl_from_IXMLElement(iface);
237     xmlChar *name, *value;
238     xmlAttrPtr attr;
239 
240     TRACE("(%p)->(%s %s)\n", This, debugstr_w(strPropertyName), debugstr_variant(&PropertyValue));
241 
242     if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
243         return E_INVALIDARG;
244 
245     name = xmlchar_from_wchar(strPropertyName);
246     value = xmlchar_from_wchar(V_BSTR(&PropertyValue));
247     attr = xmlSetProp(This->node, name, value);
248 
249     heap_free(name);
250     heap_free(value);
251     return (attr) ? S_OK : S_FALSE;
252 }
253 
254 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name,
255     VARIANT *value)
256 {
257     static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 };
258     xmlelem *This = impl_from_IXMLElement(iface);
259     xmlChar *val = NULL;
260 
261     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(name), value);
262 
263     if (!value)
264         return E_INVALIDARG;
265 
266     VariantInit(value);
267     V_BSTR(value) = NULL;
268 
269     if (!name)
270         return E_INVALIDARG;
271 
272     /* case for xml:lang attribute */
273     if (!lstrcmpiW(name, xmllangW))
274     {
275         xmlNsPtr ns;
276         ns = xmlSearchNs(This->node->doc, This->node, (xmlChar*)"xml");
277         val = xmlGetNsProp(This->node, (xmlChar*)"lang", ns->href);
278     }
279     else
280     {
281         xmlAttrPtr attr;
282         xmlChar *xml_name;
283 
284         xml_name = xmlchar_from_wchar(name);
285         attr = This->node->properties;
286         while (attr)
287         {
288             BSTR attr_name;
289 
290             attr_name = bstr_from_xmlChar(attr->name);
291             if (!lstrcmpiW(name, attr_name))
292             {
293                 val = xmlNodeListGetString(attr->doc, attr->children, 1);
294                 SysFreeString(attr_name);
295                 break;
296             }
297 
298             attr = attr->next;
299             SysFreeString(attr_name);
300         }
301 
302         heap_free(xml_name);
303     }
304 
305     if (val)
306     {
307         V_VT(value) = VT_BSTR;
308         V_BSTR(value) = bstr_from_xmlChar(val);
309     }
310 
311     xmlFree(val);
312     TRACE("returning %s\n", debugstr_w(V_BSTR(value)));
313     return (val) ? S_OK : S_FALSE;
314 }
315 
316 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
317 {
318     xmlelem *This = impl_from_IXMLElement(iface);
319     xmlChar *name;
320     xmlAttrPtr attr;
321     int res;
322     HRESULT hr = S_FALSE;
323 
324     TRACE("(%p)->(%s)\n", This, debugstr_w(strPropertyName));
325 
326     if (!strPropertyName)
327         return E_INVALIDARG;
328 
329     name = xmlchar_from_wchar(strPropertyName);
330     attr = xmlHasProp(This->node, name);
331     if (!attr)
332         goto done;
333 
334     res = xmlRemoveProp(attr);
335 
336     if (res == 0)
337         hr = S_OK;
338 
339 done:
340     heap_free(name);
341     return hr;
342 }
343 
344 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
345 {
346     xmlelem *This = impl_from_IXMLElement(iface);
347 
348     TRACE("(%p)->(%p)\n", This, p);
349 
350     if (!p)
351         return E_INVALIDARG;
352 
353     return XMLElementCollection_create(This->node, (LPVOID *)p);
354 }
355 
356 static LONG type_libxml_to_msxml(xmlElementType type)
357 {
358     switch (type)
359     {
360         case XML_ELEMENT_NODE:
361             return XMLELEMTYPE_ELEMENT;
362         case XML_TEXT_NODE:
363             return XMLELEMTYPE_TEXT;
364         case XML_COMMENT_NODE:
365             return XMLELEMTYPE_COMMENT;
366         case XML_DOCUMENT_NODE:
367             return XMLELEMTYPE_DOCUMENT;
368         case XML_DTD_NODE:
369             return XMLELEMTYPE_DTD;
370         case XML_PI_NODE:
371             return XMLELEMTYPE_PI;
372         default:
373             break;
374     }
375 
376     return XMLELEMTYPE_OTHER;
377 }
378 
379 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
380 {
381     xmlelem *This = impl_from_IXMLElement(iface);
382 
383     TRACE("(%p)->(%p)\n", This, p);
384 
385     if (!p)
386         return E_INVALIDARG;
387 
388     *p = type_libxml_to_msxml(This->node->type);
389     TRACE("returning %d\n", *p);
390     return S_OK;
391 }
392 
393 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
394 {
395     xmlelem *This = impl_from_IXMLElement(iface);
396     xmlChar *content;
397 
398     TRACE("(%p)->(%p)\n", This, p);
399 
400     if (!p)
401         return E_INVALIDARG;
402 
403     content = xmlNodeGetContent(This->node);
404     *p = bstr_from_xmlChar(content);
405     TRACE("returning %s\n", debugstr_w(*p));
406 
407     xmlFree(content);
408     return S_OK;
409 }
410 
411 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
412 {
413     xmlelem *This = impl_from_IXMLElement(iface);
414     xmlChar *content;
415 
416     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
417 
418     /* FIXME: test which types can be used */
419     if (This->node->type == XML_ELEMENT_NODE)
420         return E_NOTIMPL;
421 
422     content = xmlchar_from_wchar(p);
423     xmlNodeSetContent(This->node, content);
424 
425     heap_free(content);
426 
427     return S_OK;
428 }
429 
430 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
431                                        LONG lIndex, LONG lreserved)
432 {
433     xmlelem *This = impl_from_IXMLElement(iface);
434     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
435     xmlNodePtr child;
436 
437     TRACE("(%p)->(%p %d %d)\n", This, pChildElem, lIndex, lreserved);
438 
439     if (lIndex == 0)
440         child = xmlAddChild(This->node, childElem->node);
441     else
442         child = xmlAddNextSibling(This->node, childElem->node->last);
443 
444     /* parent is responsible for child data */
445     if (child) childElem->own = FALSE;
446 
447     return (child) ? S_OK : S_FALSE;
448 }
449 
450 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
451 {
452     xmlelem *This = impl_from_IXMLElement(iface);
453     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
454 
455     TRACE("(%p)->(%p)\n", This, childElem);
456 
457     if (!pChildElem)
458         return E_INVALIDARG;
459 
460     /* only supported for This is childElem parent case */
461     if (This->node != childElem->node->parent)
462         return E_INVALIDARG;
463 
464     xmlUnlinkNode(childElem->node);
465     /* standalone element now */
466     childElem->own = TRUE;
467 
468     return S_OK;
469 }
470 
471 static const struct IXMLElementVtbl xmlelem_vtbl =
472 {
473     xmlelem_QueryInterface,
474     xmlelem_AddRef,
475     xmlelem_Release,
476     xmlelem_GetTypeInfoCount,
477     xmlelem_GetTypeInfo,
478     xmlelem_GetIDsOfNames,
479     xmlelem_Invoke,
480     xmlelem_get_tagName,
481     xmlelem_put_tagName,
482     xmlelem_get_parent,
483     xmlelem_setAttribute,
484     xmlelem_getAttribute,
485     xmlelem_removeAttribute,
486     xmlelem_get_children,
487     xmlelem_get_type,
488     xmlelem_get_text,
489     xmlelem_put_text,
490     xmlelem_addChild,
491     xmlelem_removeChild
492 };
493 
494 HRESULT XMLElement_create(xmlNodePtr node, LPVOID *ppObj, BOOL own)
495 {
496     xmlelem *elem;
497 
498     TRACE("(%p)\n", ppObj);
499 
500     if (!ppObj)
501         return E_INVALIDARG;
502 
503     *ppObj = NULL;
504 
505     elem = heap_alloc(sizeof (*elem));
506     if(!elem)
507         return E_OUTOFMEMORY;
508 
509     elem->IXMLElement_iface.lpVtbl = &xmlelem_vtbl;
510     elem->ref = 1;
511     elem->node = node;
512     elem->own  = own;
513 
514     *ppObj = &elem->IXMLElement_iface;
515 
516     TRACE("returning iface %p\n", *ppObj);
517     return S_OK;
518 }
519 
520 /************************************************************************
521  * IXMLElementCollection
522  */
523 typedef struct _xmlelem_collection
524 {
525     IXMLElementCollection IXMLElementCollection_iface;
526     IEnumVARIANT IEnumVARIANT_iface;
527     LONG ref;
528     LONG length;
529     xmlNodePtr node;
530 
531     /* IEnumVARIANT members */
532     xmlNodePtr current;
533 } xmlelem_collection;
534 
535 static inline LONG xmlelem_collection_updatelength(xmlelem_collection *collection)
536 {
537     xmlNodePtr ptr = collection->node->children;
538 
539     collection->length = 0;
540     while (ptr)
541     {
542         collection->length++;
543         ptr = ptr->next;
544     }
545     return collection->length;
546 }
547 
548 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
549 {
550     return CONTAINING_RECORD(iface, xmlelem_collection, IXMLElementCollection_iface);
551 }
552 
553 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
554 {
555     return CONTAINING_RECORD(iface, xmlelem_collection, IEnumVARIANT_iface);
556 }
557 
558 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
559 {
560     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
561 
562     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
563 
564     if (IsEqualGUID(riid, &IID_IUnknown) ||
565         IsEqualGUID(riid, &IID_IXMLElementCollection))
566     {
567         *ppvObject = iface;
568     }
569     else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
570     {
571         *ppvObject = &This->IEnumVARIANT_iface;
572     }
573     else
574     {
575         FIXME("interface %s not implemented\n", debugstr_guid(riid));
576         *ppvObject = NULL;
577         return E_NOINTERFACE;
578     }
579 
580     IXMLElementCollection_AddRef(iface);
581 
582     return S_OK;
583 }
584 
585 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
586 {
587     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
588     TRACE("(%p)\n", This);
589     return InterlockedIncrement(&This->ref);
590 }
591 
592 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
593 {
594     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
595     LONG ref;
596 
597     TRACE("(%p)\n", This);
598 
599     ref = InterlockedDecrement(&This->ref);
600     if (ref == 0)
601     {
602         heap_free(This);
603     }
604 
605     return ref;
606 }
607 
608 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
609 {
610     FIXME("\n");
611     return E_NOTIMPL;
612 }
613 
614 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
615                                                      LCID lcid, ITypeInfo** ppTInfo)
616 {
617     FIXME("\n");
618     return E_NOTIMPL;
619 }
620 
621 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
622                                                        LPOLESTR* rgszNames, UINT cNames,
623                                                        LCID lcid, DISPID* rgDispId)
624 {
625     FIXME("\n");
626     return E_NOTIMPL;
627 }
628 
629 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
630                                                 REFIID riid, LCID lcid, WORD wFlags,
631                                                 DISPPARAMS* pDispParams, VARIANT* pVarResult,
632                                                 EXCEPINFO* pExcepInfo, UINT* puArgErr)
633 {
634     FIXME("\n");
635     return E_NOTIMPL;
636 }
637 
638 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
639 {
640     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
641     TRACE("(%p)->(%d)\n", This, v);
642     return E_FAIL;
643 }
644 
645 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
646 {
647     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
648 
649     TRACE("(%p)->(%p)\n", This, p);
650 
651     if (!p)
652         return E_INVALIDARG;
653 
654     *p = xmlelem_collection_updatelength(This);
655     return S_OK;
656 }
657 
658 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
659 {
660     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
661 
662     TRACE("(%p)->(%p)\n", This, ppUnk);
663 
664     if (!ppUnk)
665         return E_INVALIDARG;
666 
667     IXMLElementCollection_AddRef(iface);
668     *ppUnk = (IUnknown *)&This->IEnumVARIANT_iface;
669     return S_OK;
670 }
671 
672 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
673                                               VARIANT var2, IDispatch **ppDisp)
674 {
675     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
676     xmlNodePtr ptr = This->node->children;
677     int index, i;
678 
679     TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&var1), debugstr_variant(&var2), ppDisp);
680 
681     if (!ppDisp)
682         return E_INVALIDARG;
683 
684     *ppDisp = NULL;
685 
686     index = V_I4(&var1);
687     if (index < 0)
688         return E_INVALIDARG;
689 
690     xmlelem_collection_updatelength(This);
691     if (index >= This->length)
692         return E_FAIL;
693 
694     for (i = 0; i < index; i++)
695         ptr = ptr->next;
696 
697     return XMLElement_create(ptr, (LPVOID *)ppDisp, FALSE);
698 }
699 
700 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
701 {
702     xmlelem_collection_QueryInterface,
703     xmlelem_collection_AddRef,
704     xmlelem_collection_Release,
705     xmlelem_collection_GetTypeInfoCount,
706     xmlelem_collection_GetTypeInfo,
707     xmlelem_collection_GetIDsOfNames,
708     xmlelem_collection_Invoke,
709     xmlelem_collection_put_length,
710     xmlelem_collection_get_length,
711     xmlelem_collection_get__newEnum,
712     xmlelem_collection_item
713 };
714 
715 /************************************************************************
716  * xmlelem_collection implementation of IEnumVARIANT.
717  */
718 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
719     IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
720 {
721     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
722 
723     TRACE("(%p)->(%s %p)\n", this, debugstr_guid(riid), ppvObj);
724 
725     if (IsEqualGUID(riid, &IID_IUnknown) ||
726         IsEqualGUID(riid, &IID_IEnumVARIANT))
727     {
728         *ppvObj = iface;
729         IEnumVARIANT_AddRef(iface);
730         return S_OK;
731     }
732 
733     FIXME("interface %s not implemented\n", debugstr_guid(riid));
734     *ppvObj = NULL;
735     return E_NOINTERFACE;
736 }
737 
738 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
739     IEnumVARIANT *iface)
740 {
741     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
742     return IXMLElementCollection_AddRef(&this->IXMLElementCollection_iface);
743 }
744 
745 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
746     IEnumVARIANT *iface)
747 {
748     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
749     return IXMLElementCollection_Release(&this->IXMLElementCollection_iface);
750 }
751 
752 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
753     IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *fetched)
754 {
755     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
756     xmlNodePtr ptr = This->current;
757 
758     TRACE("(%p)->(%d %p %p)\n", This, celt, rgVar, fetched);
759 
760     if (!rgVar)
761         return E_INVALIDARG;
762 
763     /* FIXME: handle celt */
764     if (fetched)
765         *fetched = 1;
766 
767     if (This->current)
768         This->current = This->current->next;
769     else
770     {
771         V_VT(rgVar) = VT_EMPTY;
772         if (fetched) *fetched = 0;
773         return S_FALSE;
774     }
775 
776     V_VT(rgVar) = VT_DISPATCH;
777     return XMLElement_create(ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE);
778 }
779 
780 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
781     IEnumVARIANT *iface, ULONG celt)
782 {
783     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
784     FIXME("(%p)->(%d): stub\n", This, celt);
785     return E_NOTIMPL;
786 }
787 
788 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
789     IEnumVARIANT *iface)
790 {
791     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
792     TRACE("(%p)\n", This);
793     This->current = This->node->children;
794     return S_OK;
795 }
796 
797 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
798     IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
799 {
800     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
801     FIXME("(%p)->(%p): stub\n", This, ppEnum);
802     return E_NOTIMPL;
803 }
804 
805 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
806 {
807     xmlelem_collection_IEnumVARIANT_QueryInterface,
808     xmlelem_collection_IEnumVARIANT_AddRef,
809     xmlelem_collection_IEnumVARIANT_Release,
810     xmlelem_collection_IEnumVARIANT_Next,
811     xmlelem_collection_IEnumVARIANT_Skip,
812     xmlelem_collection_IEnumVARIANT_Reset,
813     xmlelem_collection_IEnumVARIANT_Clone
814 };
815 
816 static HRESULT XMLElementCollection_create(xmlNodePtr node, LPVOID *ppObj)
817 {
818     xmlelem_collection *collection;
819 
820     TRACE("(%p)\n", ppObj);
821 
822     *ppObj = NULL;
823 
824     if (!node->children)
825         return S_FALSE;
826 
827     collection = heap_alloc(sizeof (*collection));
828     if(!collection)
829         return E_OUTOFMEMORY;
830 
831     collection->IXMLElementCollection_iface.lpVtbl = &xmlelem_collection_vtbl;
832     collection->IEnumVARIANT_iface.lpVtbl = &xmlelem_collection_IEnumVARIANTvtbl;
833     collection->ref = 1;
834     collection->length = 0;
835     collection->node = node;
836     collection->current = node->children;
837     xmlelem_collection_updatelength(collection);
838 
839     *ppObj = &collection->IXMLElementCollection_iface;
840 
841     TRACE("returning iface %p\n", *ppObj);
842     return S_OK;
843 }
844 
845 #endif
846