Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / dll / win32 / 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 WIN32_NO_STATUS
22 #define _INC_WINDOWS
23
24 #define COBJMACROS
25
26 #include <config.h>
27
28 //#include <stdarg.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 //# include <libxml/xmlerror.h>
32 #endif
33
34 #include <windef.h>
35 #include <winbase.h>
36 //#include "winuser.h"
37 #include <ole2.h>
38 #include <msxml6.h>
39 #include <msxml2did.h>
40
41 #include "msxml_private.h"
42
43 #include <wine/debug.h>
44
45 /* This file implements the object returned by childNodes property. Note that this is
46 * not the IXMLDOMNodeList returned by XPath queries - it's implemented in selection.c.
47 * They are different because the list returned by childNodes:
48 * - is "live" - changes to the XML tree are automatically reflected in the list
49 * - doesn't supports IXMLDOMSelection
50 * - note that an attribute node have a text child in DOM but not in the XPath data model
51 * thus the child is inaccessible by an XPath query
52 */
53
54 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
55
56 #ifdef HAVE_LIBXML2
57
58 typedef struct
59 {
60 DispatchEx dispex;
61 IXMLDOMNodeList IXMLDOMNodeList_iface;
62 LONG ref;
63 xmlNodePtr parent;
64 xmlNodePtr current;
65 IEnumVARIANT *enumvariant;
66 } xmlnodelist;
67
68 static HRESULT nodelist_get_item(IUnknown *iface, LONG index, VARIANT *item)
69 {
70 V_VT(item) = VT_DISPATCH;
71 return IXMLDOMNodeList_get_item((IXMLDOMNodeList*)iface, index, (IXMLDOMNode**)&V_DISPATCH(item));
72 }
73
74 static const struct enumvariant_funcs nodelist_enumvariant = {
75 nodelist_get_item,
76 NULL
77 };
78
79 static inline xmlnodelist *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
80 {
81 return CONTAINING_RECORD(iface, xmlnodelist, IXMLDOMNodeList_iface);
82 }
83
84 static HRESULT WINAPI xmlnodelist_QueryInterface(
85 IXMLDOMNodeList *iface,
86 REFIID riid,
87 void** ppvObject )
88 {
89 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
90
91 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
92
93 if (!ppvObject)
94 {
95 /* NOTE: Interface documentation for IUnknown explicitly states
96 * this case should return E_POINTER. Empirical data proves
97 * MS violates this contract and instead return E_INVALIDARG.
98 */
99 return E_INVALIDARG;
100 }
101
102 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
103 IsEqualGUID( riid, &IID_IDispatch ) ||
104 IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
105 {
106 *ppvObject = iface;
107 }
108 else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
109 {
110 if (!This->enumvariant)
111 {
112 HRESULT hr = create_enumvariant((IUnknown*)iface, FALSE, &nodelist_enumvariant, &This->enumvariant);
113 if (FAILED(hr)) return hr;
114 }
115
116 return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject);
117 }
118 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
119 {
120 return *ppvObject ? S_OK : E_NOINTERFACE;
121 }
122 else
123 {
124 TRACE("interface %s not implemented\n", debugstr_guid(riid));
125 *ppvObject = NULL;
126 return E_NOINTERFACE;
127 }
128
129 IXMLDOMNodeList_AddRef( iface );
130
131 return S_OK;
132 }
133
134 static ULONG WINAPI xmlnodelist_AddRef(
135 IXMLDOMNodeList *iface )
136 {
137 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
138 ULONG ref = InterlockedIncrement( &This->ref );
139 TRACE("(%p)->(%d)\n", This, ref);
140 return ref;
141 }
142
143 static ULONG WINAPI xmlnodelist_Release(
144 IXMLDOMNodeList *iface )
145 {
146 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
147 ULONG ref = InterlockedDecrement( &This->ref );
148
149 TRACE("(%p)->(%d)\n", This, ref);
150 if ( ref == 0 )
151 {
152 xmldoc_release( This->parent->doc );
153 if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
154 heap_free( This );
155 }
156
157 return ref;
158 }
159
160 static HRESULT WINAPI xmlnodelist_GetTypeInfoCount(
161 IXMLDOMNodeList *iface,
162 UINT* pctinfo )
163 {
164 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
165 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
166 }
167
168 static HRESULT WINAPI xmlnodelist_GetTypeInfo(
169 IXMLDOMNodeList *iface,
170 UINT iTInfo,
171 LCID lcid,
172 ITypeInfo** ppTInfo )
173 {
174 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
175 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
176 iTInfo, lcid, ppTInfo);
177 }
178
179 static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
180 IXMLDOMNodeList *iface,
181 REFIID riid,
182 LPOLESTR* rgszNames,
183 UINT cNames,
184 LCID lcid,
185 DISPID* rgDispId )
186 {
187 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
188 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
189 riid, rgszNames, cNames, lcid, rgDispId);
190 }
191
192 static HRESULT WINAPI xmlnodelist_Invoke(
193 IXMLDOMNodeList *iface,
194 DISPID dispIdMember,
195 REFIID riid,
196 LCID lcid,
197 WORD wFlags,
198 DISPPARAMS* pDispParams,
199 VARIANT* pVarResult,
200 EXCEPINFO* pExcepInfo,
201 UINT* puArgErr )
202 {
203 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
204 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
205 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
206 }
207
208 static HRESULT WINAPI xmlnodelist_get_item(
209 IXMLDOMNodeList* iface,
210 LONG index,
211 IXMLDOMNode** listItem)
212 {
213 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
214 xmlNodePtr curr;
215 LONG nodeIndex = 0;
216
217 TRACE("(%p)->(%d %p)\n", This, index, listItem);
218
219 if(!listItem)
220 return E_INVALIDARG;
221
222 *listItem = NULL;
223
224 if (index < 0)
225 return S_FALSE;
226
227 curr = This->parent->children;
228 while(curr)
229 {
230 if(nodeIndex++ == index) break;
231 curr = curr->next;
232 }
233 if(!curr) return S_FALSE;
234
235 *listItem = create_node( curr );
236
237 return S_OK;
238 }
239
240 static HRESULT WINAPI xmlnodelist_get_length(
241 IXMLDOMNodeList* iface,
242 LONG* listLength)
243 {
244
245 xmlNodePtr curr;
246 LONG nodeCount = 0;
247
248 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
249
250 TRACE("(%p)->(%p)\n", This, listLength);
251
252 if(!listLength)
253 return E_INVALIDARG;
254
255 curr = This->parent->children;
256 while (curr)
257 {
258 nodeCount++;
259 curr = curr->next;
260 }
261
262 *listLength = nodeCount;
263 return S_OK;
264 }
265
266 static HRESULT WINAPI xmlnodelist_nextNode(
267 IXMLDOMNodeList* iface,
268 IXMLDOMNode** nextItem)
269 {
270 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
271
272 TRACE("(%p)->(%p)\n", This, nextItem );
273
274 if(!nextItem)
275 return E_INVALIDARG;
276
277 *nextItem = NULL;
278
279 if (!This->current)
280 return S_FALSE;
281
282 *nextItem = create_node( This->current );
283 This->current = This->current->next;
284 return S_OK;
285 }
286
287 static HRESULT WINAPI xmlnodelist_reset(
288 IXMLDOMNodeList* iface)
289 {
290 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
291
292 TRACE("%p\n", This);
293 This->current = This->parent->children;
294 return S_OK;
295 }
296
297 static HRESULT WINAPI xmlnodelist__newEnum(
298 IXMLDOMNodeList* iface,
299 IUnknown** enumv)
300 {
301 xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
302 TRACE("(%p)->(%p)\n", This, enumv);
303 return create_enumvariant((IUnknown*)iface, TRUE, &nodelist_enumvariant, (IEnumVARIANT**)enumv);
304 }
305
306 static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
307 {
308 xmlnodelist_QueryInterface,
309 xmlnodelist_AddRef,
310 xmlnodelist_Release,
311 xmlnodelist_GetTypeInfoCount,
312 xmlnodelist_GetTypeInfo,
313 xmlnodelist_GetIDsOfNames,
314 xmlnodelist_Invoke,
315 xmlnodelist_get_item,
316 xmlnodelist_get_length,
317 xmlnodelist_nextNode,
318 xmlnodelist_reset,
319 xmlnodelist__newEnum,
320 };
321
322 static HRESULT xmlnodelist_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
323 {
324 WCHAR *ptr;
325 int idx = 0;
326
327 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
328 idx = idx*10 + (*ptr-'0');
329 if(*ptr)
330 return DISP_E_UNKNOWNNAME;
331
332 *dispid = DISPID_DOM_COLLECTION_BASE + idx;
333 TRACE("ret %x\n", *dispid);
334 return S_OK;
335 }
336
337 static HRESULT xmlnodelist_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
338 VARIANT *res, EXCEPINFO *ei)
339 {
340 xmlnodelist *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
341
342 TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
343
344 if (id >= DISPID_DOM_COLLECTION_BASE && id <= DISPID_DOM_COLLECTION_MAX)
345 {
346 switch(flags)
347 {
348 case DISPATCH_PROPERTYGET:
349 {
350 IXMLDOMNode *disp = NULL;
351
352 V_VT(res) = VT_DISPATCH;
353 IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
354 V_DISPATCH(res) = (IDispatch*)disp;
355 break;
356 }
357 default:
358 {
359 FIXME("unimplemented flags %x\n", flags);
360 break;
361 }
362 }
363 }
364 else if (id == DISPID_VALUE)
365 {
366 switch(flags)
367 {
368 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
369 case DISPATCH_PROPERTYGET:
370 case DISPATCH_METHOD:
371 {
372 IXMLDOMNode *item;
373 VARIANT index;
374 HRESULT hr;
375
376 if (params->cArgs - params->cNamedArgs != 1) return DISP_E_BADPARAMCOUNT;
377
378 VariantInit(&index);
379 hr = VariantChangeType(&index, params->rgvarg, 0, VT_I4);
380 if(FAILED(hr))
381 {
382 FIXME("failed to convert arg, %s\n", debugstr_variant(params->rgvarg));
383 return hr;
384 }
385
386 IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, V_I4(&index), &item);
387 V_VT(res) = VT_DISPATCH;
388 V_DISPATCH(res) = (IDispatch*)item;
389 break;
390 }
391 default:
392 {
393 FIXME("DISPID_VALUE: unimplemented flags %x\n", flags);
394 break;
395 }
396 }
397 }
398 else
399 return DISP_E_UNKNOWNNAME;
400
401 TRACE("ret %p\n", V_DISPATCH(res));
402
403 return S_OK;
404 }
405
406 static const dispex_static_data_vtbl_t xmlnodelist_dispex_vtbl = {
407 xmlnodelist_get_dispid,
408 xmlnodelist_invoke
409 };
410
411 static const tid_t xmlnodelist_iface_tids[] = {
412 IXMLDOMNodeList_tid,
413 0
414 };
415 static dispex_static_data_t xmlnodelist_dispex = {
416 &xmlnodelist_dispex_vtbl,
417 IXMLDOMNodeList_tid,
418 NULL,
419 xmlnodelist_iface_tids
420 };
421
422 IXMLDOMNodeList* create_children_nodelist( xmlNodePtr node )
423 {
424 xmlnodelist *This;
425
426 This = heap_alloc( sizeof *This );
427 if ( !This )
428 return NULL;
429
430 This->IXMLDOMNodeList_iface.lpVtbl = &xmlnodelist_vtbl;
431 This->ref = 1;
432 This->parent = node;
433 This->current = node->children;
434 This->enumvariant = NULL;
435 xmldoc_add_ref( node->doc );
436
437 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNodeList_iface, &xmlnodelist_dispex);
438
439 return &This->IXMLDOMNodeList_iface;
440 }
441
442 #endif