xmlelem.c 21.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * 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 <stdarg.h>
24 25
#include <libxml/parser.h>
#include <libxml/xmlerror.h>
26

27 28 29 30
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
31
#include "msxml6.h"
32 33 34 35 36 37
#include "ocidl.h"

#include "wine/debug.h"

#include "msxml_private.h"

38 39
WINE_DEFAULT_DEBUG_CHANNEL(msxml);

40
static HRESULT XMLElementCollection_create( xmlNodePtr node, LPVOID *ppObj );
41

42 43 44 45 46
/**********************************************************************
 * IXMLElement
 */
typedef struct _xmlelem
{
47
    IXMLElement IXMLElement_iface;
48 49
    LONG ref;
    xmlNodePtr node;
50
    BOOL own;
51 52 53 54
} xmlelem;

static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
{
55
    return CONTAINING_RECORD(iface, xmlelem, IXMLElement_iface);
56 57 58 59 60 61
}

static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
{
    xmlelem *This = impl_from_IXMLElement(iface);

62
    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
63

64 65
    if (IsEqualGUID(riid, &IID_IUnknown)  ||
        IsEqualGUID(riid, &IID_IDispatch) ||
66 67 68 69 70 71 72
        IsEqualGUID(riid, &IID_IXMLElement))
    {
        *ppvObject = iface;
    }
    else
    {
        FIXME("interface %s not implemented\n", debugstr_guid(riid));
73
        *ppvObject = NULL;
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
        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)
    {
99
        if (This->own) xmlFreeNode(This->node);
100
        heap_free(This);
101 102 103 104 105 106 107
    }

    return ref;
}

static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
{
108 109 110 111 112 113 114
    xmlelem *This = impl_from_IXMLElement(iface);

    TRACE("(%p)->(%p)\n", This, pctinfo);

    *pctinfo = 1;

    return S_OK;
115 116 117
}

static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
118
                                          LCID lcid, ITypeInfo** ppTInfo)
119
{
120
    TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
121

122
    return get_typeinfo(IXMLElement_tid, ppTInfo);
123 124 125 126 127 128
}

static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
                                            LPOLESTR* rgszNames, UINT cNames,
                                            LCID lcid, DISPID* rgDispId)
{
129 130 131
    ITypeInfo *typeinfo;
    HRESULT hr;

132
    TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames,
133 134 135 136 137 138 139
          lcid, rgDispId);

    if(!rgszNames || cNames == 0 || !rgDispId)
        return E_INVALIDARG;

    hr = get_typeinfo(IXMLElement_tid, &typeinfo);
    if(SUCCEEDED(hr))
140
    {
141
        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
142 143
        ITypeInfo_Release(typeinfo);
    }
144 145

    return hr;
146 147 148 149 150 151 152
}

static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
                                     REFIID riid, LCID lcid, WORD wFlags,
                                     DISPPARAMS* pDispParams, VARIANT* pVarResult,
                                     EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
153 154 155
    ITypeInfo *typeinfo;
    HRESULT hr;

156
    TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
157 158 159 160
          lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);

    hr = get_typeinfo(IXMLElement_tid, &typeinfo);
    if(SUCCEEDED(hr))
161
    {
162
        hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
163 164
        ITypeInfo_Release(typeinfo);
    }
165 166

    return hr;
167 168 169 170 171 172
}

static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
{
    xmlelem *This = impl_from_IXMLElement(iface);

173
    TRACE("(%p)->(%p)\n", This, p);
174 175 176 177

    if (!p)
        return E_INVALIDARG;

178 179 180 181 182 183
    if (*This->node->name) {
        *p = bstr_from_xmlChar(This->node->name);
        CharUpperBuffW(*p, SysStringLen(*p));
    }else {
        *p = NULL;
    }
184 185 186 187 188 189 190 191

    TRACE("returning %s\n", debugstr_w(*p));

    return S_OK;
}

