msxml3: Accept lexical handler parameter entities switch.
[wine] / dlls / msxml3 / mxnamespace.c
1 /*
2  *    IMXNamespaceManager implementation
3  *
4  * Copyright 2011 Nikolay Sivov for CodeWeavers
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 #define COBJMACROS
22 #define NONAMELESSUNION
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #ifdef HAVE_LIBXML2
28 # include <libxml/parser.h>
29 # include <libxml/xmlerror.h>
30 # include <libxml/encoding.h>
31 #endif
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "ole2.h"
37 #include "msxml6.h"
38
39 #include "msxml_private.h"
40
41 #include "wine/debug.h"
42 #include "wine/list.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
45
46 struct ns
47 {
48     BSTR prefix;
49     BSTR uri;
50 };
51
52 struct nscontext
53 {
54     struct list entry;
55
56     struct ns *ns;
57     int   count;
58     int   max_alloc;
59 };
60
61 #define DEFAULT_PREFIX_ALLOC_COUNT 16
62
63 static const WCHAR xmlW[] = {'x','m','l',0};
64 static const WCHAR xmluriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g',
65     '/','X','M','L','/','1','9','9','8','/','n','a','m','e','s','p','a','c','e',0};
66
67 typedef struct
68 {
69     IMXNamespaceManager   IMXNamespaceManager_iface;
70     IVBMXNamespaceManager IVBMXNamespaceManager_iface;
71     LONG ref;
72
73     struct list ctxts;
74
75     VARIANT_BOOL override;
76 } namespacemanager;
77
78 static inline namespacemanager *impl_from_IMXNamespaceManager( IMXNamespaceManager *iface )
79 {
80     return CONTAINING_RECORD(iface, namespacemanager, IMXNamespaceManager_iface);
81 }
82
83 static inline namespacemanager *impl_from_IVBMXNamespaceManager( IVBMXNamespaceManager *iface )
84 {
85     return CONTAINING_RECORD(iface, namespacemanager, IVBMXNamespaceManager_iface);
86 }
87
88 static HRESULT declare_prefix(namespacemanager *This, const WCHAR *prefix, const WCHAR *uri)
89 {
90     struct nscontext *ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry);
91     static const WCHAR emptyW[] = {0};
92     struct ns *ns;
93     int i;
94
95     if (ctxt->count == ctxt->max_alloc)
96     {
97         ctxt->max_alloc *= 2;
98         ctxt->ns = heap_realloc(ctxt->ns, ctxt->max_alloc*sizeof(*ctxt->ns));
99     }
100
101     if (!prefix) prefix = emptyW;
102
103     ns = NULL;
104     for (i = 0; i < ctxt->count; i++)
105         if (!strcmpW(ctxt->ns[i].prefix, prefix))
106         {
107             ns = &ctxt->ns[i];
108             break;
109         }
110
111     if (ns)
112     {
113         if (This->override == VARIANT_TRUE)
114         {
115             SysFreeString(ns->uri);
116             ns->uri = SysAllocString(uri);
117             return S_FALSE;
118         }
119         else
120             return E_FAIL;
121     }
122     else
123     {
124         ctxt->ns[ctxt->count].prefix = SysAllocString(prefix);
125         ctxt->ns[ctxt->count].uri = SysAllocString(uri);
126         ctxt->count++;
127     }
128
129     return S_OK;
130 }
131
132 /* returned stored pointer, caller needs to copy it */
133 static HRESULT get_declared_prefix_idx(const struct nscontext *ctxt, LONG index, BSTR *prefix)
134 {
135     *prefix = NULL;
136
137     if (index >= ctxt->count || index < 0) return E_FAIL;
138
139     if (index > 0) index = ctxt->count - index;
140     *prefix = ctxt->ns[index].prefix;
141
142     return S_OK;
143 }
144
145 static HRESULT get_uri_from_prefix(const struct nscontext *ctxt, const WCHAR *prefix, BSTR *uri)
146 {
147     int i;
148
149     for (i = 0; i < ctxt->count; i++)
150         if (!strcmpW(ctxt->ns[i].prefix, prefix))
151         {
152             *uri = ctxt->ns[i].uri;
153             return S_OK;
154         }
155
156     *uri = NULL;
157     return S_FALSE;
158 }
159
160 static struct nscontext* alloc_ns_context(void)
161 {
162     struct nscontext *ctxt;
163
164     ctxt = heap_alloc(sizeof(*ctxt));
165     if (!ctxt) return NULL;
166
167     ctxt->count = 0;
168     ctxt->max_alloc = DEFAULT_PREFIX_ALLOC_COUNT;
169     ctxt->ns = heap_alloc(ctxt->max_alloc*sizeof(*ctxt->ns));
170
171     /* first allocated prefix is always 'xml' */
172     ctxt->ns[0].prefix = SysAllocString(xmlW);
173     ctxt->ns[0].uri = SysAllocString(xmluriW);
174     ctxt->count++;
175
176     return ctxt;
177 }
178
179 static void free_ns_context(struct nscontext *ctxt)
180 {
181     int i;
182
183     for (i = 0; i < ctxt->count; i++)
184     {
185         SysFreeString(ctxt->ns[i].prefix);
186         SysFreeString(ctxt->ns[i].uri);
187     }
188
189     heap_free(ctxt->ns);
190     heap_free(ctxt);
191 }
192
193 static HRESULT WINAPI namespacemanager_QueryInterface(IMXNamespaceManager *iface, REFIID riid, void **ppvObject)
194 {
195     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
196     return IVBMXNamespaceManager_QueryInterface(&This->IVBMXNamespaceManager_iface, riid, ppvObject);
197 }
198
199 static ULONG WINAPI namespacemanager_AddRef(IMXNamespaceManager *iface)
200 {
201     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
202     return IVBMXNamespaceManager_AddRef(&This->IVBMXNamespaceManager_iface);
203 }
204
205 static ULONG WINAPI namespacemanager_Release(IMXNamespaceManager *iface)
206 {
207     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
208     return IVBMXNamespaceManager_Release(&This->IVBMXNamespaceManager_iface);
209 }
210
211 static HRESULT WINAPI namespacemanager_putAllowOverride(IMXNamespaceManager *iface,
212     VARIANT_BOOL override)
213 {
214     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
215     return IVBMXNamespaceManager_put_allowOverride(&This->IVBMXNamespaceManager_iface, override);
216 }
217
218 static HRESULT WINAPI namespacemanager_getAllowOverride(IMXNamespaceManager *iface,
219     VARIANT_BOOL *override)
220 {
221     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
222     return IVBMXNamespaceManager_get_allowOverride(&This->IVBMXNamespaceManager_iface, override);
223 }
224
225 static HRESULT WINAPI namespacemanager_reset(IMXNamespaceManager *iface)
226 {
227     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
228     return IVBMXNamespaceManager_reset(&This->IVBMXNamespaceManager_iface);
229 }
230
231 static HRESULT WINAPI namespacemanager_pushContext(IMXNamespaceManager *iface)
232 {
233     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
234     return IVBMXNamespaceManager_pushContext(&This->IVBMXNamespaceManager_iface);
235 }
236
237 static HRESULT WINAPI namespacemanager_pushNodeContext(IMXNamespaceManager *iface,
238     IXMLDOMNode *node, VARIANT_BOOL deep)
239 {
240     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
241     return IVBMXNamespaceManager_pushNodeContext(&This->IVBMXNamespaceManager_iface, node, deep);
242 }
243
244 static HRESULT WINAPI namespacemanager_popContext(IMXNamespaceManager *iface)
245 {
246     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
247     return IVBMXNamespaceManager_popContext(&This->IVBMXNamespaceManager_iface);
248 }
249
250 static HRESULT WINAPI namespacemanager_declarePrefix(IMXNamespaceManager *iface,
251     const WCHAR *prefix, const WCHAR *namespaceURI)
252 {
253     static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
254
255     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
256
257     TRACE("(%p)->(%s %s)\n", This, debugstr_w(prefix), debugstr_w(namespaceURI));
258
259     if (prefix && (!strcmpW(prefix, xmlW) || !strcmpW(prefix, xmlnsW) || !namespaceURI))
260         return E_INVALIDARG;
261
262     return declare_prefix(This, prefix, namespaceURI);
263 }
264
265 static HRESULT WINAPI namespacemanager_getDeclaredPrefix(IMXNamespaceManager *iface,
266     LONG index, WCHAR *prefix, int *prefix_len)
267 {
268     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
269     struct nscontext *ctxt;
270     HRESULT hr;
271     BSTR prfx;
272
273     TRACE("(%p)->(%d %p %p)\n", This, index, prefix, prefix_len);
274
275     if (!prefix_len) return E_POINTER;
276
277     ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry);
278     hr = get_declared_prefix_idx(ctxt, index, &prfx);
279     if (hr != S_OK) return hr;
280
281     if (prefix)
282     {
283         if (*prefix_len < (INT)SysStringLen(prfx)) return E_XML_BUFFERTOOSMALL;
284         strcpyW(prefix, prfx);
285     }
286
287     *prefix_len = SysStringLen(prfx);
288
289     return S_OK;
290 }
291
292 static HRESULT WINAPI namespacemanager_getPrefix(IMXNamespaceManager *iface,
293     const WCHAR *uri, LONG index, WCHAR *prefix, int *prefix_len)
294 {
295     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
296     FIXME("(%p)->(%s %d %p %p): stub\n", This, debugstr_w(uri), index, prefix, prefix_len);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI namespacemanager_getURI(IMXNamespaceManager *iface,
301     const WCHAR *prefix, IXMLDOMNode *node, WCHAR *uri, int *uri_len)
302 {
303     namespacemanager *This = impl_from_IMXNamespaceManager( iface );
304     struct nscontext *ctxt;
305     HRESULT hr;
306     BSTR urib;
307
308     TRACE("(%p)->(%s %p %p %p)\n", This, debugstr_w(prefix), node, uri, uri_len);
309
310     if (!prefix) return E_INVALIDARG;
311     if (!uri_len) return E_POINTER;
312
313     if (node)
314     {
315         FIXME("namespaces from DOM node not supported\n");
316         return E_NOTIMPL;
317     }
318
319     ctxt = LIST_ENTRY(list_head(&This->ctxts), struct nscontext, entry);
320     hr = get_uri_from_prefix(ctxt, prefix, &urib);
321     if (hr == S_OK)
322     {
323         if (uri)
324         {
325            if (*uri_len < (INT)SysStringLen(urib)) return E_XML_BUFFERTOOSMALL;
326            strcpyW(uri, urib);
327         }
328     }
329     else
330         if (uri) *uri = 0;
331
332     *uri_len = SysStringLen(urib);
333
334     return hr;
335 }
336
337 static const struct IMXNamespaceManagerVtbl MXNamespaceManagerVtbl =
338 {
339     namespacemanager_QueryInterface,
340     namespacemanager_AddRef,
341     namespacemanager_Release,
342     namespacemanager_putAllowOverride,
343     namespacemanager_getAllowOverride,
344     namespacemanager_reset,
345     namespacemanager_pushContext,
346     namespacemanager_pushNodeContext,
347     namespacemanager_popContext,
348     namespacemanager_declarePrefix,
349     namespacemanager_getDeclaredPrefix,
350     namespacemanager_getPrefix,
351     namespacemanager_getURI
352 };
353
354 static HRESULT WINAPI vbnamespacemanager_QueryInterface(IVBMXNamespaceManager *iface, REFIID riid, void **ppvObject)
355 {
356     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
357     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
358
359     if ( IsEqualGUID( riid, &IID_IMXNamespaceManager) ||
360          IsEqualGUID( riid, &IID_IUnknown) )
361     {
362         *ppvObject = &This->IMXNamespaceManager_iface;
363     }
364     else if ( IsEqualGUID( riid, &IID_IVBMXNamespaceManager) ||
365               IsEqualGUID( riid, &IID_IDispatch) )
366     {
367         *ppvObject = &This->IVBMXNamespaceManager_iface;
368     }
369     else
370     {
371         TRACE("Unsupported interface %s\n", debugstr_guid(riid));
372         *ppvObject = NULL;
373         return E_NOINTERFACE;
374     }
375
376     IVBMXNamespaceManager_AddRef( iface );
377
378     return S_OK;
379 }
380
381 static ULONG WINAPI vbnamespacemanager_AddRef(IVBMXNamespaceManager *iface)
382 {
383     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
384     ULONG ref = InterlockedIncrement( &This->ref );
385     TRACE("(%p)->(%u)\n", This, ref );
386     return ref;
387 }
388
389 static ULONG WINAPI vbnamespacemanager_Release(IVBMXNamespaceManager *iface)
390 {
391     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
392     ULONG ref = InterlockedDecrement( &This->ref );
393
394     TRACE("(%p)->(%u)\n", This, ref );
395
396     if ( ref == 0 )
397     {
398         struct nscontext *ctxt, *ctxt2;
399
400         LIST_FOR_EACH_ENTRY_SAFE(ctxt, ctxt2, &This->ctxts, struct nscontext, entry)
401         {
402             list_remove(&ctxt->entry);
403             free_ns_context(ctxt);
404         }
405
406         heap_free( This );
407     }
408
409     return ref;
410 }
411
412 static HRESULT WINAPI vbnamespacemanager_GetTypeInfoCount(IVBMXNamespaceManager *iface, UINT *pctinfo)
413 {
414     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
415
416     TRACE("(%p)->(%p)\n", This, pctinfo);
417     *pctinfo = 1;
418
419     return S_OK;
420 }
421
422 static HRESULT WINAPI vbnamespacemanager_GetTypeInfo(IVBMXNamespaceManager *iface, UINT iTInfo,
423         LCID lcid, ITypeInfo **ppTInfo)
424 {
425     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
426
427     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
428
429     return get_typeinfo(IVBMXNamespaceManager_tid, ppTInfo);
430 }
431
432 static HRESULT WINAPI vbnamespacemanager_GetIDsOfNames(IVBMXNamespaceManager *iface, REFIID riid,
433         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
434 {
435     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
436     ITypeInfo *typeinfo;
437     HRESULT hr;
438
439     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
440           lcid, rgDispId);
441
442     if(!rgszNames || cNames == 0 || !rgDispId)
443         return E_INVALIDARG;
444
445     hr = get_typeinfo(IVBMXNamespaceManager_tid, &typeinfo);
446     if(SUCCEEDED(hr))
447     {
448         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
449         ITypeInfo_Release(typeinfo);
450     }
451
452     return hr;
453 }
454
455 static HRESULT WINAPI vbnamespacemanager_Invoke(IVBMXNamespaceManager *iface, DISPID dispIdMember, REFIID riid,
456         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
457         EXCEPINFO *pExcepInfo, UINT *puArgErr)
458 {
459     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
460     ITypeInfo *typeinfo;
461     HRESULT hr;
462
463     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
464           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
465
466     hr = get_typeinfo(IVBMXNamespaceManager_tid, &typeinfo);
467     if(SUCCEEDED(hr))
468     {
469         hr = ITypeInfo_Invoke(typeinfo, &This->IVBMXNamespaceManager_iface, dispIdMember, wFlags,
470                 pDispParams, pVarResult, pExcepInfo, puArgErr);
471         ITypeInfo_Release(typeinfo);
472     }
473
474     return hr;
475 }
476
477 static HRESULT WINAPI vbnamespacemanager_put_allowOverride(IVBMXNamespaceManager *iface,
478     VARIANT_BOOL override)
479 {
480     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
481
482     TRACE("(%p)->(%d)\n", This, override);
483     This->override = override;
484
485     return S_OK;
486 }
487
488 static HRESULT WINAPI vbnamespacemanager_get_allowOverride(IVBMXNamespaceManager *iface,
489     VARIANT_BOOL *override)
490 {
491     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
492
493     TRACE("(%p)->(%p)\n", This, override);
494
495     if (!override) return E_POINTER;
496     *override = This->override;
497
498     return S_OK;
499 }
500
501 static HRESULT WINAPI vbnamespacemanager_reset(IVBMXNamespaceManager *iface)
502 {
503     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
504     FIXME("(%p): stub\n", This);
505     return E_NOTIMPL;
506 }
507
508 static HRESULT WINAPI vbnamespacemanager_pushContext(IVBMXNamespaceManager *iface)
509 {
510     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
511     FIXME("(%p): stub\n", This);
512     return E_NOTIMPL;
513 }
514
515 static HRESULT WINAPI vbnamespacemanager_pushNodeContext(IVBMXNamespaceManager *iface,
516     IXMLDOMNode *node, VARIANT_BOOL deep)
517 {
518     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
519     FIXME("(%p)->(%p %d): stub\n", This, node, deep);
520     return E_NOTIMPL;
521 }
522
523 static HRESULT WINAPI vbnamespacemanager_popContext(IVBMXNamespaceManager *iface)
524 {
525     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
526     FIXME("(%p): stub\n", This);
527     return E_NOTIMPL;
528 }
529
530 static HRESULT WINAPI vbnamespacemanager_declarePrefix(IVBMXNamespaceManager *iface,
531     BSTR prefix, BSTR namespaceURI)
532 {
533     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
534     return IMXNamespaceManager_declarePrefix(&This->IMXNamespaceManager_iface, prefix, namespaceURI);
535 }
536
537 static HRESULT WINAPI vbnamespacemanager_getDeclaredPrefixes(IVBMXNamespaceManager *iface,
538     IMXNamespacePrefixes** prefixes)
539 {
540     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
541     FIXME("(%p)->(%p): stub\n", This, prefixes);
542     return E_NOTIMPL;
543 }
544
545 static HRESULT WINAPI vbnamespacemanager_getPrefixes(IVBMXNamespaceManager *iface,
546     BSTR namespaceURI, IMXNamespacePrefixes** prefixes)
547 {
548     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
549     FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), prefixes);
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI vbnamespacemanager_getURI(IVBMXNamespaceManager *iface,
554     BSTR prefix, VARIANT* uri)
555 {
556     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
557     FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(prefix), uri);
558     return E_NOTIMPL;
559 }
560
561 static HRESULT WINAPI vbnamespacemanager_getURIFromNode(IVBMXNamespaceManager *iface,
562     BSTR prefix, IXMLDOMNode *node, VARIANT *uri)
563 {
564     namespacemanager *This = impl_from_IVBMXNamespaceManager( iface );
565     FIXME("(%p)->(%s %p %p): stub\n", This, debugstr_w(prefix), node, uri);
566     return E_NOTIMPL;
567 }
568
569 static const struct IVBMXNamespaceManagerVtbl VBMXNamespaceManagerVtbl =
570 {
571     vbnamespacemanager_QueryInterface,
572     vbnamespacemanager_AddRef,
573     vbnamespacemanager_Release,
574     vbnamespacemanager_GetTypeInfoCount,
575     vbnamespacemanager_GetTypeInfo,
576     vbnamespacemanager_GetIDsOfNames,
577     vbnamespacemanager_Invoke,
578     vbnamespacemanager_put_allowOverride,
579     vbnamespacemanager_get_allowOverride,
580     vbnamespacemanager_reset,
581     vbnamespacemanager_pushContext,
582     vbnamespacemanager_pushNodeContext,
583     vbnamespacemanager_popContext,
584     vbnamespacemanager_declarePrefix,
585     vbnamespacemanager_getDeclaredPrefixes,
586     vbnamespacemanager_getPrefixes,
587     vbnamespacemanager_getURI,
588     vbnamespacemanager_getURIFromNode
589 };
590
591 HRESULT MXNamespaceManager_create(IUnknown *outer, void **obj)
592 {
593     namespacemanager *ns;
594     struct nscontext *ctxt;
595
596     TRACE("(%p, %p)\n", outer, obj);
597
598     ns = heap_alloc( sizeof (*ns) );
599     if( !ns )
600         return E_OUTOFMEMORY;
601
602     ns->IMXNamespaceManager_iface.lpVtbl = &MXNamespaceManagerVtbl;
603     ns->IVBMXNamespaceManager_iface.lpVtbl = &VBMXNamespaceManagerVtbl;
604     ns->ref = 1;
605
606     list_init(&ns->ctxts);
607     ctxt = alloc_ns_context();
608     list_add_head(&ns->ctxts, &ctxt->entry);
609
610     ns->override = VARIANT_TRUE;
611
612     *obj = &ns->IMXNamespaceManager_iface;
613
614     TRACE("returning iface %p\n", *obj);
615
616     return S_OK;
617 }