msxml3: Fix parameter validation for startElement() for MXXMLWriter60.
[wine/multimedia.git] / dlls / msxml3 / mxwriter.c
blob0ac5974fe810761102bb0a9d230c5db663c2704d
1 /*
2 * MXWriter implementation
4 * Copyright 2011 Nikolay Sivov for CodeWeavers
5 * Copyright 2011 Thomas Mullaly
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #include "config.h"
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "ole2.h"
34 #include "msxml6.h"
36 #include "wine/debug.h"
38 #include "msxml_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
42 #ifdef HAVE_LIBXML2
44 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
45 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
47 static const char crlfA[] = "\r\n";
49 typedef enum
51 MXWriter_BOM = 0,
52 MXWriter_DisableEscaping,
53 MXWriter_Indent,
54 MXWriter_OmitXmlDecl,
55 MXWriter_Standalone,
56 MXWriter_LastProp
57 } MXWRITER_PROPS;
59 typedef struct _mxwriter
61 IMXWriter IMXWriter_iface;
62 ISAXContentHandler ISAXContentHandler_iface;
64 LONG ref;
65 MSXML_VERSION class_version;
67 VARIANT_BOOL props[MXWriter_LastProp];
68 BOOL prop_changed;
69 xmlCharEncoding encoding;
70 BSTR version;
72 IStream *dest;
73 ULONG dest_written;
75 xmlOutputBufferPtr buffer;
76 } mxwriter;
78 static HRESULT bstr_from_xmlCharEncoding(xmlCharEncoding enc, BSTR *encoding)
80 const char *encodingA;
82 if (enc != XML_CHAR_ENCODING_UTF16LE && enc != XML_CHAR_ENCODING_UTF8) {
83 FIXME("Unsupported xmlCharEncoding: %d\n", enc);
84 *encoding = NULL;
85 return E_NOTIMPL;
88 encodingA = xmlGetCharEncodingName(enc);
89 if (encodingA) {
90 DWORD len = MultiByteToWideChar(CP_ACP, 0, encodingA, -1, NULL, 0);
91 *encoding = SysAllocStringLen(NULL, len-1);
92 if(*encoding)
93 MultiByteToWideChar( CP_ACP, 0, encodingA, -1, *encoding, len);
94 } else
95 *encoding = SysAllocStringLen(NULL, 0);
97 return *encoding ? S_OK : E_OUTOFMEMORY;
100 /* Attempts to the write data from the mxwriter's buffer to
101 * the destination stream (if there is one).
103 static HRESULT write_data_to_stream(mxwriter *This)
105 HRESULT hres;
106 ULONG written = 0;
107 xmlBufferPtr buffer = NULL;
109 if (!This->dest)
110 return S_OK;
112 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
113 * 'conv' buffer when UTF8 encoding is used.
115 if (This->encoding == XML_CHAR_ENCODING_UTF8)
116 buffer = This->buffer->buffer;
117 else
118 buffer = This->buffer->conv;
120 if (This->dest_written > buffer->use) {
121 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This->dest_written, buffer->use);
122 return E_FAIL;
123 } else if (This->dest_written == buffer->use && This->encoding != XML_CHAR_ENCODING_UTF8)
124 /* Windows seems to make an empty write call when the encoding is UTF-8 and
125 * all the data has been written to the stream. It doesn't seem make this call
126 * for any other encodings.
128 return S_OK;
130 /* Write the current content from the output buffer into 'dest'.
131 * TODO: Check what Windows does if the IStream doesn't write all of
132 * the data we give it at once.
134 hres = IStream_Write(This->dest, buffer->content+This->dest_written,
135 buffer->use-This->dest_written, &written);
136 if (FAILED(hres)) {
137 WARN("Failed to write data to IStream (%08x)\n", hres);
138 return hres;
141 This->dest_written += written;
142 return hres;
145 static inline HRESULT flush_output_buffer(mxwriter *This)
147 xmlOutputBufferFlush(This->buffer);
148 return write_data_to_stream(This);
151 /* Resets the mxwriter's output buffer by closing it, then creating a new
152 * output buffer using the given encoding.
154 static inline void reset_output_buffer(mxwriter *This)
156 xmlOutputBufferClose(This->buffer);
157 This->buffer = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This->encoding));
158 This->dest_written = 0;
161 static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
163 return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
166 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
168 return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
171 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
173 mxwriter *This = impl_from_IMXWriter( iface );
175 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
177 if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
178 IsEqualGUID( riid, &IID_IDispatch ) ||
179 IsEqualGUID( riid, &IID_IUnknown ) )
181 *obj = &This->IMXWriter_iface;
183 else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
185 *obj = &This->ISAXContentHandler_iface;
187 else
189 ERR("interface %s not implemented\n", debugstr_guid(riid));
190 *obj = NULL;
191 return E_NOINTERFACE;
194 IMXWriter_AddRef(iface);
195 return S_OK;
198 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
200 mxwriter *This = impl_from_IMXWriter( iface );
201 LONG ref = InterlockedIncrement(&This->ref);
203 TRACE("(%p)->(%d)\n", This, ref);
205 return ref;
208 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
210 mxwriter *This = impl_from_IMXWriter( iface );
211 ULONG ref = InterlockedDecrement(&This->ref);
213 TRACE("(%p)->(%d)\n", This, ref);
215 if(!ref)
217 /* Windows flushes the buffer when the interface is destroyed. */
218 flush_output_buffer(This);
220 if (This->dest) IStream_Release(This->dest);
221 SysFreeString(This->version);
223 xmlOutputBufferClose(This->buffer);
224 heap_free(This);
227 return ref;
230 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
232 mxwriter *This = impl_from_IMXWriter( iface );
234 TRACE("(%p)->(%p)\n", This, pctinfo);
236 *pctinfo = 1;
238 return S_OK;
241 static HRESULT WINAPI mxwriter_GetTypeInfo(
242 IMXWriter *iface,
243 UINT iTInfo, LCID lcid,
244 ITypeInfo** ppTInfo )
246 mxwriter *This = impl_from_IMXWriter( iface );
248 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
250 return get_typeinfo(IMXWriter_tid, ppTInfo);
253 static HRESULT WINAPI mxwriter_GetIDsOfNames(
254 IMXWriter *iface,
255 REFIID riid, LPOLESTR* rgszNames,
256 UINT cNames, LCID lcid, DISPID* rgDispId )
258 mxwriter *This = impl_from_IMXWriter( iface );
259 ITypeInfo *typeinfo;
260 HRESULT hr;
262 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
263 lcid, rgDispId);
265 if(!rgszNames || cNames == 0 || !rgDispId)
266 return E_INVALIDARG;
268 hr = get_typeinfo(IMXWriter_tid, &typeinfo);
269 if(SUCCEEDED(hr))
271 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
272 ITypeInfo_Release(typeinfo);
275 return hr;
278 static HRESULT WINAPI mxwriter_Invoke(
279 IMXWriter *iface,
280 DISPID dispIdMember, REFIID riid, LCID lcid,
281 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
282 EXCEPINFO* pExcepInfo, UINT* puArgErr )
284 mxwriter *This = impl_from_IMXWriter( iface );
285 ITypeInfo *typeinfo;
286 HRESULT hr;
288 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
289 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
291 hr = get_typeinfo(IMXWriter_tid, &typeinfo);
292 if(SUCCEEDED(hr))
294 hr = ITypeInfo_Invoke(typeinfo, &This->IMXWriter_iface, dispIdMember, wFlags,
295 pDispParams, pVarResult, pExcepInfo, puArgErr);
296 ITypeInfo_Release(typeinfo);
299 return hr;
302 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
304 mxwriter *This = impl_from_IMXWriter( iface );
305 HRESULT hr;
307 TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
309 hr = flush_output_buffer(This);
310 if (FAILED(hr))
311 return hr;
313 switch (V_VT(&dest))
315 case VT_EMPTY:
317 if (This->dest) IStream_Release(This->dest);
318 This->dest = NULL;
320 /* We need to reset the output buffer to UTF-16, since the only way
321 * the content of the mxwriter can be accessed now is through a BSTR.
323 This->encoding = xmlParseCharEncoding("UTF-16");
324 reset_output_buffer(This);
325 break;
327 case VT_UNKNOWN:
329 IStream *stream;
331 hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
332 if (hr == S_OK)
334 /* Recreate the output buffer to make sure it's using the correct encoding. */
335 reset_output_buffer(This);
337 if (This->dest) IStream_Release(This->dest);
338 This->dest = stream;
339 break;
342 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
343 return E_NOTIMPL;
345 default:
346 FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
347 return E_NOTIMPL;
350 return S_OK;
353 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
355 mxwriter *This = impl_from_IMXWriter( iface );
357 TRACE("(%p)->(%p)\n", This, dest);
359 if (!This->dest)
361 HRESULT hr = flush_output_buffer(This);
362 if (FAILED(hr))
363 return hr;
365 /* TODO: Windows always seems to re-encode the XML to UTF-16 (this includes
366 * updating the XML decl so it says "UTF-16" instead of "UTF-8"). We don't
367 * support this yet...
369 if (This->encoding == XML_CHAR_ENCODING_UTF8) {
370 FIXME("XML re-encoding not supported yet\n");
371 return E_NOTIMPL;
374 V_VT(dest) = VT_BSTR;
375 V_BSTR(dest) = SysAllocStringLen((const WCHAR*)This->buffer->conv->content,
376 This->buffer->conv->use/sizeof(WCHAR));
378 return S_OK;
380 else
381 FIXME("not implemented when stream is set up\n");
383 return E_NOTIMPL;
386 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
388 mxwriter *This = impl_from_IMXWriter( iface );
390 TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
392 /* FIXME: filter all supported encodings */
393 if (!strcmpW(encoding, utf16W) || !strcmpW(encoding, utf8W))
395 HRESULT hr;
396 LPSTR enc;
398 hr = flush_output_buffer(This);
399 if (FAILED(hr))
400 return hr;
402 enc = heap_strdupWtoA(encoding);
403 if (!enc)
404 return E_OUTOFMEMORY;
406 This->encoding = xmlParseCharEncoding(enc);
407 heap_free(enc);
409 reset_output_buffer(This);
410 return S_OK;
412 else
414 FIXME("unsupported encoding %s\n", debugstr_w(encoding));
415 return E_INVALIDARG;
419 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
421 mxwriter *This = impl_from_IMXWriter( iface );
423 TRACE("(%p)->(%p)\n", This, encoding);
425 if (!encoding) return E_POINTER;
427 return bstr_from_xmlCharEncoding(This->encoding, encoding);
430 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
432 mxwriter *This = impl_from_IMXWriter( iface );
434 TRACE("(%p)->(%d)\n", This, value);
435 This->props[MXWriter_BOM] = value;
436 This->prop_changed = TRUE;
438 return S_OK;
441 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
443 mxwriter *This = impl_from_IMXWriter( iface );
445 TRACE("(%p)->(%p)\n", This, value);
447 if (!value) return E_POINTER;
449 *value = This->props[MXWriter_BOM];
451 return S_OK;
454 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
456 mxwriter *This = impl_from_IMXWriter( iface );
458 TRACE("(%p)->(%d)\n", This, value);
459 This->props[MXWriter_Indent] = value;
460 This->prop_changed = TRUE;
462 return S_OK;
465 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
467 mxwriter *This = impl_from_IMXWriter( iface );
469 TRACE("(%p)->(%p)\n", This, value);
471 if (!value) return E_POINTER;
473 *value = This->props[MXWriter_Indent];
475 return S_OK;
478 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
480 mxwriter *This = impl_from_IMXWriter( iface );
482 TRACE("(%p)->(%d)\n", This, value);
483 This->props[MXWriter_Standalone] = value;
484 This->prop_changed = TRUE;
486 return S_OK;
489 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
491 mxwriter *This = impl_from_IMXWriter( iface );
493 TRACE("(%p)->(%p)\n", This, value);
495 if (!value) return E_POINTER;
497 *value = This->props[MXWriter_Standalone];
499 return S_OK;
502 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
504 mxwriter *This = impl_from_IMXWriter( iface );
506 TRACE("(%p)->(%d)\n", This, value);
507 This->props[MXWriter_OmitXmlDecl] = value;
508 This->prop_changed = TRUE;
510 return S_OK;
513 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
515 mxwriter *This = impl_from_IMXWriter( iface );
517 TRACE("(%p)->(%p)\n", This, value);
519 if (!value) return E_POINTER;
521 *value = This->props[MXWriter_OmitXmlDecl];
523 return S_OK;
526 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
528 mxwriter *This = impl_from_IMXWriter( iface );
530 TRACE("(%p)->(%s)\n", This, debugstr_w(version));
532 if (!version) return E_INVALIDARG;
534 SysFreeString(This->version);
535 This->version = SysAllocString(version);
537 return S_OK;
540 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
542 mxwriter *This = impl_from_IMXWriter( iface );
544 TRACE("(%p)->(%p)\n", This, version);
546 if (!version) return E_POINTER;
548 return return_bstr(This->version, version);
551 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
553 mxwriter *This = impl_from_IMXWriter( iface );
555 TRACE("(%p)->(%d)\n", This, value);
556 This->props[MXWriter_DisableEscaping] = value;
557 This->prop_changed = TRUE;
559 return S_OK;
562 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
564 mxwriter *This = impl_from_IMXWriter( iface );
566 TRACE("(%p)->(%p)\n", This, value);
568 if (!value) return E_POINTER;
570 *value = This->props[MXWriter_DisableEscaping];
572 return S_OK;
575 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
577 mxwriter *This = impl_from_IMXWriter( iface );
578 TRACE("(%p)\n", This);
579 return flush_output_buffer(This);
582 static const struct IMXWriterVtbl mxwriter_vtbl =
584 mxwriter_QueryInterface,
585 mxwriter_AddRef,
586 mxwriter_Release,
587 mxwriter_GetTypeInfoCount,
588 mxwriter_GetTypeInfo,
589 mxwriter_GetIDsOfNames,
590 mxwriter_Invoke,
591 mxwriter_put_output,
592 mxwriter_get_output,
593 mxwriter_put_encoding,
594 mxwriter_get_encoding,
595 mxwriter_put_byteOrderMark,
596 mxwriter_get_byteOrderMark,
597 mxwriter_put_indent,
598 mxwriter_get_indent,
599 mxwriter_put_standalone,
600 mxwriter_get_standalone,
601 mxwriter_put_omitXMLDeclaration,
602 mxwriter_get_omitXMLDeclaration,
603 mxwriter_put_version,
604 mxwriter_get_version,
605 mxwriter_put_disableOutputEscaping,
606 mxwriter_get_disableOutputEscaping,
607 mxwriter_flush
610 /*** ISAXContentHandler ***/
611 static HRESULT WINAPI mxwriter_saxcontent_QueryInterface(
612 ISAXContentHandler *iface,
613 REFIID riid,
614 void **obj)
616 mxwriter *This = impl_from_ISAXContentHandler( iface );
617 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
620 static ULONG WINAPI mxwriter_saxcontent_AddRef(ISAXContentHandler *iface)
622 mxwriter *This = impl_from_ISAXContentHandler( iface );
623 return IMXWriter_AddRef(&This->IMXWriter_iface);
626 static ULONG WINAPI mxwriter_saxcontent_Release(ISAXContentHandler *iface)
628 mxwriter *This = impl_from_ISAXContentHandler( iface );
629 return IMXWriter_Release(&This->IMXWriter_iface);
632 static HRESULT WINAPI mxwriter_saxcontent_putDocumentLocator(
633 ISAXContentHandler *iface,
634 ISAXLocator *locator)
636 mxwriter *This = impl_from_ISAXContentHandler( iface );
637 FIXME("(%p)->(%p)\n", This, locator);
638 return E_NOTIMPL;
641 static HRESULT WINAPI mxwriter_saxcontent_startDocument(ISAXContentHandler *iface)
643 mxwriter *This = impl_from_ISAXContentHandler( iface );
644 xmlChar *s;
646 TRACE("(%p)\n", This);
648 /* If properties have been changed since the last "endDocument" call
649 * we need to reset the output buffer. If we don't the output buffer
650 * could end up with multiple XML documents in it, plus this seems to
651 * be how Windows works.
653 if (This->prop_changed) {
654 reset_output_buffer(This);
655 This->prop_changed = FALSE;
658 if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
660 /* version */
661 xmlOutputBufferWriteString(This->buffer, "<?xml version=\"");
662 s = xmlchar_from_wchar(This->version);
663 xmlOutputBufferWriteString(This->buffer, (char*)s);
664 heap_free(s);
665 xmlOutputBufferWriteString(This->buffer, "\"");
667 /* encoding */
668 xmlOutputBufferWriteString(This->buffer, " encoding=\"");
669 xmlOutputBufferWriteString(This->buffer, xmlGetCharEncodingName(This->encoding));
670 xmlOutputBufferWriteString(This->buffer, "\"");
672 /* standalone */
673 xmlOutputBufferWriteString(This->buffer, " standalone=\"");
674 if (This->props[MXWriter_Standalone] == VARIANT_TRUE)
675 xmlOutputBufferWriteString(This->buffer, "yes\"?>");
676 else
677 xmlOutputBufferWriteString(This->buffer, "no\"?>");
679 xmlOutputBufferWriteString(This->buffer, crlfA);
681 if (This->dest && This->encoding == XML_CHAR_ENCODING_UTF16LE) {
682 static const CHAR utf16BOM[] = {0xff,0xfe};
684 if (This->props[MXWriter_BOM] == VARIANT_TRUE)
685 /* Windows passes a NULL pointer as the pcbWritten parameter and
686 * ignores any error codes returned from this Write call.
688 IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
691 return S_OK;
694 static HRESULT WINAPI mxwriter_saxcontent_endDocument(ISAXContentHandler *iface)
696 mxwriter *This = impl_from_ISAXContentHandler( iface );
697 TRACE("(%p)\n", This);
698 This->prop_changed = FALSE;
699 return flush_output_buffer(This);
702 static HRESULT WINAPI mxwriter_saxcontent_startPrefixMapping(
703 ISAXContentHandler *iface,
704 const WCHAR *prefix,
705 int nprefix,
706 const WCHAR *uri,
707 int nuri)
709 mxwriter *This = impl_from_ISAXContentHandler( iface );
710 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
711 return E_NOTIMPL;
714 static HRESULT WINAPI mxwriter_saxcontent_endPrefixMapping(
715 ISAXContentHandler *iface,
716 const WCHAR *prefix,
717 int nprefix)
719 mxwriter *This = impl_from_ISAXContentHandler( iface );
720 FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
721 return E_NOTIMPL;
724 static HRESULT WINAPI mxwriter_saxcontent_startElement(
725 ISAXContentHandler *iface,
726 const WCHAR *namespaceUri,
727 int nnamespaceUri,
728 const WCHAR *local_name,
729 int nlocal_name,
730 const WCHAR *QName,
731 int nQName,
732 ISAXAttributes *attr)
734 mxwriter *This = impl_from_ISAXContentHandler( iface );
735 xmlChar *s;
737 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
738 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
740 if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
741 return E_INVALIDARG;
743 xmlOutputBufferWriteString(This->buffer, "<");
744 s = xmlchar_from_wchar(QName);
745 xmlOutputBufferWriteString(This->buffer, (char*)s);
746 heap_free(s);
748 if (attr)
750 HRESULT hr;
751 INT length;
752 INT i;
754 hr = ISAXAttributes_getLength(attr, &length);
755 if (FAILED(hr)) return hr;
757 if (length) xmlOutputBufferWriteString(This->buffer, " ");
759 for (i = 0; i < length; i++)
761 const WCHAR *str;
762 INT len;
764 hr = ISAXAttributes_getQName(attr, i, &str, &len);
765 if (FAILED(hr)) return hr;
767 s = xmlchar_from_wchar(str);
768 xmlOutputBufferWriteString(This->buffer, (char*)s);
769 heap_free(s);
771 xmlOutputBufferWriteString(This->buffer, "=\"");
773 hr = ISAXAttributes_getValue(attr, i, &str, &len);
774 if (FAILED(hr)) return hr;
776 s = xmlchar_from_wchar(str);
777 xmlOutputBufferWriteString(This->buffer, (char*)s);
778 heap_free(s);
780 xmlOutputBufferWriteString(This->buffer, "\"");
784 xmlOutputBufferWriteString(This->buffer, ">");
786 return S_OK;
789 static HRESULT WINAPI mxwriter_saxcontent_endElement(
790 ISAXContentHandler *iface,
791 const WCHAR *namespaceUri,
792 int nnamespaceUri,
793 const WCHAR * local_name,
794 int nlocal_name,
795 const WCHAR *QName,
796 int nQName)
798 mxwriter *This = impl_from_ISAXContentHandler( iface );
799 xmlChar *s;
801 TRACE("(%p)->(%s %s %s)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
802 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName));
804 if (!namespaceUri || !local_name || !QName) return E_INVALIDARG;
806 xmlOutputBufferWriteString(This->buffer, "</");
807 s = xmlchar_from_wchar(QName);
808 xmlOutputBufferWriteString(This->buffer, (char*)s);
809 heap_free(s);
810 xmlOutputBufferWriteString(This->buffer, ">");
812 return S_OK;
815 static HRESULT WINAPI mxwriter_saxcontent_characters(
816 ISAXContentHandler *iface,
817 const WCHAR *chars,
818 int nchars)
820 mxwriter *This = impl_from_ISAXContentHandler( iface );
822 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
824 if (!chars) return E_INVALIDARG;
826 if (nchars)
828 xmlChar *s = xmlchar_from_wcharn(chars, nchars);
829 xmlOutputBufferWriteString(This->buffer, (char*)s);
830 heap_free(s);
833 return S_OK;
836 static HRESULT WINAPI mxwriter_saxcontent_ignorableWhitespace(
837 ISAXContentHandler *iface,
838 const WCHAR *chars,
839 int nchars)
841 mxwriter *This = impl_from_ISAXContentHandler( iface );
842 FIXME("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
843 return E_NOTIMPL;
846 static HRESULT WINAPI mxwriter_saxcontent_processingInstruction(
847 ISAXContentHandler *iface,
848 const WCHAR *target,
849 int ntarget,
850 const WCHAR *data,
851 int ndata)
853 mxwriter *This = impl_from_ISAXContentHandler( iface );
854 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
855 return E_NOTIMPL;
858 static HRESULT WINAPI mxwriter_saxcontent_skippedEntity(
859 ISAXContentHandler *iface,
860 const WCHAR *name,
861 int nname)
863 mxwriter *This = impl_from_ISAXContentHandler( iface );
864 FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
865 return E_NOTIMPL;
868 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl =
870 mxwriter_saxcontent_QueryInterface,
871 mxwriter_saxcontent_AddRef,
872 mxwriter_saxcontent_Release,
873 mxwriter_saxcontent_putDocumentLocator,
874 mxwriter_saxcontent_startDocument,
875 mxwriter_saxcontent_endDocument,
876 mxwriter_saxcontent_startPrefixMapping,
877 mxwriter_saxcontent_endPrefixMapping,
878 mxwriter_saxcontent_startElement,
879 mxwriter_saxcontent_endElement,
880 mxwriter_saxcontent_characters,
881 mxwriter_saxcontent_ignorableWhitespace,
882 mxwriter_saxcontent_processingInstruction,
883 mxwriter_saxcontent_skippedEntity
886 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
888 static const WCHAR version10W[] = {'1','.','0',0};
889 mxwriter *This;
891 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
893 if (pUnkOuter) FIXME("support aggregation, outer\n");
895 This = heap_alloc( sizeof (*This) );
896 if(!This)
897 return E_OUTOFMEMORY;
899 This->IMXWriter_iface.lpVtbl = &mxwriter_vtbl;
900 This->ISAXContentHandler_iface.lpVtbl = &mxwriter_saxcontent_vtbl;
901 This->ref = 1;
902 This->class_version = version;
904 This->props[MXWriter_BOM] = VARIANT_TRUE;
905 This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
906 This->props[MXWriter_Indent] = VARIANT_FALSE;
907 This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
908 This->props[MXWriter_Standalone] = VARIANT_FALSE;
909 This->prop_changed = FALSE;
910 This->encoding = xmlParseCharEncoding("UTF-16");
911 This->version = SysAllocString(version10W);
913 This->dest = NULL;
914 This->dest_written = 0;
916 This->buffer = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This->encoding));
918 *ppObj = &This->IMXWriter_iface;
920 TRACE("returning iface %p\n", *ppObj);
922 return S_OK;
925 #else
927 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **obj)
929 MESSAGE("This program tried to use a MXXMLWriter object, but\n"
930 "libxml2 support was not present at compile time.\n");
931 return E_NOTIMPL;
934 #endif /* HAVE_LIBXML2 */