mshtml: Don't crash in QueryInterface if uri is NULL.
[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 "msxml2.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 } xmlnodemap;
48
49 static inline xmlnodemap *impl_from_IXMLDOMNamedNodeMap( IXMLDOMNamedNodeMap *iface )
50 {
51     return (xmlnodemap *)((char*)iface - FIELD_OFFSET(xmlnodemap, lpVtbl));
52 }
53
54 static inline xmlnodemap *impl_from_ISupportErrorInfo( ISupportErrorInfo *iface )
55 {
56     return (xmlnodemap *)((char*)iface - FIELD_OFFSET(xmlnodemap, lpSEIVtbl));
57 }
58
59 static HRESULT WINAPI xmlnodemap_QueryInterface(
60     IXMLDOMNamedNodeMap *iface,
61     REFIID riid, void** ppvObject )
62 {
63     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
64     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
65
66     if( IsEqualGUID( riid, &IID_IUnknown ) ||
67         IsEqualGUID( riid, &IID_IDispatch ) ||
68         IsEqualGUID( riid, &IID_IXMLDOMNamedNodeMap ) )
69     {
70         *ppvObject = iface;
71     }
72     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
73     {
74         *ppvObject = &This->lpSEIVtbl;
75     }
76     else
77     {
78         FIXME("interface %s not implemented\n", debugstr_guid(riid));
79         return E_NOINTERFACE;
80     }
81
82     IXMLDOMElement_AddRef( iface );
83
84     return S_OK;
85 }
86
87 static ULONG WINAPI xmlnodemap_AddRef(
88     IXMLDOMNamedNodeMap *iface )
89 {
90     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
91     return InterlockedIncrement( &This->ref );
92 }
93
94 static ULONG WINAPI xmlnodemap_Release(
95     IXMLDOMNamedNodeMap *iface )
96 {
97     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
98     ULONG ref;
99
100     ref = InterlockedDecrement( &This->ref );
101     if ( ref == 0 )
102     {
103         IXMLDOMNode_Release( This->node );
104         HeapFree( GetProcessHeap(), 0, This );
105     }
106
107     return ref;
108 }
109
110 static HRESULT WINAPI xmlnodemap_GetTypeInfoCount(
111     IXMLDOMNamedNodeMap *iface,
112     UINT* pctinfo )
113 {
114     FIXME("\n");
115     return E_NOTIMPL;
116 }
117
118 static HRESULT WINAPI xmlnodemap_GetTypeInfo(
119     IXMLDOMNamedNodeMap *iface,
120     UINT iTInfo, LCID lcid,
121     ITypeInfo** ppTInfo )
122 {
123     FIXME("\n");
124     return E_NOTIMPL;
125 }
126
127 static HRESULT WINAPI xmlnodemap_GetIDsOfNames(
128     IXMLDOMNamedNodeMap *iface,
129     REFIID riid, LPOLESTR* rgszNames,
130     UINT cNames, LCID lcid, DISPID* rgDispId )
131 {
132     FIXME("\n");
133     return E_NOTIMPL;
134 }
135
136 static HRESULT WINAPI xmlnodemap_Invoke(
137     IXMLDOMNamedNodeMap *iface,
138     DISPID dispIdMember, REFIID riid, LCID lcid,
139     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
140     EXCEPINFO* pExcepInfo, UINT* puArgErr )
141 {
142     FIXME("\n");
143     return E_NOTIMPL;
144 }
145
146 xmlChar *xmlChar_from_wchar( LPWSTR str )
147 {
148     DWORD len;
149     xmlChar *xmlstr;
150
151     len = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL );
152     xmlstr = (xmlChar*) HeapAlloc( GetProcessHeap(), 0, len );
153     if ( xmlstr )
154         WideCharToMultiByte( CP_UTF8, 0, str, -1, (LPSTR) xmlstr, len, NULL, NULL );
155     return xmlstr;
156 }
157
158 static HRESULT WINAPI xmlnodemap_getNamedItem(
159     IXMLDOMNamedNodeMap *iface,
160     BSTR name,
161     IXMLDOMNode** namedItem)
162 {
163     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
164     xmlChar *element_name;
165     xmlAttrPtr attr;
166     xmlNodePtr node;
167
168     TRACE("%p %s\n", This, debugstr_w(name) );
169
170     node = xmlNodePtr_from_domnode( This->node, 0 );
171     if ( !node )
172         return E_FAIL;
173
174     element_name = xmlChar_from_wchar( name );
175     attr = xmlHasNsProp( node, element_name, NULL );
176     HeapFree( GetProcessHeap(), 0, element_name );
177
178     if ( !attr )
179         return E_FAIL;
180
181     *namedItem = create_node( (xmlNodePtr) attr );
182
183     return S_OK;
184 }
185
186 static HRESULT WINAPI xmlnodemap_setNamedItem(
187     IXMLDOMNamedNodeMap *iface,
188     IXMLDOMNode* newItem,
189     IXMLDOMNode** namedItem)
190 {
191     FIXME("\n");
192     return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI xmlnodemap_removeNamedItem(
196     IXMLDOMNamedNodeMap *iface,
197     BSTR name,
198     IXMLDOMNode** namedItem)
199 {
200     FIXME("\n");
201     return E_NOTIMPL;
202 }
203
204 static HRESULT WINAPI xmlnodemap_get_item(
205     IXMLDOMNamedNodeMap *iface,
206     long index,
207     IXMLDOMNode** listItem)
208 {
209     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
210     xmlNodePtr node;
211     xmlAttrPtr curr;
212     long attrIndex;
213
214     TRACE("%p %ld\n", This, index);
215
216     *listItem = NULL;
217
218     if (index < 0)
219         return S_FALSE;
220
221     node = xmlNodePtr_from_domnode( This->node, 0 );
222     curr = node->properties;
223
224     for (attrIndex = 0; attrIndex < index; attrIndex++) {
225         if (curr->next == NULL)
226             return S_FALSE;
227         else
228             curr = curr->next;
229     }
230     
231     *listItem = create_node( (xmlNodePtr) curr );
232
233     return S_OK;
234 }
235
236 static HRESULT WINAPI xmlnodemap_get_length(
237     IXMLDOMNamedNodeMap *iface,
238     long* listLength)
239 {
240     xmlNodePtr node;
241     xmlAttrPtr first;
242     xmlAttrPtr curr;
243     long attrCount;
244
245     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
246
247     TRACE("%p\n", This);
248
249     node = xmlNodePtr_from_domnode( This->node, 0 );
250     if ( !node )
251         return E_FAIL;
252
253     first = node->properties;
254     if (first == NULL) {
255         *listLength = 0;
256         return S_OK;
257     }
258
259     curr = first;
260     attrCount = 1;
261     while (curr->next != NULL) {
262         attrCount++;
263         curr = curr->next;
264     }
265     *listLength = attrCount;
266  
267     return S_OK;
268 }
269
270 static HRESULT WINAPI xmlnodemap_getQualifiedItem(
271     IXMLDOMNamedNodeMap *iface,
272     BSTR baseName,
273     BSTR namespaceURI,
274     IXMLDOMNode** qualifiedItem)
275 {
276     FIXME("\n");
277     return E_NOTIMPL;
278 }
279
280 static HRESULT WINAPI xmlnodemap_removeQualifiedItem(
281     IXMLDOMNamedNodeMap *iface,
282     BSTR baseName,
283     BSTR namespaceURI,
284     IXMLDOMNode** qualifiedItem)
285 {
286     FIXME("\n");
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI xmlnodemap_nextNode(
291     IXMLDOMNamedNodeMap *iface,
292     IXMLDOMNode** nextItem)
293 {
294     FIXME("\n");
295     return E_NOTIMPL;
296 }
297
298 static HRESULT WINAPI xmlnodemap_reset(
299     IXMLDOMNamedNodeMap *iface )
300 {
301     FIXME("\n");
302     return E_NOTIMPL;
303 }
304
305 static HRESULT WINAPI xmlnodemap__newEnum(
306     IXMLDOMNamedNodeMap *iface,
307     IUnknown** ppUnk)
308 {
309     FIXME("\n");
310     return E_NOTIMPL;
311 }
312
313 static const struct IXMLDOMNamedNodeMapVtbl xmlnodemap_vtbl =
314 {
315     xmlnodemap_QueryInterface,
316     xmlnodemap_AddRef,
317     xmlnodemap_Release,
318     xmlnodemap_GetTypeInfoCount,
319     xmlnodemap_GetTypeInfo,
320     xmlnodemap_GetIDsOfNames,
321     xmlnodemap_Invoke,
322     xmlnodemap_getNamedItem,
323     xmlnodemap_setNamedItem,
324     xmlnodemap_removeNamedItem,
325     xmlnodemap_get_item,
326     xmlnodemap_get_length,
327     xmlnodemap_getQualifiedItem,
328     xmlnodemap_removeQualifiedItem,
329     xmlnodemap_nextNode,
330     xmlnodemap_reset,
331     xmlnodemap__newEnum,
332 };
333
334 static HRESULT WINAPI support_error_QueryInterface(
335     ISupportErrorInfo *iface,
336     REFIID riid, void** ppvObject )
337 {
338     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
339     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
340
341     return IXMLDOMNamedNodeMap_QueryInterface((IXMLDOMNamedNodeMap*)&This->lpVtbl, riid, ppvObject);
342 }
343
344 static ULONG WINAPI support_error_AddRef(
345     ISupportErrorInfo *iface )
346 {
347     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
348     return IXMLDOMNamedNodeMap_AddRef((IXMLDOMNamedNodeMap*)&This->lpVtbl);
349 }
350
351 static ULONG WINAPI support_error_Release(
352     ISupportErrorInfo *iface )
353 {
354     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
355     return IXMLDOMNamedNodeMap_Release((IXMLDOMNamedNodeMap*)&This->lpVtbl);
356 }
357
358 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
359     ISupportErrorInfo *iface,
360     REFIID riid )
361 {
362     FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
363     return S_FALSE;
364 }
365
366 static const struct ISupportErrorInfoVtbl support_error_vtbl =
367 {
368     support_error_QueryInterface,
369     support_error_AddRef,
370     support_error_Release,
371     support_error_InterfaceSupportsErrorInfo
372 };
373
374 IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node )
375 {
376     xmlnodemap *nodemap;
377
378     nodemap = HeapAlloc( GetProcessHeap(), 0, sizeof *nodemap );
379     if ( !nodemap )
380         return NULL;
381
382     nodemap->lpVtbl = &xmlnodemap_vtbl;
383     nodemap->lpSEIVtbl = &support_error_vtbl;
384     nodemap->node = node;
385     nodemap->ref = 1;
386
387     IXMLDOMNode_AddRef( node );
388     /* Since we AddRef a node here, we don't need to call xmldoc_add_ref() */
389
390     return (IXMLDOMNamedNodeMap*) &nodemap->lpVtbl;
391 }
392
393 #endif