msxml3: Reader shouldn't depend on input being properly allocated BSTR string.
[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 #include "msxml2did.h"
38
39 #include "msxml_private.h"
40
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
44
45 #ifdef HAVE_LIBXML2
46
47 typedef struct _xmlnodemap
48 {
49     DispatchEx dispex;
50     IXMLDOMNamedNodeMap IXMLDOMNamedNodeMap_iface;
51     ISupportErrorInfo ISupportErrorInfo_iface;
52     LONG ref;
53
54     xmlNodePtr node;
55     LONG iterator;
56
57     const struct nodemap_funcs *funcs;
58 } xmlnodemap;
59
60 static inline xmlnodemap *impl_from_IXMLDOMNamedNodeMap( IXMLDOMNamedNodeMap *iface )
61 {
62     return CONTAINING_RECORD(iface, xmlnodemap, IXMLDOMNamedNodeMap_iface);
63 }
64
65 static inline xmlnodemap *impl_from_ISupportErrorInfo( ISupportErrorInfo *iface )
66 {
67     return CONTAINING_RECORD(iface, xmlnodemap, ISupportErrorInfo_iface);
68 }
69
70 static HRESULT WINAPI xmlnodemap_QueryInterface(
71     IXMLDOMNamedNodeMap *iface,
72     REFIID riid, void** ppvObject )
73 {
74     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
75     TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
76
77     if( IsEqualGUID( riid, &IID_IUnknown ) ||
78         IsEqualGUID( riid, &IID_IDispatch ) ||
79         IsEqualGUID( riid, &IID_IXMLDOMNamedNodeMap ) )
80     {
81         *ppvObject = iface;
82     }
83     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
84     {
85         return *ppvObject ? S_OK : E_NOINTERFACE;
86     }
87     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
88     {
89         *ppvObject = &This->ISupportErrorInfo_iface;
90     }
91     else
92     {
93         TRACE("interface %s not implemented\n", debugstr_guid(riid));
94         *ppvObject = NULL;
95         return E_NOINTERFACE;
96     }
97
98     IXMLDOMElement_AddRef( iface );
99
100     return S_OK;
101 }
102
103 static ULONG WINAPI xmlnodemap_AddRef(
104     IXMLDOMNamedNodeMap *iface )
105 {
106     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
107     ULONG ref = InterlockedIncrement( &This->ref );
108     TRACE("(%p)->(%d)\n", This, ref);
109     return ref;
110 }
111
112 static ULONG WINAPI xmlnodemap_Release(
113     IXMLDOMNamedNodeMap *iface )
114 {
115     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
116     ULONG ref = InterlockedDecrement( &This->ref );
117
118     TRACE("(%p)->(%d)\n", This, ref);
119     if ( ref == 0 )
120     {
121         xmldoc_release( This->node->doc );
122         release_dispex(&This->dispex);
123         heap_free( This );
124     }
125
126     return ref;
127 }
128
129 static HRESULT WINAPI xmlnodemap_GetTypeInfoCount(
130     IXMLDOMNamedNodeMap *iface,
131     UINT* pctinfo )
132 {
133     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
134     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
135 }
136
137 static HRESULT WINAPI xmlnodemap_GetTypeInfo(
138     IXMLDOMNamedNodeMap *iface,
139     UINT iTInfo, LCID lcid,
140     ITypeInfo** ppTInfo )
141 {
142     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
143     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
144         iTInfo, lcid, ppTInfo);
145 }
146
147 static HRESULT WINAPI xmlnodemap_GetIDsOfNames(
148     IXMLDOMNamedNodeMap *iface,
149     REFIID riid, LPOLESTR* rgszNames,
150     UINT cNames, LCID lcid, DISPID* rgDispId )
151 {
152     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
153     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
154         riid, rgszNames, cNames, lcid, rgDispId);
155 }
156
157 static HRESULT WINAPI xmlnodemap_Invoke(
158     IXMLDOMNamedNodeMap *iface,
159     DISPID dispIdMember, REFIID riid, LCID lcid,
160     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
161     EXCEPINFO* pExcepInfo, UINT* puArgErr )
162 {
163     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
164     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
165         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
166 }
167
168 static HRESULT WINAPI xmlnodemap_getNamedItem(
169     IXMLDOMNamedNodeMap *iface,
170     BSTR name,
171     IXMLDOMNode** item)
172 {
173     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
174
175     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), item );
176
177     return This->funcs->get_named_item(This->node, name, item);
178 }
179
180 static HRESULT WINAPI xmlnodemap_setNamedItem(
181     IXMLDOMNamedNodeMap *iface,
182     IXMLDOMNode* newItem,
183     IXMLDOMNode** namedItem)
184 {
185     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
186
187     TRACE("(%p)->(%p %p)\n", This, newItem, namedItem );
188
189     return This->funcs->set_named_item(This->node, newItem, namedItem);
190 }
191
192 static HRESULT WINAPI xmlnodemap_removeNamedItem(
193     IXMLDOMNamedNodeMap *iface,
194     BSTR name,
195     IXMLDOMNode** namedItem)
196 {
197     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
198
199     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), namedItem );
200
201     return This->funcs->remove_named_item(This->node, name, namedItem);
202 }
203
204 static HRESULT WINAPI xmlnodemap_get_item(
205     IXMLDOMNamedNodeMap *iface,
206     LONG index,
207     IXMLDOMNode** item)
208 {
209     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
210
211     TRACE("(%p)->(%d %p)\n", This, index, item);
212
213     return This->funcs->get_item(This->node, index, item);
214 }
215
216 static HRESULT WINAPI xmlnodemap_get_length(
217     IXMLDOMNamedNodeMap *iface,
218     LONG *length)
219 {
220     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
221
222     TRACE("(%p)->(%p)\n", This, length);
223
224     return This->funcs->get_length(This->node, length);
225 }
226
227 static HRESULT WINAPI xmlnodemap_getQualifiedItem(
228     IXMLDOMNamedNodeMap *iface,
229     BSTR baseName,
230     BSTR namespaceURI,
231     IXMLDOMNode** item)
232 {
233     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
234
235     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(baseName), debugstr_w(namespaceURI), item);
236
237     return This->funcs->get_qualified_item(This->node, baseName, namespaceURI, item);
238 }
239
240 static HRESULT WINAPI xmlnodemap_removeQualifiedItem(
241     IXMLDOMNamedNodeMap *iface,
242     BSTR baseName,
243     BSTR namespaceURI,
244     IXMLDOMNode** item)
245 {
246     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
247
248     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(baseName), debugstr_w(namespaceURI), item);
249
250     return This->funcs->remove_qualified_item(This->node, baseName, namespaceURI, item);
251 }
252
253 static HRESULT WINAPI xmlnodemap_nextNode(
254     IXMLDOMNamedNodeMap *iface,
255     IXMLDOMNode** nextItem)
256 {
257     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
258
259     TRACE("(%p)->(%p: %d)\n", This, nextItem, This->iterator);
260
261     return This->funcs->next_node(This->node, &This->iterator, nextItem);
262 }
263
264 static HRESULT WINAPI xmlnodemap_reset(
265     IXMLDOMNamedNodeMap *iface )
266 {
267     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
268
269     TRACE("(%p)->(%d)\n", This, This->iterator);
270
271     This->iterator = 0;
272
273     return S_OK;
274 }
275
276 static HRESULT WINAPI xmlnodemap__newEnum(
277     IXMLDOMNamedNodeMap *iface,
278     IUnknown** ppUnk)
279 {
280     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( iface );
281     FIXME("(%p)->(%p)\n", This, ppUnk);
282     return E_NOTIMPL;
283 }
284
285 static const struct IXMLDOMNamedNodeMapVtbl XMLDOMNamedNodeMapVtbl =
286 {
287     xmlnodemap_QueryInterface,
288     xmlnodemap_AddRef,
289     xmlnodemap_Release,
290     xmlnodemap_GetTypeInfoCount,
291     xmlnodemap_GetTypeInfo,
292     xmlnodemap_GetIDsOfNames,
293     xmlnodemap_Invoke,
294     xmlnodemap_getNamedItem,
295     xmlnodemap_setNamedItem,
296     xmlnodemap_removeNamedItem,
297     xmlnodemap_get_item,
298     xmlnodemap_get_length,
299     xmlnodemap_getQualifiedItem,
300     xmlnodemap_removeQualifiedItem,
301     xmlnodemap_nextNode,
302     xmlnodemap_reset,
303     xmlnodemap__newEnum,
304 };
305
306 static HRESULT WINAPI support_error_QueryInterface(
307     ISupportErrorInfo *iface,
308     REFIID riid, void** ppvObject )
309 {
310     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
311     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
312     return IXMLDOMNamedNodeMap_QueryInterface(&This->IXMLDOMNamedNodeMap_iface, riid, ppvObject);
313 }
314
315 static ULONG WINAPI support_error_AddRef(
316     ISupportErrorInfo *iface )
317 {
318     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
319     return IXMLDOMNamedNodeMap_AddRef(&This->IXMLDOMNamedNodeMap_iface);
320 }
321
322 static ULONG WINAPI support_error_Release(
323     ISupportErrorInfo *iface )
324 {
325     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
326     return IXMLDOMNamedNodeMap_Release(&This->IXMLDOMNamedNodeMap_iface);
327 }
328
329 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
330     ISupportErrorInfo *iface,
331     REFIID riid )
332 {
333     xmlnodemap *This = impl_from_ISupportErrorInfo( iface );
334     TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
335     return IsEqualGUID(riid, &IID_IXMLDOMNamedNodeMap) ? S_OK : S_FALSE;
336 }
337
338 static const struct ISupportErrorInfoVtbl SupportErrorInfoVtbl =
339 {
340     support_error_QueryInterface,
341     support_error_AddRef,
342     support_error_Release,
343     support_error_InterfaceSupportsErrorInfo
344 };
345
346 static HRESULT xmlnodemap_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
347 {
348     WCHAR *ptr;
349     int idx = 0;
350
351     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
352         idx = idx*10 + (*ptr-'0');
353     if(*ptr)
354         return DISP_E_UNKNOWNNAME;
355
356     *dispid = DISPID_DOM_COLLECTION_BASE + idx;
357     TRACE("ret %x\n", *dispid);
358     return S_OK;
359 }
360
361 static HRESULT xmlnodemap_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
362         VARIANT *res, EXCEPINFO *ei)
363 {
364     xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( (IXMLDOMNamedNodeMap*)iface );
365
366     TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
367
368     V_VT(res) = VT_DISPATCH;
369     V_DISPATCH(res) = NULL;
370
371     if (id < DISPID_DOM_COLLECTION_BASE || id > DISPID_DOM_COLLECTION_MAX)
372         return DISP_E_UNKNOWNNAME;
373
374     switch(flags)
375     {
376         case INVOKE_PROPERTYGET:
377         {
378             IXMLDOMNode *disp = NULL;
379
380             IXMLDOMNamedNodeMap_get_item(&This->IXMLDOMNamedNodeMap_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
381             V_DISPATCH(res) = (IDispatch*)disp;
382             break;
383         }
384         default:
385         {
386             FIXME("unimplemented flags %x\n", flags);
387             break;
388         }
389     }
390
391     TRACE("ret %p\n", V_DISPATCH(res));
392
393     return S_OK;
394 }
395
396 static const dispex_static_data_vtbl_t xmlnodemap_dispex_vtbl = {
397     xmlnodemap_get_dispid,
398     xmlnodemap_invoke
399 };
400
401 static const tid_t xmlnodemap_iface_tids[] = {
402     IXMLDOMNamedNodeMap_tid,
403     0
404 };
405
406 static dispex_static_data_t xmlnodemap_dispex = {
407     &xmlnodemap_dispex_vtbl,
408     IXMLDOMNamedNodeMap_tid,
409     NULL,
410     xmlnodemap_iface_tids
411 };
412
413 IXMLDOMNamedNodeMap *create_nodemap(xmlNodePtr node, const struct nodemap_funcs *funcs)
414 {
415     xmlnodemap *This;
416
417     This = heap_alloc( sizeof *This );
418     if ( !This )
419         return NULL;
420
421     This->IXMLDOMNamedNodeMap_iface.lpVtbl = &XMLDOMNamedNodeMapVtbl;
422     This->ISupportErrorInfo_iface.lpVtbl = &SupportErrorInfoVtbl;
423     This->node = node;
424     This->ref = 1;
425     This->iterator = 0;
426     This->funcs = funcs;
427
428     init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNamedNodeMap_iface, &xmlnodemap_dispex);
429
430     xmldoc_add_ref(node->doc);
431
432     return &This->IXMLDOMNamedNodeMap_iface;
433 }
434
435 #endif