mshtml: Ignore navigation failures from detached bindings.
[wine] / dlls / msxml3 / stylesheet.c
1 /*
2  *    XSLTemplate/XSLProcessor support
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
23 #include "config.h"
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 "ole2.h"
35 #include "msxml6.h"
36
37 #include "msxml_private.h"
38
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
42
43 typedef struct
44 {
45     DispatchEx dispex;
46     IXSLTemplate IXSLTemplate_iface;
47     LONG ref;
48
49     IXMLDOMNode *node;
50 } xsltemplate;
51
52 typedef struct
53 {
54     DispatchEx dispex;
55     IXSLProcessor IXSLProcessor_iface;
56     LONG ref;
57
58     xsltemplate *stylesheet;
59     IXMLDOMNode *input;
60
61     IStream     *output;
62     BSTR         outstr;
63 } xslprocessor;
64
65 static HRESULT XSLProcessor_create(xsltemplate*, IXSLProcessor**);
66
67 static inline xsltemplate *impl_from_IXSLTemplate( IXSLTemplate *iface )
68 {
69     return CONTAINING_RECORD(iface, xsltemplate, IXSLTemplate_iface);
70 }
71
72 static inline xslprocessor *impl_from_IXSLProcessor( IXSLProcessor *iface )
73 {
74     return CONTAINING_RECORD(iface, xslprocessor, IXSLProcessor_iface);
75 }
76
77 static void xsltemplate_set_node( xsltemplate *This, IXMLDOMNode *node )
78 {
79     if (This->node) IXMLDOMNode_Release(This->node);
80     This->node = node;
81     if (node) IXMLDOMNode_AddRef(node);
82 }
83
84 static HRESULT WINAPI xsltemplate_QueryInterface(
85     IXSLTemplate *iface,
86     REFIID riid,
87     void** ppvObject )
88 {
89     xsltemplate *This = impl_from_IXSLTemplate( iface );
90     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
91
92     if ( IsEqualGUID( riid, &IID_IXSLTemplate ) ||
93          IsEqualGUID( riid, &IID_IDispatch ) ||
94          IsEqualGUID( riid, &IID_IUnknown ) )
95     {
96         *ppvObject = iface;
97     }
98     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
99     {
100         return *ppvObject ? S_OK : E_NOINTERFACE;
101     }
102     else
103     {
104         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
105         *ppvObject = NULL;
106         return E_NOINTERFACE;
107     }
108
109     IUnknown_AddRef((IUnknown*)*ppvObject);
110     return S_OK;
111 }
112
113 static ULONG WINAPI xsltemplate_AddRef( IXSLTemplate *iface )
114 {
115     xsltemplate *This = impl_from_IXSLTemplate( iface );
116     ULONG ref = InterlockedIncrement( &This->ref );
117     TRACE("(%p)->(%d)\n", This, ref);
118     return ref;
119 }
120
121 static ULONG WINAPI xsltemplate_Release( IXSLTemplate *iface )
122 {
123     xsltemplate *This = impl_from_IXSLTemplate( iface );
124     ULONG ref = InterlockedDecrement( &This->ref );
125
126     TRACE("(%p)->(%d)\n", This, ref);
127     if ( ref == 0 )
128     {
129         if (This->node) IXMLDOMNode_Release( This->node );
130         release_dispex(&This->dispex);
131         heap_free( This );
132     }
133
134     return ref;
135 }
136
137 static HRESULT WINAPI xsltemplate_GetTypeInfoCount( IXSLTemplate *iface, UINT* pctinfo )
138 {
139     xsltemplate *This = impl_from_IXSLTemplate( iface );
140     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
141 }
142
143 static HRESULT WINAPI xsltemplate_GetTypeInfo(
144     IXSLTemplate *iface,
145     UINT iTInfo, LCID lcid,
146     ITypeInfo** ppTInfo )
147 {
148     xsltemplate *This = impl_from_IXSLTemplate( iface );
149     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
150         iTInfo, lcid, ppTInfo);
151 }
152
153 static HRESULT WINAPI xsltemplate_GetIDsOfNames(
154     IXSLTemplate *iface,
155     REFIID riid, LPOLESTR* rgszNames,
156     UINT cNames, LCID lcid, DISPID* rgDispId )
157 {
158     xsltemplate *This = impl_from_IXSLTemplate( iface );
159     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
160         riid, rgszNames, cNames, lcid, rgDispId);
161 }
162
163 static HRESULT WINAPI xsltemplate_Invoke(
164     IXSLTemplate *iface,
165     DISPID dispIdMember, REFIID riid, LCID lcid,
166     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
167     EXCEPINFO* pExcepInfo, UINT* puArgErr )
168 {
169     xsltemplate *This = impl_from_IXSLTemplate( iface );
170     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
171         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
172 }
173
174 static HRESULT WINAPI xsltemplate_putref_stylesheet( IXSLTemplate *iface,
175     IXMLDOMNode *node)
176 {
177     xsltemplate *This = impl_from_IXSLTemplate( iface );
178
179     TRACE("(%p)->(%p)\n", This, node);
180
181     if (!node)
182     {
183         xsltemplate_set_node(This, NULL);
184         return S_OK;
185     }
186
187     /* FIXME: test for document type */
188     xsltemplate_set_node(This, node);
189
190     return S_OK;
191 }
192
193 static HRESULT WINAPI xsltemplate_get_stylesheet( IXSLTemplate *iface,
194     IXMLDOMNode **node)
195 {
196     xsltemplate *This = impl_from_IXSLTemplate( iface );
197
198     FIXME("(%p)->(%p): stub\n", This, node);
199     return E_NOTIMPL;
200 }
201
202 static HRESULT WINAPI xsltemplate_createProcessor( IXSLTemplate *iface,
203     IXSLProcessor **processor)
204 {
205     xsltemplate *This = impl_from_IXSLTemplate( iface );
206
207     TRACE("(%p)->(%p)\n", This, processor);
208
209     if (!processor) return E_INVALIDARG;
210
211     return XSLProcessor_create(This, processor);
212 }
213
214 static const struct IXSLTemplateVtbl XSLTemplateVtbl =
215 {
216     xsltemplate_QueryInterface,
217     xsltemplate_AddRef,
218     xsltemplate_Release,
219     xsltemplate_GetTypeInfoCount,
220     xsltemplate_GetTypeInfo,
221     xsltemplate_GetIDsOfNames,
222     xsltemplate_Invoke,
223     xsltemplate_putref_stylesheet,
224     xsltemplate_get_stylesheet,
225     xsltemplate_createProcessor
226 };
227
228 static const tid_t xsltemplate_iface_tids[] = {
229     IXSLTemplate_tid,
230     0
231 };
232
233 static dispex_static_data_t xsltemplate_dispex = {
234     NULL,
235     IXSLTemplate_tid,
236     NULL,
237     xsltemplate_iface_tids
238 };
239
240 HRESULT XSLTemplate_create(IUnknown *outer, void **ppObj)
241 {
242     xsltemplate *This;
243
244     TRACE("(%p, %p)\n", outer, ppObj);
245
246     if(outer) FIXME("support aggregation, outer\n");
247
248     This = heap_alloc( sizeof (*This) );
249     if(!This)
250         return E_OUTOFMEMORY;
251
252     This->IXSLTemplate_iface.lpVtbl = &XSLTemplateVtbl;
253     This->ref = 1;
254     This->node = NULL;
255     init_dispex(&This->dispex, (IUnknown*)&This->IXSLTemplate_iface, &xsltemplate_dispex);
256
257     *ppObj = &This->IXSLTemplate_iface;
258
259     TRACE("returning iface %p\n", *ppObj);
260
261     return S_OK;
262 }
263
264 /*** IXSLProcessor ***/
265 static HRESULT WINAPI xslprocessor_QueryInterface(
266     IXSLProcessor *iface,
267     REFIID riid,
268     void** ppvObject )
269 {
270     xslprocessor *This = impl_from_IXSLProcessor( iface );
271     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
272
273     if ( IsEqualGUID( riid, &IID_IXSLProcessor ) ||
274          IsEqualGUID( riid, &IID_IDispatch ) ||
275          IsEqualGUID( riid, &IID_IUnknown ) )
276     {
277         *ppvObject = iface;
278     }
279     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
280     {
281         return *ppvObject ? S_OK : E_NOINTERFACE;
282     }
283     else
284     {
285         FIXME("Unsupported interface %s\n", debugstr_guid(riid));
286         *ppvObject = NULL;
287         return E_NOINTERFACE;
288     }
289
290     IUnknown_AddRef((IUnknown*)*ppvObject);
291     return S_OK;
292 }
293
294 static ULONG WINAPI xslprocessor_AddRef( IXSLProcessor *iface )
295 {
296     xslprocessor *This = impl_from_IXSLProcessor( iface );
297     ULONG ref = InterlockedIncrement( &This->ref );
298     TRACE("(%p)->(%d)\n", This, ref);
299     return ref;
300 }
301
302 static ULONG WINAPI xslprocessor_Release( IXSLProcessor *iface )
303 {
304     xslprocessor *This = impl_from_IXSLProcessor( iface );
305     ULONG ref = InterlockedDecrement( &This->ref );
306
307     TRACE("(%p)->(%d)\n", This, ref);
308     if ( ref == 0 )
309     {
310         if (This->input) IXMLDOMNode_Release(This->input);
311         if (This->output) IStream_Release(This->output);
312         SysFreeString(This->outstr);
313         IXSLTemplate_Release(&This->stylesheet->IXSLTemplate_iface);
314         release_dispex(&This->dispex);
315         heap_free( This );
316     }
317
318     return ref;
319 }
320
321 static HRESULT WINAPI xslprocessor_GetTypeInfoCount( IXSLProcessor *iface, UINT* pctinfo )
322 {
323     xslprocessor *This = impl_from_IXSLProcessor( iface );
324     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
325 }
326
327 static HRESULT WINAPI xslprocessor_GetTypeInfo(
328     IXSLProcessor *iface,
329     UINT iTInfo, LCID lcid,
330     ITypeInfo** ppTInfo )
331 {
332     xslprocessor *This = impl_from_IXSLProcessor( iface );
333     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
334         iTInfo, lcid, ppTInfo);
335 }
336
337 static HRESULT WINAPI xslprocessor_GetIDsOfNames(
338     IXSLProcessor *iface,
339     REFIID riid, LPOLESTR* rgszNames,
340     UINT cNames, LCID lcid, DISPID* rgDispId )
341 {
342     xslprocessor *This = impl_from_IXSLProcessor( iface );
343     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
344         riid, rgszNames, cNames, lcid, rgDispId);
345 }
346
347 static HRESULT WINAPI xslprocessor_Invoke(
348     IXSLProcessor *iface,
349     DISPID dispIdMember, REFIID riid, LCID lcid,
350     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
351     EXCEPINFO* pExcepInfo, UINT* puArgErr )
352 {
353     xslprocessor *This = impl_from_IXSLProcessor( iface );
354     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
355         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
356 }
357
358 static HRESULT WINAPI xslprocessor_put_input( IXSLProcessor *iface, VARIANT input )
359 {
360     xslprocessor *This = impl_from_IXSLProcessor( iface );
361     IXMLDOMNode *input_node;
362     HRESULT hr;
363
364     TRACE("(%p)->(%s)\n", This, debugstr_variant(&input));
365
366     /* try IXMLDOMNode directly first */
367     if (V_VT(&input) == VT_UNKNOWN)
368         hr = IUnknown_QueryInterface(V_UNKNOWN(&input), &IID_IXMLDOMNode, (void**)&input_node);
369     else if (V_VT(&input) == VT_DISPATCH)
370         hr = IDispatch_QueryInterface(V_DISPATCH(&input), &IID_IXMLDOMNode, (void**)&input_node);
371     else
372     {
373         IXMLDOMDocument *doc;
374
375         hr = DOMDocument_create(MSXML_DEFAULT, NULL, (void**)&doc);
376         if (hr == S_OK)
377         {
378             VARIANT_BOOL b;
379
380             hr = IXMLDOMDocument_load(doc, input, &b);
381             if (hr == S_OK)
382                 hr = IXMLDOMDocument_QueryInterface(doc, &IID_IXMLDOMNode, (void**)&input_node);
383             IXMLDOMDocument_Release(doc);
384         }
385     }
386
387     if (hr == S_OK)
388     {
389         if (This->input) IXMLDOMNode_Release(This->input);
390         This->input = input_node;
391     }
392
393     return hr;
394 }
395
396 static HRESULT WINAPI xslprocessor_get_input( IXSLProcessor *iface, VARIANT *input )
397 {
398     xslprocessor *This = impl_from_IXSLProcessor( iface );
399
400     FIXME("(%p)->(%p): stub\n", This, input);
401     return E_NOTIMPL;
402 }
403
404 static HRESULT WINAPI xslprocessor_get_ownerTemplate(
405     IXSLProcessor *iface,
406     IXSLTemplate **template)
407 {
408     xslprocessor *This = impl_from_IXSLProcessor( iface );
409
410     FIXME("(%p)->(%p): stub\n", This, template);
411     return E_NOTIMPL;
412 }
413
414 static HRESULT WINAPI xslprocessor_setStartMode(
415     IXSLProcessor *iface,
416     BSTR p,
417     BSTR uri)
418 {
419     xslprocessor *This = impl_from_IXSLProcessor( iface );
420
421     FIXME("(%p)->(%s %s): stub\n", This, debugstr_w(p), debugstr_w(uri));
422     return E_NOTIMPL;
423 }
424
425 static HRESULT WINAPI xslprocessor_get_startMode(
426     IXSLProcessor *iface,
427     BSTR *p)
428 {
429     xslprocessor *This = impl_from_IXSLProcessor( iface );
430
431     FIXME("(%p)->(%p): stub\n", This, p);
432     return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI xslprocessor_get_startModeURI(
436     IXSLProcessor *iface,
437     BSTR *uri)
438 {
439     xslprocessor *This = impl_from_IXSLProcessor( iface );
440
441     FIXME("(%p)->(%p): stub\n", This, uri);
442     return E_NOTIMPL;
443 }
444
445 static HRESULT WINAPI xslprocessor_put_output(
446     IXSLProcessor *iface,
447     VARIANT output)
448 {
449     xslprocessor *This = impl_from_IXSLProcessor( iface );
450     IStream *stream;
451     HRESULT hr;
452
453     FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&output));
454
455     switch (V_VT(&output))
456     {
457       case VT_EMPTY:
458         stream = NULL;
459         hr = S_OK;
460         break;
461       case VT_UNKNOWN:
462         hr = IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IStream, (void**)&stream);
463         break;
464       default:
465         hr = E_FAIL;
466     }
467
468     if (hr == S_OK)
469     {
470         if (This->output) IStream_Release(This->output);
471         This->output = stream;
472     }
473
474     return hr;
475 }
476
477 static HRESULT WINAPI xslprocessor_get_output(
478     IXSLProcessor *iface,
479     VARIANT *output)
480 {
481     xslprocessor *This = impl_from_IXSLProcessor( iface );
482
483     TRACE("(%p)->(%p)\n", This, output);
484
485     if (!output) return E_INVALIDARG;
486
487     if (This->output)
488     {
489         V_VT(output) = VT_UNKNOWN;
490         V_UNKNOWN(output) = (IUnknown*)This->output;
491         IStream_AddRef(This->output);
492     }
493     else if (This->outstr)
494     {
495         V_VT(output) = VT_BSTR;
496         V_BSTR(output) = SysAllocString(This->outstr);
497     }
498     else
499         V_VT(output) = VT_EMPTY;
500
501     return S_OK;
502 }
503
504 static HRESULT WINAPI xslprocessor_transform(
505     IXSLProcessor *iface,
506     VARIANT_BOOL  *ret)
507 {
508     xslprocessor *This = impl_from_IXSLProcessor( iface );
509     HRESULT hr;
510
511     TRACE("(%p)->(%p)\n", This, ret);
512
513     if (!ret) return E_INVALIDARG;
514
515     SysFreeString(This->outstr);
516     hr = IXMLDOMNode_transformNode(This->input, This->stylesheet->node, &This->outstr);
517     if (hr == S_OK)
518     {
519         if (This->output)
520         {
521             ULONG len = 0;
522
523             /* output to stream */
524             hr = IStream_Write(This->output, This->outstr, SysStringByteLen(This->outstr), &len);
525             *ret = len == SysStringByteLen(This->outstr) ? VARIANT_TRUE : VARIANT_FALSE;
526         }
527     }
528     else
529         *ret = VARIANT_FALSE;
530
531     return hr;
532 }
533
534 static HRESULT WINAPI xslprocessor_reset( IXSLProcessor *iface )
535 {
536     xslprocessor *This = impl_from_IXSLProcessor( iface );
537
538     FIXME("(%p): stub\n", This);
539     return E_NOTIMPL;
540 }
541
542 static HRESULT WINAPI xslprocessor_get_readyState(
543     IXSLProcessor *iface,
544     LONG *state)
545 {
546     xslprocessor *This = impl_from_IXSLProcessor( iface );
547
548     FIXME("(%p)->(%p): stub\n", This, state);
549     return E_NOTIMPL;
550 }
551
552 static HRESULT WINAPI xslprocessor_addParameter(
553     IXSLProcessor *iface,
554     BSTR p,
555     VARIANT var,
556     BSTR uri)
557 {
558     xslprocessor *This = impl_from_IXSLProcessor( iface );
559
560     FIXME("(%p)->(%s %s %s): stub\n", This, debugstr_w(p), debugstr_variant(&var),
561         debugstr_w(uri));
562     return E_NOTIMPL;
563 }
564
565 static HRESULT WINAPI xslprocessor_addObject(
566     IXSLProcessor *iface,
567     IDispatch *obj,
568     BSTR uri)
569 {
570     xslprocessor *This = impl_from_IXSLProcessor( iface );
571
572     FIXME("(%p)->(%p %s): stub\n", This, obj, debugstr_w(uri));
573     return E_NOTIMPL;
574 }
575
576 static HRESULT WINAPI xslprocessor_get_stylesheet(
577     IXSLProcessor *iface,
578     IXMLDOMNode  **node)
579 {
580     xslprocessor *This = impl_from_IXSLProcessor( iface );
581
582     FIXME("(%p)->(%p): stub\n", This, node);
583     return E_NOTIMPL;
584 }
585
586 static const struct IXSLProcessorVtbl XSLProcessorVtbl =
587 {
588     xslprocessor_QueryInterface,
589     xslprocessor_AddRef,
590     xslprocessor_Release,
591     xslprocessor_GetTypeInfoCount,
592     xslprocessor_GetTypeInfo,
593     xslprocessor_GetIDsOfNames,
594     xslprocessor_Invoke,
595     xslprocessor_put_input,
596     xslprocessor_get_input,
597     xslprocessor_get_ownerTemplate,
598     xslprocessor_setStartMode,
599     xslprocessor_get_startMode,
600     xslprocessor_get_startModeURI,
601     xslprocessor_put_output,
602     xslprocessor_get_output,
603     xslprocessor_transform,
604     xslprocessor_reset,
605     xslprocessor_get_readyState,
606     xslprocessor_addParameter,
607     xslprocessor_addObject,
608     xslprocessor_get_stylesheet
609 };
610
611 static const tid_t xslprocessor_iface_tids[] = {
612     IXSLProcessor_tid,
613     0
614 };
615
616 static dispex_static_data_t xslprocessor_dispex = {
617     NULL,
618     IXSLProcessor_tid,
619     NULL,
620     xslprocessor_iface_tids
621 };
622
623 HRESULT XSLProcessor_create(xsltemplate *template, IXSLProcessor **ppObj)
624 {
625     xslprocessor *This;
626
627     TRACE("(%p)\n", ppObj);
628
629     This = heap_alloc( sizeof (*This) );
630     if(!This)
631         return E_OUTOFMEMORY;
632
633     This->IXSLProcessor_iface.lpVtbl = &XSLProcessorVtbl;
634     This->ref = 1;
635     This->input = NULL;
636     This->output = NULL;
637     This->outstr = NULL;
638     This->stylesheet = template;
639     IXSLTemplate_AddRef(&template->IXSLTemplate_iface);
640     init_dispex(&This->dispex, (IUnknown*)&This->IXSLProcessor_iface, &xslprocessor_dispex);
641
642     *ppObj = &This->IXSLProcessor_iface;
643
644     TRACE("returning iface %p\n", *ppObj);
645
646     return S_OK;
647 }