static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
{
192 193 194
    xmlelem *This = impl_from_IXMLElement(iface);

    FIXME("(%p)->(%s): stub\n", This, debugstr_w(p));
195 196 197 198 199 200 201 202 203 204 205

    if (!p)
        return E_INVALIDARG;

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
{
    xmlelem *This = impl_from_IXMLElement(iface);

206
    TRACE("(%p)->(%p)\n", This, parent);
207 208 209 210 211 212 213 214 215

    if (!parent)
        return E_INVALIDARG;

    *parent = NULL;

    if (!This->node->parent)
        return S_FALSE;

216
    return XMLElement_create(This->node->parent, (LPVOID *)parent, FALSE);
217 218 219 220 221 222 223 224 225
}

static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
                                            VARIANT PropertyValue)
{
    xmlelem *This = impl_from_IXMLElement(iface);
    xmlChar *name, *value;
    xmlAttrPtr attr;

226
    TRACE("(%p)->(%s %s)\n", This, debugstr_w(strPropertyName), debugstr_variant(&PropertyValue));
227 228 229 230

    if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
        return E_INVALIDARG;

231 232
    name = xmlchar_from_wchar(strPropertyName);
    value = xmlchar_from_wchar(V_BSTR(&PropertyValue));
233 234
    attr = xmlSetProp(This->node, name, value);

235 236
    heap_free(name);
    heap_free(value);
237 238 239
    return (attr) ? S_OK : S_FALSE;
}

240 241
static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name,
    VARIANT *value)
242
{
243
    static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 };
244
    xmlelem *This = impl_from_IXMLElement(iface);
245
    xmlChar *val = NULL;
246

247
    TRACE("(%p)->(%s, %p)\n", This, debugstr_w(name), value);
248

249
    if (!value)
250 251
        return E_INVALIDARG;

252 253
    VariantInit(value);
    V_BSTR(value) = NULL;
254

255
    if (!name)
256 257
        return E_INVALIDARG;

258 259
    /* case for xml:lang attribute */
    if (!lstrcmpiW(name, xmllangW))
260
    {
261 262 263 264 265 266 267 268 269
        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;

270
        xml_name = xmlchar_from_wchar(name);
271 272
        attr = This->node->properties;
        while (attr)
273
        {
274 275 276 277 278 279 280 281 282 283 284 285
            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);
286 287
        }

288
        heap_free(xml_name);
289 290 291 292
    }

    if (val)
    {
293 294
        V_VT(value) = VT_BSTR;
        V_BSTR(value) = bstr_from_xmlChar(val);
295 296 297
    }

    xmlFree(val);
298
    TRACE("returning %s\n", debugstr_w(V_BSTR(value)));
299 300 301 302 303 304 305 306 307 308 309
    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;

310
    TRACE("(%p)->(%s)\n", This, debugstr_w(strPropertyName));
311 312 313 314

    if (!strPropertyName)
        return E_INVALIDARG;

315
    name = xmlchar_from_wchar(strPropertyName);
316 317 318 319 320 321 322 323 324 325
    attr = xmlHasProp(This->node, name);
    if (!attr)
        goto done;

    res = xmlRemoveProp(attr);

    if (res == 0)
        hr = S_OK;

done:
326
    heap_free(name);
327 328 329 330 331 332 333
    return hr;
}

static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
{
    xmlelem *This = impl_from_IXMLElement(iface);

334
    TRACE("(%p)->(%p)\n", This, p);
335 336 337 338

    if (!p)
        return E_INVALIDARG;

339
    return XMLElementCollection_create(This->node, (LPVOID *)p);
340 341
}

342
static LONG type_libxml_to_msxml(xmlElementType type)
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
{
    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;
}

365
static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
366 367 368
{
    xmlelem *This = impl_from_IXMLElement(iface);

369
    TRACE("(%p)->(%p)\n", This, p);
370 371 372 373 374

    if (!p)
        return E_INVALIDARG;

    *p = type_libxml_to_msxml(This->node->type);
375
    TRACE("returning %ld\n", *p);
376 377 378 379 380 381 382 383
    return S_OK;
}

static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
{
    xmlelem *This = impl_from_IXMLElement(iface);
    xmlChar *content;

384
    TRACE("(%p)->(%p)\n", This, p);
385 386 387 388 389 390 391

    if (!p)
        return E_INVALIDARG;

    content = xmlNodeGetContent(This->node);
    *p = bstr_from_xmlChar(content);
    TRACE("returning %s\n", debugstr_w(*p));
392 393

    xmlFree(content);
394 395 396 397 398 399 400 401
    return S_OK;
}

static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
{
    xmlelem *This = impl_from_IXMLElement(iface);
    xmlChar *content;

402
    TRACE("(%p)->(%s)\n", This, debugstr_w(p));
403 404 405 406 407

    /* FIXME: test which types can be used */
    if (This->node->type == XML_ELEMENT_NODE)
        return E_NOTIMPL;

408
    content = xmlchar_from_wchar(p);
409
    xmlNodeSetContent(This->node, content);
410

411
    heap_free(content);
412

413 414 415 416
    return S_OK;
}

