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