ReactOS  0.4.15-dev-3745-g356babc
nodelist.c
Go to the documentation of this file.
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 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 #endif
30 
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "msxml6.h"
36 #include "msxml2did.h"
37 
38 #include "msxml_private.h"
39 
40 #include "wine/debug.h"
41 
42 /* This file implements the object returned by childNodes property. Note that this is
43  * not the IXMLDOMNodeList returned by XPath queries - it's implemented in selection.c.
44  * They are different because the list returned by childNodes:
45  * - is "live" - changes to the XML tree are automatically reflected in the list
46  * - doesn't supports IXMLDOMSelection
47  * - note that an attribute node have a text child in DOM but not in the XPath data model
48  * thus the child is inaccessible by an XPath query
49  */
50 
51 #ifdef HAVE_LIBXML2
52 
54 
55 typedef struct
56 {
57  DispatchEx dispex;
58  IXMLDOMNodeList IXMLDOMNodeList_iface;
59  LONG ref;
63 } xmlnodelist;
64 
65 static HRESULT nodelist_get_item(IUnknown *iface, LONG index, VARIANT *item)
66 {
68  return IXMLDOMNodeList_get_item((IXMLDOMNodeList*)iface, index, (IXMLDOMNode**)&V_DISPATCH(item));
69 }
70 
71 static const struct enumvariant_funcs nodelist_enumvariant = {
72  nodelist_get_item,
73  NULL
74 };
75 
76 static inline xmlnodelist *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
77 {
78  return CONTAINING_RECORD(iface, xmlnodelist, IXMLDOMNodeList_iface);
79 }
80 
81 static HRESULT WINAPI xmlnodelist_QueryInterface(
82  IXMLDOMNodeList *iface,
83  REFIID riid,
84  void** ppvObject )
85 {
86  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
87 
88  TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
89 
90 #ifdef __REACTOS__
91  if (!ppvObject)
92  {
93  /* NOTE: Interface documentation for IUnknown explicitly states
94  * this case should return E_POINTER. Empirical data proves
95  * MS violates this contract and instead return E_INVALIDARG.
96  */
97  return E_INVALIDARG;
98  }
99 #endif
100 
101  if ( IsEqualGUID( riid, &IID_IUnknown ) ||
103  IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
104  {
105  *ppvObject = iface;
106  }
107  else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
108  {
109  if (!This->enumvariant)
110  {
111  HRESULT hr = create_enumvariant((IUnknown*)iface, FALSE, &nodelist_enumvariant, &This->enumvariant);
112  if (FAILED(hr)) return hr;
113  }
114 
115  return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject);
116  }
117  else if (dispex_query_interface(&This->dispex, riid, ppvObject))
118  {
119  return *ppvObject ? S_OK : E_NOINTERFACE;
120  }
121  else
122  {
123  TRACE("interface %s not implemented\n", debugstr_guid(riid));
124  *ppvObject = NULL;
125  return E_NOINTERFACE;
126  }
127 
128  IXMLDOMNodeList_AddRef( iface );
129 
130  return S_OK;
131 }
132 
133 static ULONG WINAPI xmlnodelist_AddRef(
134  IXMLDOMNodeList *iface )
135 {
136  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
137  ULONG ref = InterlockedIncrement( &This->ref );
138  TRACE("(%p)->(%d)\n", This, ref);
139  return ref;
140 }
141 
142 static ULONG WINAPI xmlnodelist_Release(
143  IXMLDOMNodeList *iface )
144 {
145  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
146  ULONG ref = InterlockedDecrement( &This->ref );
147 
148  TRACE("(%p)->(%d)\n", This, ref);
149  if ( ref == 0 )
150  {
151  xmldoc_release( This->parent->doc );
152  if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
153  heap_free( This );
154  }
155 
156  return ref;
157 }
158 
159 static HRESULT WINAPI xmlnodelist_GetTypeInfoCount(
160  IXMLDOMNodeList *iface,
161  UINT* pctinfo )
162 {
163  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
164  return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
165 }
166 
167 static HRESULT WINAPI xmlnodelist_GetTypeInfo(
168  IXMLDOMNodeList *iface,
169  UINT iTInfo,
170  LCID lcid,
171  ITypeInfo** ppTInfo )
172 {
173  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
174  return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
175  iTInfo, lcid, ppTInfo);
176 }
177 
178 static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
179  IXMLDOMNodeList *iface,
180  REFIID riid,
181  LPOLESTR* rgszNames,
182  UINT cNames,
183  LCID lcid,
184  DISPID* rgDispId )
185 {
186  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
187  return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
188  riid, rgszNames, cNames, lcid, rgDispId);
189 }
190 
191 static HRESULT WINAPI xmlnodelist_Invoke(
192  IXMLDOMNodeList *iface,
193  DISPID dispIdMember,
194  REFIID riid,
195  LCID lcid,
196  WORD wFlags,
197  DISPPARAMS* pDispParams,
198  VARIANT* pVarResult,
199  EXCEPINFO* pExcepInfo,
200  UINT* puArgErr )
201 {
202  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
203  return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
204  dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
205 }
206 
207 static HRESULT WINAPI xmlnodelist_get_item(
208  IXMLDOMNodeList* iface,
209  LONG index,
210  IXMLDOMNode** listItem)
211 {
212  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
213  xmlNodePtr curr;
214  LONG nodeIndex = 0;
215 
216  TRACE("(%p)->(%d %p)\n", This, index, listItem);
217 
218  if(!listItem)
219  return E_INVALIDARG;
220 
221  *listItem = NULL;
222 
223  if (index < 0)
224  return S_FALSE;
225 
226  curr = This->parent->children;
227  while(curr)
228  {
229  if(nodeIndex++ == index) break;
230  curr = curr->next;
231  }
232  if(!curr) return S_FALSE;
233 
234  *listItem = create_node( curr );
235 
236  return S_OK;
237 }
238 
239 static HRESULT WINAPI xmlnodelist_get_length(
240  IXMLDOMNodeList* iface,
241  LONG* listLength)
242 {
243 
244  xmlNodePtr curr;
245  LONG nodeCount = 0;
246 
247  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
248 
249  TRACE("(%p)->(%p)\n", This, listLength);
250 
251  if(!listLength)
252  return E_INVALIDARG;
253 
254  curr = This->parent->children;
255  while (curr)
256  {
257  nodeCount++;
258  curr = curr->next;
259  }
260 
261  *listLength = nodeCount;
262  return S_OK;
263 }
264 
265 static HRESULT WINAPI xmlnodelist_nextNode(
266  IXMLDOMNodeList* iface,
267  IXMLDOMNode** nextItem)
268 {
269  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
270 
271  TRACE("(%p)->(%p)\n", This, nextItem );
272 
273  if(!nextItem)
274  return E_INVALIDARG;
275 
276  *nextItem = NULL;
277 
278  if (!This->current)
279  return S_FALSE;
280 
281  *nextItem = create_node( This->current );
282  This->current = This->current->next;
283  return S_OK;
284 }
285 
286 static HRESULT WINAPI xmlnodelist_reset(
287  IXMLDOMNodeList* iface)
288 {
289  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
290 
291  TRACE("%p\n", This);
292  This->current = This->parent->children;
293  return S_OK;
294 }
295 
296 static HRESULT WINAPI xmlnodelist__newEnum(
297  IXMLDOMNodeList* iface,
298  IUnknown** enumv)
299 {
300  xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
301  TRACE("(%p)->(%p)\n", This, enumv);
302  return create_enumvariant((IUnknown*)iface, TRUE, &nodelist_enumvariant, (IEnumVARIANT**)enumv);
303 }
304 
305 static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
306 {
307  xmlnodelist_QueryInterface,
308  xmlnodelist_AddRef,
309  xmlnodelist_Release,
310  xmlnodelist_GetTypeInfoCount,
311  xmlnodelist_GetTypeInfo,
312  xmlnodelist_GetIDsOfNames,
313  xmlnodelist_Invoke,
314  xmlnodelist_get_item,
315  xmlnodelist_get_length,
316  xmlnodelist_nextNode,
317  xmlnodelist_reset,
318  xmlnodelist__newEnum,
319 };
320 
321 static HRESULT xmlnodelist_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
322 {
323  WCHAR *ptr;
324  int idx = 0;
325 
326  for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
327  idx = idx*10 + (*ptr-'0');
328  if(*ptr)
329  return DISP_E_UNKNOWNNAME;
330 
331  *dispid = DISPID_DOM_COLLECTION_BASE + idx;
332  TRACE("ret %x\n", *dispid);
333  return S_OK;
334 }
335 
336 static HRESULT xmlnodelist_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
337  VARIANT *res, EXCEPINFO *ei)
338 {
339  xmlnodelist *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
340 
341  TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
342 
344  {
345  switch(flags)
346  {
348  {
349  IXMLDOMNode *disp = NULL;
350 
351  V_VT(res) = VT_DISPATCH;
352  IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
353  V_DISPATCH(res) = (IDispatch*)disp;
354  break;
355  }
356  default:
357  {
358  FIXME("unimplemented flags %x\n", flags);
359  break;
360  }
361  }
362  }
363  else if (id == DISPID_VALUE)
364  {
365  switch(flags)
366  {
369  case DISPATCH_METHOD:
370  {
371  IXMLDOMNode *item;
372  VARIANT index;
373  HRESULT hr;
374 
375  if (params->cArgs - params->cNamedArgs != 1) return DISP_E_BADPARAMCOUNT;
376 
377  VariantInit(&index);
378  hr = VariantChangeType(&index, params->rgvarg, 0, VT_I4);
379  if(FAILED(hr))
380  {
381  FIXME("failed to convert arg, %s\n", debugstr_variant(params->rgvarg));
382  return hr;
383  }
384 
385  IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, V_I4(&index), &item);
386  V_VT(res) = VT_DISPATCH;
388  break;
389  }
390  default:
391  {
392  FIXME("DISPID_VALUE: unimplemented flags %x\n", flags);
393  break;
394  }
395  }
396  }
397  else
398  return DISP_E_UNKNOWNNAME;
399 
400  TRACE("ret %p\n", V_DISPATCH(res));
401 
402  return S_OK;
403 }
404 
405 static const dispex_static_data_vtbl_t xmlnodelist_dispex_vtbl = {
406  xmlnodelist_get_dispid,
407  xmlnodelist_invoke
408 };
409 
410 static const tid_t xmlnodelist_iface_tids[] = {
412  0
413 };
414 static dispex_static_data_t xmlnodelist_dispex = {
415  &xmlnodelist_dispex_vtbl,
417  NULL,
418  xmlnodelist_iface_tids
419 };
420 
421 IXMLDOMNodeList* create_children_nodelist( xmlNodePtr node )
422 {
423  xmlnodelist *This;
424 
425  This = heap_alloc( sizeof *This );
426  if ( !This )
427  return NULL;
428 
429  This->IXMLDOMNodeList_iface.lpVtbl = &xmlnodelist_vtbl;
430  This->ref = 1;
431  This->parent = node;
432  This->current = node->children;
433  This->enumvariant = NULL;
434  xmldoc_add_ref( node->doc );
435 
436  init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNodeList_iface, &xmlnodelist_dispex);
437 
438  return &This->IXMLDOMNodeList_iface;
439 }
440 
441 #endif
#define DISP_E_UNKNOWNNAME
Definition: winerror.h:2515
HRESULT WINAPI DECLSPEC_HOTPATCH VariantChangeType(VARIANTARG *pvargDest, VARIANTARG *pvargSrc, USHORT wFlags, VARTYPE vt)
Definition: variant.c:962
#define REFIID
Definition: guiddef.h:118
#define E_NOINTERFACE
Definition: winerror.h:2364
Definition: compat.h:2157
#define DISPATCH_PROPERTYGET
Definition: oleauto.h:1007
HRESULT hr
Definition: shlfolder.c:183
#define TRUE
Definition: types.h:120
REFIID riid
Definition: precomp.h:44
tid_t
Definition: ieframe.h:311
#define DISPID_DOM_COLLECTION_BASE
Definition: msxml2did.h:70
DWORD LCID
Definition: nls.h:13
OLECHAR * BSTR
Definition: compat.h:2152
void WINAPI VariantInit(VARIANTARG *pVarg)
Definition: variant.c:568
#define DISPID_DOM_COLLECTION_MAX
Definition: msxml2did.h:71
static LPOLESTR
Definition: stg_prop.c:27
Definition: send.c:48
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
#define V_I4(A)
Definition: oleauto.h:247
#define DISPATCH_METHOD
Definition: oleauto.h:1006
#define V_DISPATCH(A)
Definition: oleauto.h:239
struct node node
#define FALSE
Definition: types.h:117
GLenum const GLfloat * params
Definition: glext.h:5645
long LONG
Definition: pedump.c:60
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:111
static PVOID ptr
Definition: dispmode.c:27
unsigned int idx
Definition: utils.c:41
#define S_FALSE
Definition: winerror.h:2357
#define E_INVALIDARG
Definition: ddrawi.h:101
GLuint index
Definition: glext.h:6031
#define debugstr_guid
Definition: kernel32.h:35
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define TRACE(s)
Definition: solgame.cpp:4
r parent
Definition: btrfs.c:2944
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:79
const GUID IID_IUnknown
static HRESULT create_node(HTMLDocumentNode *, nsIDOMNode *, HTMLDOMNode **)
Definition: htmlnode.c:1216
#define WINAPI
Definition: msvc.h:6
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
struct task_struct * current
Definition: linux.c:32
GLbitfield flags
Definition: glext.h:7161
Definition: tree.h:489
const GUID IID_IDispatch
#define index(s, c)
Definition: various.h:29
#define InterlockedDecrement
Definition: armddk.h:52
#define V_VT(A)
Definition: oleauto.h:211
REFIID LPVOID * ppvObject
Definition: precomp.h:44
_In_ DWORD _Out_ _In_ WORD wFlags
Definition: wincon.h:531
struct stdole::EXCEPINFO EXCEPINFO
static const char * debugstr_variant(const VARIANT *var)
Definition: container.c:46
static VARIANTARG static DISPID
Definition: ordinal.c:49
#define S_OK
Definition: intsafe.h:52
#define InterlockedIncrement
Definition: armddk.h:53
static ATOM item
Definition: dde.c:856
BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv)
Definition: dispex.c:1656
struct _xmlNode * next
Definition: tree.h:496
WINE_UNICODE_INLINE int isdigitW(WCHAR wc)
Definition: unicode.h:170
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4112
HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
Definition: dispex.c:919
#define DISP_E_BADPARAMCOUNT
Definition: winerror.h:2523
Definition: name.c:38
GLuint res
Definition: glext.h:9613
struct stdole::DISPPARAMS DISPPARAMS
unsigned int ULONG
Definition: retypes.h:1
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
static BOOL heap_free(void *mem)
Definition: appwiz.h:75
Definition: dlist.c:348