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