static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
417
                                       LONG lIndex, LONG lreserved)
418 419 420 421 422
{
    xmlelem *This = impl_from_IXMLElement(iface);
    xmlelem *childElem = impl_from_IXMLElement(pChildElem);
    xmlNodePtr child;

423
    TRACE("%p, %p, %ld, %ld.\n", iface, pChildElem, lIndex, lreserved);
424 425 426 427 428 429

    if (lIndex == 0)
        child = xmlAddChild(This->node, childElem->node);
    else
        child = xmlAddNextSibling(This->node, childElem->node->last);

430 431 432
    /* parent is responsible for child data */
    if (child) childElem->own = FALSE;

433 434 435 436 437
    return (child) ? S_OK : S_FALSE;
}

static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
{
438 439 440
    xmlelem *This = impl_from_IXMLElement(iface);
    xmlelem *childElem = impl_from_IXMLElement(pChildElem);

441
    TRACE("(%p)->(%p)\n", This, childElem);
442 443 444 445 446 447 448 449 450

    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);
451 452
    /* standalone element now */
    childElem->own = TRUE;
453 454

    return S_OK;
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
}

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
};

480
HRESULT XMLElement_create(xmlNodePtr node, LPVOID *ppObj, BOOL own)
481 482 483
{
    xmlelem *elem;

484
    TRACE("(%p)\n", ppObj);
485 486 487 488 489 490

    if (!ppObj)
        return E_INVALIDARG;

    *ppObj = NULL;

491
    elem = heap_alloc(sizeof (*elem));
492 493 494
    if(!elem)
        return E_OUTOFMEMORY;

495
    elem->IXMLElement_iface.lpVtbl = &xmlelem_vtbl;
496 497
    elem->ref = 1;
    elem->node = node;
498
    elem->own  = own;
499

500
    *ppObj = &elem->IXMLElement_iface;
501 502 503 504 505 506 507 508 509 510

    TRACE("returning iface %p\n", *ppObj);
    return S_OK;
}

/************************************************************************
 * IXMLElementCollection
 */
typedef struct _xmlelem_collection
{
511 512
    IXMLElementCollection IXMLElementCollection_iface;
    IEnumVARIANT IEnumVARIANT_iface;
513 514 515 516 517 518 519 520
    LONG ref;
    LONG length;
    xmlNodePtr node;

    /* IEnumVARIANT members */
    xmlNodePtr current;
} xmlelem_collection;

521 522 523 524 525 526 527 528 529 530 531 532 533
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;
}

534 535
static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
{
536
    return CONTAINING_RECORD(iface, xmlelem_collection, IXMLElementCollection_iface);
537 538 539 540
}

static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
{
541
    return CONTAINING_RECORD(iface, xmlelem_collection, IEnumVARIANT_iface);
542 543 544 545 546 547
}

static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
{
    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);

548
    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
549 550 551 552 553 554 555 556

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IXMLElementCollection))
    {
        *ppvObject = iface;
    }
    else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
    {
557
        *ppvObject = &This->IEnumVARIANT_iface;
558 559 560 561
    }
    else
    {
        FIXME("interface %s not implemented\n", debugstr_guid(riid));
562
        *ppvObject = NULL;
563 564 565 566 567 568 569 570 571 572 573
        return E_NOINTERFACE;
    }

    IXMLElementCollection_AddRef(iface);

    return S_OK;
}

static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
{
    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
574
    TRACE("(%p)\n", This);
575 576 577 578 579 580 581 582
    return InterlockedIncrement(&This->ref);
}

static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
{
    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
    LONG ref;

583
    TRACE("(%p)\n", This);
584 585 586 587

    ref = InterlockedDecrement(&This->ref);
    if (ref == 0)
    {
588
        heap_free(This);
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
    }

    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;
}

624
static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
625
{
626 627
    TRACE("%p, %ld.\n", iface, v);

628 629 630
    return E_FAIL;
}

631
static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
632 633 634
{
    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);

635
    TRACE("(%p)->(%p)\n", This, p);
636 637 638 639

    if (!p)
        return E_INVALIDARG;

640
    *p = xmlelem_collection_updatelength(This);
641 642 643 644 645 646 647
    return S_OK;
}

static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
{
    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);

648
    TRACE("(%p)->(%p)\n", This, ppUnk);
649 650 651 652

    if (!ppUnk)
        return E_INVALIDARG;

