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