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