msxml3: Implement ::get_responseXML().
[wine] / dlls / msxml3 / nodemap.c
1 /*
2  *    Node map 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 "config.h"
22
23 #define COBJMACROS
24
25 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31 #include "msxml6.h"
32
33 #include "msxml_private.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
38
39 #ifdef HAVE_LIBXML2
40
41 typedef struct _xmlnodemap
42 {
43     const struct IXMLDOMNamedNodeMapVtbl *lpVtbl;
44     const struct ISupportErrorInfoVtbl *lpSEIVtbl;
45     LONG ref;
46     IXMLDOMNode *node;
47     LONG iterator;
48 } xmlnodemap;
49
50 static inline xmlnodemap *impl_from_IXMLDOMNamedNodeMap( IXMLDOMNamedNodeMap *iface )
51 {
52     return (xmlnodemap *)((char*)iface - FIELD_OFFSET(xmlnodemap, lpVtbl));
53 }
54
55 static inline xmlnodemap *impl_from_ISupportErrorInfo( ISupportErrorInfo *iface )
56 {
57     return (xmlnodemap *)((char*)iface - FIELD_OFFSET(xmlnodemap, lpSEIVtbl));
58 }
59
60 static HRESULT WINAPI xmlnodemap_QueryInterface(
61     IXMLDOMNamedNodeMap *iface,
62     REFIID riid, void** ppvObject )
63 {
64     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
65     TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
66
67     if( IsEqualGUID( riid, &IID_IUnknown ) ||
68         IsEqualGUID( riid, &IID_IDispatch ) ||
69         IsEqualGUID( riid, &IID_IXMLDOMNamedNodeMap ) )
70     {
71         *ppvObject = iface;
72     }
73     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
74     {
75         *ppvObject = &This->lpSEIVtbl;
76     }
77     else
78     {
79         FIXME("interface %s not implemented\n", debugstr_guid(riid));
80         return E_NOINTERFACE;
81     }
82
83     IXMLDOMElement_AddRef( iface );
84
85     return S_OK;
86 }
87
88 static ULONG WINAPI xmlnodemap_AddRef(
89     IXMLDOMNamedNodeMap *iface )
90 {
91     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
92     return InterlockedIncrement( &This->ref );
93 }
94
95 static ULONG WINAPI xmlnodemap_Release(
96     IXMLDOMNamedNodeMap *iface )
97 {
98     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
99     ULONG ref;
100
101     ref = InterlockedDecrement( &This->ref );
102     if ( ref == 0 )
103     {
104         IXMLDOMNode_Release( This->node );
105         heap_free( This );
106     }
107
108     return ref;
109 }
110
111 static HRESULT WINAPI xmlnodemap_GetTypeInfoCount(
112     IXMLDOMNamedNodeMap *iface,
113     UINT* pctinfo )
114 {
115     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
116
117     TRACE("(%p)->(%p)\n", This, pctinfo);
118
119     *pctinfo = 1;
120
121     return S_OK;
122 }
123
124 static HRESULT WINAPI xmlnodemap_GetTypeInfo(
125     IXMLDOMNamedNodeMap *iface,
126     UINT iTInfo, LCID lcid,
127     ITypeInfo** ppTInfo )
128 {
129     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
130     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
131     return get_typeinfo(IXMLDOMNamedNodeMap_tid, ppTInfo);
132 }
133
134 static HRESULT WINAPI xmlnodemap_GetIDsOfNames(
135     IXMLDOMNamedNodeMap *iface,
136     REFIID riid, LPOLESTR* rgszNames,
137     UINT cNames, LCID lcid, DISPID* rgDispId )
138 {
139     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
140     ITypeInfo *typeinfo;
141     HRESULT hr;
142
143     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
144           lcid, rgDispId);
145
146     if(!rgszNames || cNames == 0 || !rgDispId)
147         return E_INVALIDARG;
148
149     hr = get_typeinfo(IXMLDOMNamedNodeMap_tid, &typeinfo);
150     if(SUCCEEDED(hr))
151     {
152         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
153         ITypeInfo_Release(typeinfo);
154     }
155
156     return hr;
157 }
158
159 static HRESULT WINAPI xmlnodemap_Invoke(
160     IXMLDOMNamedNodeMap *iface,
161     DISPID dispIdMember, REFIID riid, LCID lcid,
162     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
163     EXCEPINFO* pExcepInfo, UINT* puArgErr )
164 {
165     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
166     ITypeInfo *typeinfo;
167     HRESULT hr;
168
169     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
170           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
171
172     hr = get_typeinfo(IXMLDOMNamedNodeMap_tid, &typeinfo);
173     if(SUCCEEDED(hr))
174     {
175         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
176                 pVarResult, pExcepInfo, puArgErr);
177         ITypeInfo_Release(typeinfo);
178     }
179
180     return hr;
181 }
182
183 xmlChar *xmlChar_from_wchar( LPCWSTR str )
184 {
185     DWORD len;
186     xmlChar *xmlstr;
187
188     len = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL );
189     xmlstr = heap_alloc( len );
190     if ( xmlstr )
191         WideCharToMultiByte( CP_UTF8, 0, str, -1, (LPSTR) xmlstr, len, NULL, NULL );
192     return xmlstr;
193 }
194
195 static HRESULT WINAPI xmlnodemap_getNamedItem(
196     IXMLDOMNamedNodeMap *iface,
197     BSTR name,
198     IXMLDOMNode** namedItem)
199 {
200     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
201     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), namedItem );
202     return IXMLDOMNamedNodeMap_getQualifiedItem(iface, name, NULL, namedItem);
203 }
204
205 static HRESULT WINAPI xmlnodemap_setNamedItem(
206     IXMLDOMNamedNodeMap *iface,
207     IXMLDOMNode* newItem,
208     IXMLDOMNode** namedItem)
209 {
210     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
211     xmlNodePtr nodeNew;
212     xmlNodePtr node;
213     xmlnode *ThisNew;
214
215     TRACE("(%p)->(%p %p)\n", This, newItem, namedItem );
216
217     if(!newItem)
218         return E_INVALIDARG;
219
220     if(namedItem) *namedItem = NULL;
221
222     node = xmlNodePtr_from_domnode( This->node, 0 );
223     if ( !node )
224         return E_FAIL;
225
226     /* Must be an Attribute */
227     ThisNew = get_node_obj( newItem );
228     if(!ThisNew) {
229         FIXME("ThisNew is not our node implementation\n");
230         return E_FAIL;
231     }
232
233     if(ThisNew->node->type != XML_ATTRIBUTE_NODE)
234         return E_FAIL;
235
236     if(!ThisNew->node->parent)
237         if(xmldoc_remove_orphan(ThisNew->node->doc, ThisNew->node) != S_OK)
238             WARN("%p is not an orphan of %p\n", ThisNew->node, ThisNew->node->doc);
239
240     nodeNew = xmlAddChild(node, ThisNew->node);
241
242     if(namedItem)
243         *namedItem = create_node( nodeNew );
244     return S_OK;
245 }
246
247 static HRESULT WINAPI xmlnodemap_removeNamedItem(
248     IXMLDOMNamedNodeMap *iface,
249     BSTR name,
250     IXMLDOMNode** namedItem)
251 {
252     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
253     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), namedItem );
254     return IXMLDOMNamedNodeMap_removeQualifiedItem(iface, name, NULL, namedItem);
255 }
256
257 static HRESULT WINAPI xmlnodemap_get_item(
258     IXMLDOMNamedNodeMap *iface,
259     LONG index,
260     IXMLDOMNode** listItem)
261 {
262     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
263     xmlNodePtr node;
264     xmlAttrPtr curr;
265     LONG attrIndex;
266
267     TRACE("(%p)->(%d %p)\n", This, index, listItem);
268
269     *listItem = NULL;
270
271     if (index < 0)
272         return S_FALSE;
273
274     node = xmlNodePtr_from_domnode( This->node, 0 );
275     curr = node->properties;
276
277     for (attrIndex = 0; attrIndex < index; attrIndex++) {
278         if (curr->next == NULL)
279             return S_FALSE;
280         else
281             curr = curr->next;
282     }
283     
284     *listItem = create_node( (xmlNodePtr) curr );
285
286     return S_OK;
287 }
288
289 static HRESULT WINAPI xmlnodemap_get_length(
290     IXMLDOMNamedNodeMap *iface,
291     LONG *listLength)
292 {
293     xmlNodePtr node;
294     xmlAttrPtr first;
295     xmlAttrPtr curr;
296     LONG attrCount;
297
298     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
299
300     TRACE("(%p)->(%p)\n", This, listLength);
301
302     if( !listLength )
303         return E_INVALIDARG;
304
305     node = xmlNodePtr_from_domnode( This->node, 0 );
306     if ( !node )
307         return E_FAIL;
308
309     first = node->properties;
310     if (first == NULL) {
311         *listLength = 0;
312         return S_OK;
313     }
314
315     curr = first;
316     attrCount = 1;
317     while (curr->next) {
318         attrCount++;
319         curr = curr->next;
320     }
321     *listLength = attrCount;
322  
323     return S_OK;
324 }
325
326 static HRESULT WINAPI xmlnodemap_getQualifiedItem(
327     IXMLDOMNamedNodeMap *iface,
328     BSTR baseName,
329     BSTR namespaceURI,
330     IXMLDOMNode** qualifiedItem)
331 {
332     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
333     xmlAttrPtr attr;
334     xmlNodePtr node;
335     xmlChar *href;
336     xmlChar *name;
337
338     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(baseName), debugstr_w(namespaceURI), qualifiedItem);
339
340     if (!baseName || !qualifiedItem) return E_INVALIDARG;
341
342     node = xmlNodePtr_from_domnode(This->node, XML_ELEMENT_NODE);
343     if ( !node )
344         return E_FAIL;
345
346     if (namespaceURI && *namespaceURI)
347     {
348         href = xmlChar_from_wchar(namespaceURI);
349         if (!href) return E_OUTOFMEMORY;
350     }
351     else
352         href = NULL;
353
354     name = xmlChar_from_wchar(baseName);
355     if (!name)
356     {
357         heap_free(href);
358         return E_OUTOFMEMORY;
359     }
360
361     attr = xmlHasNsProp(node, name, href);
362
363     heap_free(name);
364     heap_free(href);
365
366     if (!attr)
367     {
368         *qualifiedItem = NULL;
369         return S_FALSE;
370     }
371
372     *qualifiedItem = create_node((xmlNodePtr)attr);
373
374     return S_OK;
375 }
376
377 static HRESULT WINAPI xmlnodemap_removeQualifiedItem(
378     IXMLDOMNamedNodeMap *iface,
379     BSTR baseName,
380     BSTR namespaceURI,
381     IXMLDOMNode** qualifiedItem)
382 {
383     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
384     xmlAttrPtr attr;
385     xmlNodePtr node;
386     xmlChar *name;
387     xmlChar *href;
388
389     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(baseName), debugstr_w(namespaceURI), qualifiedItem);
390
391     if (!baseName) return E_INVALIDARG;
392
393     node = xmlNodePtr_from_domnode( This->node, XML_ELEMENT_NODE );
394     if ( !node )
395         return E_FAIL;
396
397     if (namespaceURI && *namespaceURI)
398     {
399         href = xmlChar_from_wchar(namespaceURI);
400         if (!href) return E_OUTOFMEMORY;
401     }
402     else
403         href = NULL;
404
405     name = xmlChar_from_wchar(baseName);
406     if (!name)
407     {
408         heap_free(href);
409         return E_OUTOFMEMORY;
410     }
411
412     attr = xmlHasNsProp( node, name, href );
413
414     heap_free(name);
415     heap_free(href);
416
417     if ( !attr )
418     {
419         if (qualifiedItem) *qualifiedItem = NULL;
420         return S_FALSE;
421     }
422
423     if ( qualifiedItem )
424     {
425         xmlUnlinkNode( (xmlNodePtr) attr );
426         xmldoc_add_orphan( attr->doc, (xmlNodePtr) attr );
427         *qualifiedItem = create_node( (xmlNodePtr) attr );
428     }
429     else
430     {
431         if (xmlRemoveProp(attr) == -1)
432             ERR("xmlRemoveProp failed\n");
433     }
434
435     return S_OK;
436 }
437
438 static HRESULT WINAPI xmlnodemap_nextNode(
439     IXMLDOMNamedNodeMap *iface,
440     IXMLDOMNode** nextItem)
441 {
442     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
443     xmlNodePtr node;
444     xmlAttrPtr curr;
445     LONG attrIndex;
446
447     TRACE("(%p)->(%p: %d)\n", This, nextItem, This->iterator);
448
449     *nextItem = NULL;
450
451     node = xmlNodePtr_from_domnode( This->node, 0 );
452     curr = node->properties;
453
454     for (attrIndex = 0; attrIndex < This->iterator; attrIndex++) {
455         if (curr->next == NULL)
456             return S_FALSE;
457         else
458             curr = curr->next;
459     }
460
461     This->iterator++;
462
463     *nextItem = create_node( (xmlNodePtr) curr );
464
465     return S_OK;
466 }
467
468 static HRESULT WINAPI xmlnodemap_reset(
469     IXMLDOMNamedNodeMap *iface )
470 {
471     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
472
473     TRACE("(%p: %d)\n", This, This->iterator);
474
475     This->iterator = 0;
476
477     return S_OK;
478 }
479
480 static HRESULT WINAPI xmlnodemap__newEnum(
481     IXMLDOMNamedNodeMap *iface,
482     IUnknown** ppUnk)
483 {
484     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
485     FIXME("(%p)->(%p)\n", This, ppUnk);
486     return E_NOTIMPL;
487 }
488
489 static const struct IXMLDOMNamedNodeMapVtbl xmlnodemap_vtbl =
490 {
491     xmlnodemap_QueryInterface,
492     xmlnodemap_AddRef,
493     xmlnodemap_Release,
494     xmlnodemap_GetTypeInfoCount,
495     xmlnodemap_GetTypeInfo,
496     xmlnodemap_GetIDsOfNames,
497     xmlnodemap_Invoke,
498     xmlnodemap_getNamedItem,
499     xmlnodemap_setNamedItem,
500     xmlnodemap_removeNamedItem,
501     xmlnodemap_get_item,
502     xmlnodemap_get_length,
503     xmlnodemap_getQualifiedItem,
504     xmlnodemap_removeQualifiedItem,
505     xmlnodemap_nextNode,
506     xmlnodemap_reset,
507     xmlnodemap__newEnum,
508 };
509
510 static HRESULT WINAPI support_error_QueryInterface(
511     ISupportErrorInfo *iface,
512     REFIID riid, void** ppvObject )
513 {
514     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
515     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
516     return IXMLDOMNamedNodeMap_QueryInterface((IXMLDOMNamedNodeMap*)&This->lpVtbl, riid, ppvObject);
517 }
518
519 static ULONG WINAPI support_error_AddRef(
520     ISupportErrorInfo *iface )
521 {
522     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
523     return IXMLDOMNamedNodeMap_AddRef((IXMLDOMNamedNodeMap*)&This->lpVtbl);
524 }
525
526 static ULONG WINAPI support_error_Release(
527     ISupportErrorInfo *iface )
528 {
529     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
530     return IXMLDOMNamedNodeMap_Release((IXMLDOMNamedNodeMap*)&This->lpVtbl);
531 }
532
533 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
534     ISupportErrorInfo *iface,
535     REFIID riid )
536 {
537     FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
538     return S_FALSE;
539 }
540
541 static const struct ISupportErrorInfoVtbl support_error_vtbl =
542 {
543     support_error_QueryInterface,
544     support_error_AddRef,
545     support_error_Release,
546     support_error_InterfaceSupportsErrorInfo
547 };
548
549 IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node )
550 {
551     xmlnodemap *nodemap;
552
553     nodemap = heap_alloc( sizeof *nodemap );
554     if ( !nodemap )
555         return NULL;
556
557     nodemap->lpVtbl = &xmlnodemap_vtbl;
558     nodemap->lpSEIVtbl = &support_error_vtbl;
559     nodemap->node = node;
560     nodemap->ref = 1;
561     nodemap->iterator = 0;
562
563     IXMLDOMNode_AddRef( node );
564     /* Since we AddRef a node here, we don't need to call xmldoc_add_ref() */
565
566     return (IXMLDOMNamedNodeMap*) &nodemap->lpVtbl;
567 }
568
569 #endif