653 654
    IXMLElementCollection_AddRef(iface);
    *ppUnk = (IUnknown *)&This->IEnumVARIANT_iface;
655 656 657 658 659 660 661
    return S_OK;
}

static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
                                              VARIANT var2, IDispatch **ppDisp)
{
    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
662
    xmlNodePtr ptr = This->node->children;
663 664
    int index, i;

665
    TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&var1), debugstr_variant(&var2), ppDisp);
666 667 668 669 670 671 672 673 674

    if (!ppDisp)
        return E_INVALIDARG;

    *ppDisp = NULL;

    index = V_I4(&var1);
    if (index < 0)
        return E_INVALIDARG;
675 676

    xmlelem_collection_updatelength(This);
677 678 679 680 681 682
    if (index >= This->length)
        return E_FAIL;

    for (i = 0; i < index; i++)
        ptr = ptr->next;

683
    return XMLElement_create(ptr, (LPVOID *)ppDisp, FALSE);
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
}

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);
708 709 710 711 712 713 714 715 716 717 718 719 720 721

    TRACE("(%p)->(%s %p)\n", this, debugstr_guid(riid), ppvObj);

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IEnumVARIANT))
    {
        *ppvObj = iface;
        IEnumVARIANT_AddRef(iface);
        return S_OK;
    }

    FIXME("interface %s not implemented\n", debugstr_guid(riid));
    *ppvObj = NULL;
    return E_NOINTERFACE;
722 723 724 725 726 727
}

static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
    IEnumVARIANT *iface)
{
    xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
728
    return IXMLElementCollection_AddRef(&this->IXMLElementCollection_iface);
729 730 731 732 733 734
}

static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
    IEnumVARIANT *iface)
{
    xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
735
    return IXMLElementCollection_Release(&this->IXMLElementCollection_iface);
736 737 738
}

static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
739
    IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *fetched)
740 741
{
    xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
742
    HRESULT hr;
743

744
    TRACE("%p, %lu, %p, %p.\n", iface, celt, rgVar, fetched);
745 746 747 748

    if (!rgVar)
        return E_INVALIDARG;

749
    if (fetched) *fetched = 0;
750

751
    if (!This->current)
752 753 754 755
    {
        V_VT(rgVar) = VT_EMPTY;
        return S_FALSE;
    }
756

757 758 759 760 761 762 763
    while (celt > 0 && This->current)
    {
        V_VT(rgVar) = VT_DISPATCH;
        hr = XMLElement_create(This->current, (void **)&V_DISPATCH(rgVar), FALSE);
        if (FAILED(hr)) return hr;
        This->current = This->current->next;
        if (fetched) ++*fetched;
764 765
        rgVar++;
        celt--;
766
    }
767 768 769
    if (!celt) return S_OK;
    V_VT(rgVar) = VT_EMPTY;
    return S_FALSE;
770 771 772 773 774
}

static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
    IEnumVARIANT *iface, ULONG celt)
{
775
    FIXME("%p, %lu: stub\n", iface, celt);
776 777 778 779 780 781 782
    return E_NOTIMPL;
}

static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
    IEnumVARIANT *iface)
{
    xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
783
    TRACE("(%p)\n", This);
784
    This->current = This->node->children;
785 786 787 788 789 790
    return S_OK;
}

static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
    IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
{
791 792
    xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
    FIXME("(%p)->(%p): stub\n", This, ppEnum);
793 794 795 796 797 798 799 800 801 802 803 804 805 806
    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
};

807
static HRESULT XMLElementCollection_create(xmlNodePtr node, LPVOID *ppObj)
808 809 810
{
    xmlelem_collection *collection;

811
    TRACE("(%p)\n", ppObj);
812 813 814

    *ppObj = NULL;

815
    if (!node->children)
816 817
        return S_FALSE;

818
    collection = heap_alloc(sizeof (*collection));
819 820 821
    if(!collection)
        return E_OUTOFMEMORY;

822 823
    collection->IXMLElementCollection_iface.lpVtbl = &xmlelem_collection_vtbl;
    collection->IEnumVARIANT_iface.lpVtbl = &xmlelem_collection_IEnumVARIANTvtbl;
824 825 826
    collection->ref = 1;
    collection->length = 0;
    collection->node = node;
827 828
    collection->current = node->children;
    xmlelem_collection_updatelength(collection);
829

830
    *ppObj = &collection->IXMLElementCollection_iface;
831 832 833 834

    TRACE("returning iface %p\n", *ppObj);
    return S_OK;
}