msxml3: Improved checking of failed case.
[wine] / dlls / msxml3 / nodelist.c
1 /*
2  *    Node list implementation
3  *
4  * Copyright 2005 Mike McCormack
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
32 #include "msxml_private.h"
33
34 #include "wine/debug.h"
35
36 /* This file implements the object returned by childNodes property. Note that this is
37  * not the IXMLDOMNodeList returned by XPath querites - it's implemented in queryresult.c.
38  * They are different because the list returned by childNodes:
39  *  - is "live" - changes to the XML tree are automatically reflected in the list
40  *  - doesn't supports IXMLDOMSelection
41  *  - note that an attribute node have a text child in DOM but not in the XPath data model
42  *    thus the child is inaccessible by an XPath query
43  */
44
45 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
46
47 #ifdef HAVE_LIBXML2
48
49 typedef struct _xmlnodelist
50 {
51     const struct IXMLDOMNodeListVtbl *lpVtbl;
52     LONG ref;
53     xmlNodePtr parent;
54     xmlNodePtr current;
55 } xmlnodelist;
56
57 static inline xmlnodelist *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
58 {
59     return (xmlnodelist *)((char*)iface - FIELD_OFFSET(xmlnodelist, lpVtbl));
60 }
61
62 static HRESULT WINAPI xmlnodelist_QueryInterface(
63     IXMLDOMNodeList *iface,
64     REFIID riid,
65     void** ppvObject )
66 {
67     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
68
69     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
70          IsEqualGUID( riid, &IID_IDispatch ) ||
71          IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
72     {
73         *ppvObject = iface;
74     }
75     else
76     {
77         FIXME("interface %s not implemented\n", debugstr_guid(riid));
78         *ppvObject = NULL;
79         return E_NOINTERFACE;
80     }
81
82     IXMLDOMNodeList_AddRef( iface );
83
84     return S_OK;
85 }
86
87 static ULONG WINAPI xmlnodelist_AddRef(
88     IXMLDOMNodeList *iface )
89 {
90     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
91     return InterlockedIncrement( &This->ref );
92 }
93
94 static ULONG WINAPI xmlnodelist_Release(
95     IXMLDOMNodeList *iface )
96 {
97     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
98     ULONG ref;
99
100     ref = InterlockedDecrement( &This->ref );
101     if ( ref == 0 )
102     {
103         xmldoc_release( This->parent->doc );
104         HeapFree( GetProcessHeap(), 0, This );
105     }
106
107     return ref;
108 }
109
110 static HRESULT WINAPI xmlnodelist_GetTypeInfoCount(
111     IXMLDOMNodeList *iface,
112     UINT* pctinfo )
113 {
114     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
115
116     TRACE("(%p)->(%p)\n", This, pctinfo);
117
118     *pctinfo = 1;
119
120     return S_OK;
121 }
122
123 static HRESULT WINAPI xmlnodelist_GetTypeInfo(
124     IXMLDOMNodeList *iface,
125     UINT iTInfo,
126     LCID lcid,
127     ITypeInfo** ppTInfo )
128 {
129     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
130     HRESULT hr;
131
132     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
133
134     hr = get_typeinfo(IXMLDOMNodeList_tid, ppTInfo);
135
136     return hr;
137 }
138
139 static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
140     IXMLDOMNodeList *iface,
141     REFIID riid,
142     LPOLESTR* rgszNames,
143     UINT cNames,
144     LCID lcid,
145     DISPID* rgDispId )
146 {
147     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
148     ITypeInfo *typeinfo;
149     HRESULT hr;
150
151     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
152           lcid, rgDispId);
153
154     if(!rgszNames || cNames == 0 || !rgDispId)
155         return E_INVALIDARG;
156
157     hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
158     if(SUCCEEDED(hr))
159     {
160         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
161         ITypeInfo_Release(typeinfo);
162     }
163
164     return hr;
165 }
166
167 static HRESULT WINAPI xmlnodelist_Invoke(
168     IXMLDOMNodeList *iface,
169     DISPID dispIdMember,
170     REFIID riid,
171     LCID lcid,
172     WORD wFlags,
173     DISPPARAMS* pDispParams,
174     VARIANT* pVarResult,
175     EXCEPINFO* pExcepInfo,
176     UINT* puArgErr )
177 {
178     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
179     ITypeInfo *typeinfo;
180     HRESULT hr;
181
182     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
183           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
184
185     hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
186     if(SUCCEEDED(hr))
187     {
188         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
189                 pVarResult, pExcepInfo, puArgErr);
190         ITypeInfo_Release(typeinfo);
191     }
192
193     return hr;
194 }
195
196 static HRESULT WINAPI xmlnodelist_get_item(
197         IXMLDOMNodeList* iface,
198         long index,
199         IXMLDOMNode** listItem)
200 {
201     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
202     xmlNodePtr curr;
203     long nodeIndex = 0;
204
205     TRACE("%p %ld\n", This, index);
206  
207     *listItem = NULL;
208
209     if (index < 0)
210         return S_FALSE;
211
212     curr = This->parent->children;
213     while(curr)
214     {
215         if(nodeIndex++ == index) break;
216         curr = curr->next;
217     }
218     if(!curr) return S_FALSE;
219
220     *listItem = create_node( curr );
221
222     return S_OK;
223 }
224
225 static HRESULT WINAPI xmlnodelist_get_length(
226         IXMLDOMNodeList* iface,
227         long* listLength)
228 {
229
230     xmlNodePtr curr;
231     long nodeCount = 0;
232
233     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
234
235     TRACE("%p\n", This);
236
237     curr = This->parent->children;
238     while (curr)
239     {
240         nodeCount++;
241         curr = curr->next;
242     }
243
244     *listLength = nodeCount;
245     return S_OK;
246 }
247
248 static HRESULT WINAPI xmlnodelist_nextNode(
249         IXMLDOMNodeList* iface,
250         IXMLDOMNode** nextItem)
251 {
252     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
253
254     TRACE("%p %p\n", This, nextItem );
255
256     *nextItem = NULL;
257
258     if (!This->current)
259         return S_FALSE;
260
261     *nextItem = create_node( This->current );
262     This->current = This->current->next;
263     return S_OK;
264 }
265
266 static HRESULT WINAPI xmlnodelist_reset(
267         IXMLDOMNodeList* iface)
268 {
269     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
270
271     TRACE("%p\n", This);
272     This->current = This->parent->children;
273     return S_OK;
274 }
275
276 static HRESULT WINAPI xmlnodelist__newEnum(
277         IXMLDOMNodeList* iface,
278         IUnknown** ppUnk)
279 {
280     FIXME("\n");
281     return E_NOTIMPL;
282 }
283
284
285 static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
286 {
287     xmlnodelist_QueryInterface,
288     xmlnodelist_AddRef,
289     xmlnodelist_Release,
290     xmlnodelist_GetTypeInfoCount,
291     xmlnodelist_GetTypeInfo,
292     xmlnodelist_GetIDsOfNames,
293     xmlnodelist_Invoke,
294     xmlnodelist_get_item,
295     xmlnodelist_get_length,
296     xmlnodelist_nextNode,
297     xmlnodelist_reset,
298     xmlnodelist__newEnum,
299 };
300
301 IXMLDOMNodeList* create_children_nodelist( xmlNodePtr node )
302 {
303     xmlnodelist *nodelist;
304
305     nodelist = HeapAlloc( GetProcessHeap(), 0, sizeof *nodelist );
306     if ( !nodelist )
307         return NULL;
308
309     nodelist->lpVtbl = &xmlnodelist_vtbl;
310     nodelist->ref = 1;
311     nodelist->parent = node;
312     nodelist->current = node->children;
313
314     xmldoc_add_ref( node->doc );
315
316     return (IXMLDOMNodeList*) &nodelist->lpVtbl;
317 }
318
319 #endif