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