shlwapi: Implement URL_APPLY_GUESSFILE in UrlApplyScheme.
[wine] / dlls / msxml3 / mxwriter.c
1 /*
2  *    MXWriter 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 #include "config.h"
23
24 #include <stdarg.h>
25 #ifdef HAVE_LIBXML2
26 # include <libxml/parser.h>
27 #endif
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "ole2.h"
32
33 #include "msxml6.h"
34
35 #include "wine/debug.h"
36
37 #include "msxml_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
40
41 #ifdef HAVE_LIBXML2
42
43 static const char crlfA[] = "\r\n";
44
45 typedef enum
46 {
47     MXWriter_BOM = 0,
48     MXWriter_DisableEscaping,
49     MXWriter_Indent,
50     MXWriter_OmitXmlDecl,
51     MXWriter_Standalone,
52     MXWriter_LastProp
53 } MXWRITER_PROPS;
54
55 typedef struct _mxwriter
56 {
57     IMXWriter IMXWriter_iface;
58     ISAXContentHandler ISAXContentHandler_iface;
59
60     LONG ref;
61
62     VARIANT_BOOL props[MXWriter_LastProp];
63     BSTR encoding;
64     BSTR version;
65
66     IStream *dest;
67
68     xmlOutputBufferPtr buffer;
69 } mxwriter;
70
71 static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
72 {
73     return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
74 }
75
76 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
77 {
78     return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
79 }
80
81 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
82 {
83     mxwriter *This = impl_from_IMXWriter( iface );
84
85     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
86
87     if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
88          IsEqualGUID( riid, &IID_IDispatch ) ||
89          IsEqualGUID( riid, &IID_IUnknown ) )
90     {
91         *obj = &This->IMXWriter_iface;
92     }
93     else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
94     {
95         *obj = &This->ISAXContentHandler_iface;
96     }
97     else
98     {
99         ERR("interface %s not implemented\n", debugstr_guid(riid));
100         *obj = NULL;
101         return E_NOINTERFACE;
102     }
103
104     IMXWriter_AddRef(iface);
105     return S_OK;
106 }
107
108 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
109 {
110     mxwriter *This = impl_from_IMXWriter( iface );
111     LONG ref = InterlockedIncrement(&This->ref);
112
113     TRACE("(%p)->(%d)\n", This, ref);
114
115     return ref;
116 }
117
118 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
119 {
120     mxwriter *This = impl_from_IMXWriter( iface );
121     ULONG ref = InterlockedDecrement(&This->ref);
122
123     TRACE("(%p)->(%d)\n", This, ref);
124
125     if(!ref)
126     {
127         if (This->dest) IStream_Release(This->dest);
128         SysFreeString(This->encoding);
129         SysFreeString(This->version);
130
131         xmlOutputBufferClose(This->buffer);
132         heap_free(This);
133     }
134
135     return ref;
136 }
137
138 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
139 {
140     mxwriter *This = impl_from_IMXWriter( iface );
141
142     TRACE("(%p)->(%p)\n", This, pctinfo);
143
144     *pctinfo = 1;
145
146     return S_OK;
147 }
148
149 static HRESULT WINAPI mxwriter_GetTypeInfo(
150     IMXWriter *iface,
151     UINT iTInfo, LCID lcid,
152     ITypeInfo** ppTInfo )
153 {
154     mxwriter *This = impl_from_IMXWriter( iface );
155
156     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
157
158     return get_typeinfo(IMXWriter_tid, ppTInfo);
159 }
160
161 static HRESULT WINAPI mxwriter_GetIDsOfNames(
162     IMXWriter *iface,
163     REFIID riid, LPOLESTR* rgszNames,
164     UINT cNames, LCID lcid, DISPID* rgDispId )
165 {
166     mxwriter *This = impl_from_IMXWriter( iface );
167     ITypeInfo *typeinfo;
168     HRESULT hr;
169
170     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
171           lcid, rgDispId);
172
173     if(!rgszNames || cNames == 0 || !rgDispId)
174         return E_INVALIDARG;
175
176     hr = get_typeinfo(IMXWriter_tid, &typeinfo);
177     if(SUCCEEDED(hr))
178     {
179         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
180         ITypeInfo_Release(typeinfo);
181     }
182
183     return hr;
184 }
185
186 static HRESULT WINAPI mxwriter_Invoke(
187     IMXWriter *iface,
188     DISPID dispIdMember, REFIID riid, LCID lcid,
189     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
190     EXCEPINFO* pExcepInfo, UINT* puArgErr )
191 {
192     mxwriter *This = impl_from_IMXWriter( iface );
193     ITypeInfo *typeinfo;
194     HRESULT hr;
195
196     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
197           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
198
199     hr = get_typeinfo(IMXWriter_tid, &typeinfo);
200     if(SUCCEEDED(hr))
201     {
202         hr = ITypeInfo_Invoke(typeinfo, &This->IMXWriter_iface, dispIdMember, wFlags,
203                 pDispParams, pVarResult, pExcepInfo, puArgErr);
204         ITypeInfo_Release(typeinfo);
205     }
206
207     return hr;
208 }
209
210 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
211 {
212     mxwriter *This = impl_from_IMXWriter( iface );
213
214     TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
215
216     switch (V_VT(&dest))
217     {
218     case VT_EMPTY:
219     {
220         if (This->dest) IStream_Release(This->dest);
221         This->dest = NULL;
222         break;
223     }
224     case VT_UNKNOWN:
225     {
226         IStream *stream;
227         HRESULT hr;
228
229         hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
230         if (hr == S_OK)
231         {
232             if (This->dest) IStream_Release(This->dest);
233             This->dest = stream;
234             break;
235         }
236
237         FIXME("unhandled interface type for VT_UNKNOWN destination\n");
238         return E_NOTIMPL;
239     }
240     default:
241         FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
242         return E_NOTIMPL;
243     }
244
245     return S_OK;
246 }
247
248 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
249 {
250     mxwriter *This = impl_from_IMXWriter( iface );
251
252     TRACE("(%p)->(%p)\n", This, dest);
253
254     if (!This->dest)
255     {
256         V_VT(dest)   = VT_BSTR;
257         V_BSTR(dest) = bstr_from_xmlChar(This->buffer->buffer->content);
258
259         return S_OK;
260     }
261     else
262         FIXME("not implemented when stream is set up\n");
263
264     return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
268 {
269     static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
270     static const WCHAR utf8W[]  = {'U','T','F','-','8',0};
271     mxwriter *This = impl_from_IMXWriter( iface );
272
273     TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
274
275     /* FIXME: filter all supported encodings */
276     if (!strcmpW(encoding, utf16W) || !strcmpW(encoding, utf8W))
277     {
278         SysFreeString(This->encoding);
279         This->encoding = SysAllocString(encoding);
280         return S_OK;
281     }
282     else
283     {
284         FIXME("unsupported encoding %s\n", debugstr_w(encoding));
285         return E_INVALIDARG;
286     }
287 }
288
289 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
290 {
291     mxwriter *This = impl_from_IMXWriter( iface );
292
293     TRACE("(%p)->(%p)\n", This, encoding);
294
295     if (!encoding) return E_POINTER;
296
297     return return_bstr(This->encoding, encoding);
298 }
299
300 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
301 {
302     mxwriter *This = impl_from_IMXWriter( iface );
303
304     TRACE("(%p)->(%d)\n", This, value);
305     This->props[MXWriter_BOM] = value;
306
307     return S_OK;
308 }
309
310 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
311 {
312     mxwriter *This = impl_from_IMXWriter( iface );
313
314     TRACE("(%p)->(%p)\n", This, value);
315
316     if (!value) return E_POINTER;
317
318     *value = This->props[MXWriter_BOM];
319
320     return S_OK;
321 }
322
323 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
324 {
325     mxwriter *This = impl_from_IMXWriter( iface );
326
327     TRACE("(%p)->(%d)\n", This, value);
328     This->props[MXWriter_Indent] = value;
329
330     return S_OK;
331 }
332
333 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
334 {
335     mxwriter *This = impl_from_IMXWriter( iface );
336
337     TRACE("(%p)->(%p)\n", This, value);
338
339     if (!value) return E_POINTER;
340
341     *value = This->props[MXWriter_Indent];
342
343     return S_OK;
344 }
345
346 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
347 {
348     mxwriter *This = impl_from_IMXWriter( iface );
349
350     TRACE("(%p)->(%d)\n", This, value);
351     This->props[MXWriter_Standalone] = value;
352
353     return S_OK;
354 }
355
356 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
357 {
358     mxwriter *This = impl_from_IMXWriter( iface );
359
360     TRACE("(%p)->(%p)\n", This, value);
361
362     if (!value) return E_POINTER;
363
364     *value = This->props[MXWriter_Standalone];
365
366     return S_OK;
367 }
368
369 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
370 {
371     mxwriter *This = impl_from_IMXWriter( iface );
372
373     TRACE("(%p)->(%d)\n", This, value);
374     This->props[MXWriter_OmitXmlDecl] = value;
375
376     return S_OK;
377 }
378
379 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
380 {
381     mxwriter *This = impl_from_IMXWriter( iface );
382
383     TRACE("(%p)->(%p)\n", This, value);
384
385     if (!value) return E_POINTER;
386
387     *value = This->props[MXWriter_OmitXmlDecl];
388
389     return S_OK;
390 }
391
392 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
393 {
394     mxwriter *This = impl_from_IMXWriter( iface );
395     FIXME("(%p)->(%s)\n", This, debugstr_w(version));
396     return E_NOTIMPL;
397 }
398
399 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
400 {
401     mxwriter *This = impl_from_IMXWriter( iface );
402
403     TRACE("(%p)->(%p)\n", This, version);
404
405     if (!version) return E_POINTER;
406
407     return return_bstr(This->version, version);
408 }
409
410 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
411 {
412     mxwriter *This = impl_from_IMXWriter( iface );
413
414     TRACE("(%p)->(%d)\n", This, value);
415     This->props[MXWriter_DisableEscaping] = value;
416
417     return S_OK;
418 }
419
420 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
421 {
422     mxwriter *This = impl_from_IMXWriter( iface );
423
424     TRACE("(%p)->(%p)\n", This, value);
425
426     if (!value) return E_POINTER;
427
428     *value = This->props[MXWriter_DisableEscaping];
429
430     return S_OK;
431 }
432
433 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
434 {
435     mxwriter *This = impl_from_IMXWriter( iface );
436     FIXME("(%p)\n", This);
437     return E_NOTIMPL;
438 }
439
440 static const struct IMXWriterVtbl mxwriter_vtbl =
441 {
442     mxwriter_QueryInterface,
443     mxwriter_AddRef,
444     mxwriter_Release,
445     mxwriter_GetTypeInfoCount,
446     mxwriter_GetTypeInfo,
447     mxwriter_GetIDsOfNames,
448     mxwriter_Invoke,
449     mxwriter_put_output,
450     mxwriter_get_output,
451     mxwriter_put_encoding,
452     mxwriter_get_encoding,
453     mxwriter_put_byteOrderMark,
454     mxwriter_get_byteOrderMark,
455     mxwriter_put_indent,
456     mxwriter_get_indent,
457     mxwriter_put_standalone,
458     mxwriter_get_standalone,
459     mxwriter_put_omitXMLDeclaration,
460     mxwriter_get_omitXMLDeclaration,
461     mxwriter_put_version,
462     mxwriter_get_version,
463     mxwriter_put_disableOutputEscaping,
464     mxwriter_get_disableOutputEscaping,
465     mxwriter_flush
466 };
467
468 /*** ISAXContentHandler ***/
469 static HRESULT WINAPI mxwriter_saxcontent_QueryInterface(
470     ISAXContentHandler *iface,
471     REFIID riid,
472     void **obj)
473 {
474     mxwriter *This = impl_from_ISAXContentHandler( iface );
475     return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
476 }
477
478 static ULONG WINAPI mxwriter_saxcontent_AddRef(ISAXContentHandler *iface)
479 {
480     mxwriter *This = impl_from_ISAXContentHandler( iface );
481     return IMXWriter_AddRef(&This->IMXWriter_iface);
482 }
483
484 static ULONG WINAPI mxwriter_saxcontent_Release(ISAXContentHandler *iface)
485 {
486     mxwriter *This = impl_from_ISAXContentHandler( iface );
487     return IMXWriter_Release(&This->IMXWriter_iface);
488 }
489
490 static HRESULT WINAPI mxwriter_saxcontent_putDocumentLocator(
491     ISAXContentHandler *iface,
492     ISAXLocator *locator)
493 {
494     mxwriter *This = impl_from_ISAXContentHandler( iface );
495     FIXME("(%p)->(%p)\n", This, locator);
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI mxwriter_saxcontent_startDocument(ISAXContentHandler *iface)
500 {
501     mxwriter *This = impl_from_ISAXContentHandler( iface );
502     xmlChar *s;
503
504     TRACE("(%p)\n", This);
505
506     if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
507
508     /* version */
509     xmlOutputBufferWriteString(This->buffer, "<?xml version=\"");
510     s = xmlchar_from_wchar(This->version);
511     xmlOutputBufferWriteString(This->buffer, (char*)s);
512     heap_free(s);
513     xmlOutputBufferWriteString(This->buffer, "\"");
514
515     /* encoding */
516     xmlOutputBufferWriteString(This->buffer, " encoding=\"");
517     s = xmlchar_from_wchar(This->encoding);
518     xmlOutputBufferWriteString(This->buffer, (char*)s);
519     heap_free(s);
520     xmlOutputBufferWriteString(This->buffer, "\"");
521
522     /* standalone */
523     xmlOutputBufferWriteString(This->buffer, " standalone=\"");
524     if (This->props[MXWriter_Standalone] == VARIANT_TRUE)
525         xmlOutputBufferWriteString(This->buffer, "yes\"?>");
526     else
527         xmlOutputBufferWriteString(This->buffer, "no\"?>");
528
529     xmlOutputBufferWriteString(This->buffer, crlfA);
530
531     return S_OK;
532 }
533
534 static HRESULT WINAPI mxwriter_saxcontent_endDocument(ISAXContentHandler *iface)
535 {
536     mxwriter *This = impl_from_ISAXContentHandler( iface );
537     FIXME("(%p)\n", This);
538     return E_NOTIMPL;
539 }
540
541 static HRESULT WINAPI mxwriter_saxcontent_startPrefixMapping(
542     ISAXContentHandler *iface,
543     const WCHAR *prefix,
544     int nprefix,
545     const WCHAR *uri,
546     int nuri)
547 {
548     mxwriter *This = impl_from_ISAXContentHandler( iface );
549     FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI mxwriter_saxcontent_endPrefixMapping(
554     ISAXContentHandler *iface,
555     const WCHAR *prefix,
556     int nprefix)
557 {
558     mxwriter *This = impl_from_ISAXContentHandler( iface );
559     FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
560     return E_NOTIMPL;
561 }
562
563 static HRESULT WINAPI mxwriter_saxcontent_startElement(
564     ISAXContentHandler *iface,
565     const WCHAR *namespaceUri,
566     int nnamespaceUri,
567     const WCHAR *local_name,
568     int nlocal_name,
569     const WCHAR *QName,
570     int nQName,
571     ISAXAttributes *attr)
572 {
573     mxwriter *This = impl_from_ISAXContentHandler( iface );
574     xmlChar *s;
575
576     TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
577         debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
578
579     if (!namespaceUri || !local_name || !QName) return E_INVALIDARG;
580
581     xmlOutputBufferWriteString(This->buffer, "<");
582     s = xmlchar_from_wchar(QName);
583     xmlOutputBufferWriteString(This->buffer, (char*)s);
584     heap_free(s);
585
586     if (attr)
587     {
588         HRESULT hr;
589         INT length;
590         INT i;
591
592         hr = ISAXAttributes_getLength(attr, &length);
593         if (FAILED(hr)) return hr;
594
595         if (length) xmlOutputBufferWriteString(This->buffer, " ");
596
597         for (i = 0; i < length; i++)
598         {
599             const WCHAR *str;
600             INT len;
601
602             hr = ISAXAttributes_getQName(attr, i, &str, &len);
603             if (FAILED(hr)) return hr;
604
605             s = xmlchar_from_wchar(str);
606             xmlOutputBufferWriteString(This->buffer, (char*)s);
607             heap_free(s);
608
609             xmlOutputBufferWriteString(This->buffer, "=\"");
610
611             hr = ISAXAttributes_getValue(attr, i, &str, &len);
612             if (FAILED(hr)) return hr;
613
614             s = xmlchar_from_wchar(str);
615             xmlOutputBufferWriteString(This->buffer, (char*)s);
616             heap_free(s);
617
618             xmlOutputBufferWriteString(This->buffer, "\"");
619         }
620     }
621
622     xmlOutputBufferWriteString(This->buffer, ">");
623
624     return S_OK;
625 }
626
627 static HRESULT WINAPI mxwriter_saxcontent_endElement(
628     ISAXContentHandler *iface,
629     const WCHAR *namespaceUri,
630     int nnamespaceUri,
631     const WCHAR * local_name,
632     int nlocal_name,
633     const WCHAR *QName,
634     int nQName)
635 {
636     mxwriter *This = impl_from_ISAXContentHandler( iface );
637     xmlChar *s;
638
639     TRACE("(%p)->(%s %s %s)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
640         debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName));
641
642     if (!namespaceUri || !local_name || !QName) return E_INVALIDARG;
643
644     xmlOutputBufferWriteString(This->buffer, "</");
645     s = xmlchar_from_wchar(QName);
646     xmlOutputBufferWriteString(This->buffer, (char*)s);
647     heap_free(s);
648     xmlOutputBufferWriteString(This->buffer, ">");
649
650     return S_OK;
651 }
652
653 static HRESULT WINAPI mxwriter_saxcontent_characters(
654     ISAXContentHandler *iface,
655     const WCHAR *chars,
656     int nchars)
657 {
658     mxwriter *This = impl_from_ISAXContentHandler( iface );
659
660     TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
661
662     if (!chars) return E_INVALIDARG;
663
664     if (nchars)
665     {
666         xmlChar *s = xmlchar_from_wcharn(chars, nchars);
667         xmlOutputBufferWriteString(This->buffer, (char*)s);
668         heap_free(s);
669     }
670
671     return S_OK;
672 }
673
674 static HRESULT WINAPI mxwriter_saxcontent_ignorableWhitespace(
675     ISAXContentHandler *iface,
676     const WCHAR *chars,
677     int nchars)
678 {
679     mxwriter *This = impl_from_ISAXContentHandler( iface );
680     FIXME("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
681     return E_NOTIMPL;
682 }
683
684 static HRESULT WINAPI mxwriter_saxcontent_processingInstruction(
685     ISAXContentHandler *iface,
686     const WCHAR *target,
687     int ntarget,
688     const WCHAR *data,
689     int ndata)
690 {
691     mxwriter *This = impl_from_ISAXContentHandler( iface );
692     FIXME("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
693     return E_NOTIMPL;
694 }
695
696 static HRESULT WINAPI mxwriter_saxcontent_skippedEntity(
697     ISAXContentHandler *iface,
698     const WCHAR *name,
699     int nname)
700 {
701     mxwriter *This = impl_from_ISAXContentHandler( iface );
702     FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
703     return E_NOTIMPL;
704 }
705
706 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl =
707 {
708     mxwriter_saxcontent_QueryInterface,
709     mxwriter_saxcontent_AddRef,
710     mxwriter_saxcontent_Release,
711     mxwriter_saxcontent_putDocumentLocator,
712     mxwriter_saxcontent_startDocument,
713     mxwriter_saxcontent_endDocument,
714     mxwriter_saxcontent_startPrefixMapping,
715     mxwriter_saxcontent_endPrefixMapping,
716     mxwriter_saxcontent_startElement,
717     mxwriter_saxcontent_endElement,
718     mxwriter_saxcontent_characters,
719     mxwriter_saxcontent_ignorableWhitespace,
720     mxwriter_saxcontent_processingInstruction,
721     mxwriter_saxcontent_skippedEntity
722 };
723
724 HRESULT MXWriter_create(IUnknown *pUnkOuter, void **ppObj)
725 {
726     static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
727     static const WCHAR version10W[] = {'1','.','0',0};
728     mxwriter *This;
729
730     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
731
732     if (pUnkOuter) FIXME("support aggregation, outer\n");
733
734     This = heap_alloc( sizeof (*This) );
735     if(!This)
736         return E_OUTOFMEMORY;
737
738     This->IMXWriter_iface.lpVtbl = &mxwriter_vtbl;
739     This->ISAXContentHandler_iface.lpVtbl = &mxwriter_saxcontent_vtbl;
740     This->ref = 1;
741
742     This->props[MXWriter_BOM] = VARIANT_TRUE;
743     This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
744     This->props[MXWriter_Indent] = VARIANT_FALSE;
745     This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
746     This->props[MXWriter_Standalone] = VARIANT_FALSE;
747     This->encoding   = SysAllocString(utf16W);
748     This->version    = SysAllocString(version10W);
749
750     This->dest = NULL;
751
752     /* set up a buffer, default encoding is UTF-16 */
753     This->buffer = xmlAllocOutputBuffer(xmlFindCharEncodingHandler("UTF-16"));
754
755     *ppObj = &This->IMXWriter_iface;
756
757     TRACE("returning iface %p\n", *ppObj);
758
759     return S_OK;
760 }
761
762 #else
763
764 HRESULT MXWriter_create(IUnknown *pUnkOuter, void **obj)
765 {
766     MESSAGE("This program tried to use a MXXMLWriter object, but\n"
767             "libxml2 support was not present at compile time.\n");
768     return E_NOTIMPL;
769 }
770
771 #endif /* HAVE_LIBXML2 */