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
27 # include <libxml/parser.h>
36 #include "wine/debug.h"
38 #include "msxml_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
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";
48 static const WCHAR emptyW
[] = {0};
53 MXWriter_DisableEscaping
,
60 typedef struct _mxwriter
63 IMXWriter IMXWriter_iface
;
64 ISAXContentHandler ISAXContentHandler_iface
;
67 MSXML_VERSION class_version
;
69 VARIANT_BOOL props
[MXWriter_LastProp
];
71 xmlCharEncoding encoding
;
74 /* contains a pending (or not closed yet) element name or NULL if
75 we don't have to close */
81 xmlOutputBufferPtr buffer
;
84 static HRESULT
bstr_from_xmlCharEncoding(xmlCharEncoding enc
, BSTR
*encoding
)
86 const char *encodingA
;
88 if (enc
!= XML_CHAR_ENCODING_UTF16LE
&& enc
!= XML_CHAR_ENCODING_UTF8
) {
89 FIXME("Unsupported xmlCharEncoding: %d\n", enc
);
94 encodingA
= xmlGetCharEncodingName(enc
);
96 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, encodingA
, -1, NULL
, 0);
97 *encoding
= SysAllocStringLen(NULL
, len
-1);
99 MultiByteToWideChar( CP_ACP
, 0, encodingA
, -1, *encoding
, len
);
101 *encoding
= SysAllocStringLen(NULL
, 0);
103 return *encoding
? S_OK
: E_OUTOFMEMORY
;
106 /* Attempts to the write data from the mxwriter's buffer to
107 * the destination stream (if there is one).
109 static HRESULT
write_data_to_stream(mxwriter
*This
)
113 xmlBufferPtr buffer
= NULL
;
118 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
119 * 'conv' buffer when UTF8 encoding is used.
121 if (This
->encoding
== XML_CHAR_ENCODING_UTF8
)
122 buffer
= This
->buffer
->buffer
;
124 buffer
= This
->buffer
->conv
;
126 if (This
->dest_written
> buffer
->use
) {
127 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This
->dest_written
, buffer
->use
);
129 } else if (This
->dest_written
== buffer
->use
&& This
->encoding
!= XML_CHAR_ENCODING_UTF8
)
130 /* Windows seems to make an empty write call when the encoding is UTF-8 and
131 * all the data has been written to the stream. It doesn't seem make this call
132 * for any other encodings.
136 /* Write the current content from the output buffer into 'dest'.
137 * TODO: Check what Windows does if the IStream doesn't write all of
138 * the data we give it at once.
140 hres
= IStream_Write(This
->dest
, buffer
->content
+This
->dest_written
,
141 buffer
->use
-This
->dest_written
, &written
);
143 WARN("Failed to write data to IStream (%08x)\n", hres
);
147 This
->dest_written
+= written
;
151 /* Newly added element start tag left unclosed cause for empty elements
152 we have to close it differently. */
153 static void close_element_starttag(const mxwriter
*This
)
155 if (!This
->element
) return;
156 xmlOutputBufferWriteString(This
->buffer
, ">");
159 static void set_element_name(mxwriter
*This
, const WCHAR
*name
, int len
)
161 SysFreeString(This
->element
);
162 This
->element
= name
? SysAllocStringLen(name
, len
) : NULL
;
165 static inline HRESULT
flush_output_buffer(mxwriter
*This
)
167 close_element_starttag(This
);
168 set_element_name(This
, NULL
, 0);
169 xmlOutputBufferFlush(This
->buffer
);
170 return write_data_to_stream(This
);
173 /* Resets the mxwriter's output buffer by closing it, then creating a new
174 * output buffer using the given encoding.
176 static inline void reset_output_buffer(mxwriter
*This
)
178 xmlOutputBufferClose(This
->buffer
);
179 This
->buffer
= xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This
->encoding
));
180 This
->dest_written
= 0;
183 static HRESULT
writer_set_property(mxwriter
*writer
, MXWRITER_PROPS property
, VARIANT_BOOL value
)
185 writer
->props
[property
] = value
;
186 writer
->prop_changed
= TRUE
;
190 static HRESULT
writer_get_property(const mxwriter
*writer
, MXWRITER_PROPS property
, VARIANT_BOOL
*value
)
192 if (!value
) return E_POINTER
;
193 *value
= writer
->props
[property
];
197 static inline mxwriter
*impl_from_IMXWriter(IMXWriter
*iface
)
199 return CONTAINING_RECORD(iface
, mxwriter
, IMXWriter_iface
);
202 static inline mxwriter
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
204 return CONTAINING_RECORD(iface
, mxwriter
, ISAXContentHandler_iface
);
207 static HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
209 mxwriter
*This
= impl_from_IMXWriter( iface
);
211 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
215 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
216 IsEqualGUID( riid
, &IID_IDispatch
) ||
217 IsEqualGUID( riid
, &IID_IUnknown
) )
219 *obj
= &This
->IMXWriter_iface
;
221 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
223 *obj
= &This
->ISAXContentHandler_iface
;
225 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
227 return *obj
? S_OK
: E_NOINTERFACE
;
231 ERR("interface %s not implemented\n", debugstr_guid(riid
));
233 return E_NOINTERFACE
;
236 IMXWriter_AddRef(iface
);
240 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
242 mxwriter
*This
= impl_from_IMXWriter( iface
);
243 LONG ref
= InterlockedIncrement(&This
->ref
);
245 TRACE("(%p)->(%d)\n", This
, ref
);
250 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
252 mxwriter
*This
= impl_from_IMXWriter( iface
);
253 ULONG ref
= InterlockedDecrement(&This
->ref
);
255 TRACE("(%p)->(%d)\n", This
, ref
);
259 /* Windows flushes the buffer when the interface is destroyed. */
260 flush_output_buffer(This
);
262 if (This
->dest
) IStream_Release(This
->dest
);
263 SysFreeString(This
->version
);
265 xmlOutputBufferClose(This
->buffer
);
266 SysFreeString(This
->element
);
267 release_dispex(&This
->dispex
);
274 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
276 mxwriter
*This
= impl_from_IMXWriter( iface
);
277 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
280 static HRESULT WINAPI
mxwriter_GetTypeInfo(
282 UINT iTInfo
, LCID lcid
,
283 ITypeInfo
** ppTInfo
)
285 mxwriter
*This
= impl_from_IMXWriter( iface
);
286 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
287 iTInfo
, lcid
, ppTInfo
);
290 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
292 REFIID riid
, LPOLESTR
* rgszNames
,
293 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
295 mxwriter
*This
= impl_from_IMXWriter( iface
);
296 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
297 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
300 static HRESULT WINAPI
mxwriter_Invoke(
302 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
303 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
304 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
306 mxwriter
*This
= impl_from_IMXWriter( iface
);
307 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
308 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
311 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
313 mxwriter
*This
= impl_from_IMXWriter( iface
);
316 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
318 hr
= flush_output_buffer(This
);
326 if (This
->dest
) IStream_Release(This
->dest
);
329 /* We need to reset the output buffer to UTF-16, since the only way
330 * the content of the mxwriter can be accessed now is through a BSTR.
332 This
->encoding
= xmlParseCharEncoding("UTF-16");
333 reset_output_buffer(This
);
340 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
343 /* Recreate the output buffer to make sure it's using the correct encoding. */
344 reset_output_buffer(This
);
346 if (This
->dest
) IStream_Release(This
->dest
);
351 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
355 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
362 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
364 mxwriter
*This
= impl_from_IMXWriter( iface
);
366 TRACE("(%p)->(%p)\n", This
, dest
);
370 HRESULT hr
= flush_output_buffer(This
);
374 /* TODO: Windows always seems to re-encode the XML to UTF-16 (this includes
375 * updating the XML decl so it says "UTF-16" instead of "UTF-8"). We don't
376 * support this yet...
378 if (This
->encoding
== XML_CHAR_ENCODING_UTF8
) {
379 FIXME("XML re-encoding not supported yet\n");
383 V_VT(dest
) = VT_BSTR
;
384 V_BSTR(dest
) = SysAllocStringLen((const WCHAR
*)This
->buffer
->conv
->content
,
385 This
->buffer
->conv
->use
/sizeof(WCHAR
));
390 FIXME("not implemented when stream is set up\n");
395 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
397 mxwriter
*This
= impl_from_IMXWriter( iface
);
399 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
401 /* FIXME: filter all supported encodings */
402 if (!strcmpW(encoding
, utf16W
) || !strcmpW(encoding
, utf8W
))
407 hr
= flush_output_buffer(This
);
411 enc
= heap_strdupWtoA(encoding
);
413 return E_OUTOFMEMORY
;
415 This
->encoding
= xmlParseCharEncoding(enc
);
418 reset_output_buffer(This
);
423 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
428 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
430 mxwriter
*This
= impl_from_IMXWriter( iface
);
432 TRACE("(%p)->(%p)\n", This
, encoding
);
434 if (!encoding
) return E_POINTER
;
436 return bstr_from_xmlCharEncoding(This
->encoding
, encoding
);
439 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
441 mxwriter
*This
= impl_from_IMXWriter( iface
);
443 TRACE("(%p)->(%d)\n", This
, value
);
444 return writer_set_property(This
, MXWriter_BOM
, value
);
447 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
449 mxwriter
*This
= impl_from_IMXWriter( iface
);
451 TRACE("(%p)->(%p)\n", This
, value
);
452 return writer_get_property(This
, MXWriter_BOM
, value
);
455 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
457 mxwriter
*This
= impl_from_IMXWriter( iface
);
459 TRACE("(%p)->(%d)\n", This
, value
);
460 return writer_set_property(This
, MXWriter_Indent
, value
);
463 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
465 mxwriter
*This
= impl_from_IMXWriter( iface
);
467 TRACE("(%p)->(%p)\n", This
, value
);
468 return writer_get_property(This
, MXWriter_Indent
, value
);
471 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
473 mxwriter
*This
= impl_from_IMXWriter( iface
);
475 TRACE("(%p)->(%d)\n", This
, value
);
476 return writer_set_property(This
, MXWriter_Standalone
, value
);
479 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
481 mxwriter
*This
= impl_from_IMXWriter( iface
);
483 TRACE("(%p)->(%p)\n", This
, value
);
484 return writer_get_property(This
, MXWriter_Standalone
, value
);
487 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
489 mxwriter
*This
= impl_from_IMXWriter( iface
);
491 TRACE("(%p)->(%d)\n", This
, value
);
492 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
495 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
497 mxwriter
*This
= impl_from_IMXWriter( iface
);
499 TRACE("(%p)->(%p)\n", This
, value
);
500 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
503 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
505 mxwriter
*This
= impl_from_IMXWriter( iface
);
507 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
509 if (!version
) return E_INVALIDARG
;
511 SysFreeString(This
->version
);
512 This
->version
= SysAllocString(version
);
517 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
519 mxwriter
*This
= impl_from_IMXWriter( iface
);
521 TRACE("(%p)->(%p)\n", This
, version
);
523 if (!version
) return E_POINTER
;
525 return return_bstr(This
->version
, version
);
528 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
530 mxwriter
*This
= impl_from_IMXWriter( iface
);
532 TRACE("(%p)->(%d)\n", This
, value
);
533 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
536 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
538 mxwriter
*This
= impl_from_IMXWriter( iface
);
540 TRACE("(%p)->(%p)\n", This
, value
);
541 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
544 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
546 mxwriter
*This
= impl_from_IMXWriter( iface
);
547 TRACE("(%p)\n", This
);
548 return flush_output_buffer(This
);
551 static const struct IMXWriterVtbl MXWriterVtbl
=
553 mxwriter_QueryInterface
,
556 mxwriter_GetTypeInfoCount
,
557 mxwriter_GetTypeInfo
,
558 mxwriter_GetIDsOfNames
,
562 mxwriter_put_encoding
,
563 mxwriter_get_encoding
,
564 mxwriter_put_byteOrderMark
,
565 mxwriter_get_byteOrderMark
,
568 mxwriter_put_standalone
,
569 mxwriter_get_standalone
,
570 mxwriter_put_omitXMLDeclaration
,
571 mxwriter_get_omitXMLDeclaration
,
572 mxwriter_put_version
,
573 mxwriter_get_version
,
574 mxwriter_put_disableOutputEscaping
,
575 mxwriter_get_disableOutputEscaping
,
579 /*** ISAXContentHandler ***/
580 static HRESULT WINAPI
mxwriter_saxcontent_QueryInterface(
581 ISAXContentHandler
*iface
,
585 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
586 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
589 static ULONG WINAPI
mxwriter_saxcontent_AddRef(ISAXContentHandler
*iface
)
591 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
592 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
595 static ULONG WINAPI
mxwriter_saxcontent_Release(ISAXContentHandler
*iface
)
597 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
598 return IMXWriter_Release(&This
->IMXWriter_iface
);
601 static HRESULT WINAPI
mxwriter_saxcontent_putDocumentLocator(
602 ISAXContentHandler
*iface
,
603 ISAXLocator
*locator
)
605 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
606 FIXME("(%p)->(%p)\n", This
, locator
);
610 static HRESULT WINAPI
mxwriter_saxcontent_startDocument(ISAXContentHandler
*iface
)
612 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
615 TRACE("(%p)\n", This
);
617 /* If properties have been changed since the last "endDocument" call
618 * we need to reset the output buffer. If we don't the output buffer
619 * could end up with multiple XML documents in it, plus this seems to
620 * be how Windows works.
622 if (This
->prop_changed
) {
623 reset_output_buffer(This
);
624 This
->prop_changed
= FALSE
;
627 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
630 xmlOutputBufferWriteString(This
->buffer
, "<?xml version=\"");
631 s
= xmlchar_from_wchar(This
->version
);
632 xmlOutputBufferWriteString(This
->buffer
, (char*)s
);
634 xmlOutputBufferWriteString(This
->buffer
, "\"");
637 xmlOutputBufferWriteString(This
->buffer
, " encoding=\"");
638 xmlOutputBufferWriteString(This
->buffer
, xmlGetCharEncodingName(This
->encoding
));
639 xmlOutputBufferWriteString(This
->buffer
, "\"");
642 xmlOutputBufferWriteString(This
->buffer
, " standalone=\"");
643 if (This
->props
[MXWriter_Standalone
] == VARIANT_TRUE
)
644 xmlOutputBufferWriteString(This
->buffer
, "yes\"?>");
646 xmlOutputBufferWriteString(This
->buffer
, "no\"?>");
648 xmlOutputBufferWriteString(This
->buffer
, crlfA
);
650 if (This
->dest
&& This
->encoding
== XML_CHAR_ENCODING_UTF16LE
) {
651 static const CHAR utf16BOM
[] = {0xff,0xfe};
653 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
654 /* Windows passes a NULL pointer as the pcbWritten parameter and
655 * ignores any error codes returned from this Write call.
657 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
663 static HRESULT WINAPI
mxwriter_saxcontent_endDocument(ISAXContentHandler
*iface
)
665 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
666 TRACE("(%p)\n", This
);
667 This
->prop_changed
= FALSE
;
668 return flush_output_buffer(This
);
671 static HRESULT WINAPI
mxwriter_saxcontent_startPrefixMapping(
672 ISAXContentHandler
*iface
,
678 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
679 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
683 static HRESULT WINAPI
mxwriter_saxcontent_endPrefixMapping(
684 ISAXContentHandler
*iface
,
688 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
689 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
693 static HRESULT WINAPI
mxwriter_saxcontent_startElement(
694 ISAXContentHandler
*iface
,
695 const WCHAR
*namespaceUri
,
697 const WCHAR
*local_name
,
701 ISAXAttributes
*attr
)
703 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
706 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
707 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
709 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
712 close_element_starttag(This
);
713 set_element_name(This
, QName
? QName
: emptyW
,
716 xmlOutputBufferWriteString(This
->buffer
, "<");
717 s
= xmlchar_from_wcharn(QName
, nQName
);
718 xmlOutputBufferWriteString(This
->buffer
, (char*)s
);
727 hr
= ISAXAttributes_getLength(attr
, &length
);
728 if (FAILED(hr
)) return hr
;
730 for (i
= 0; i
< length
; i
++)
735 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
736 if (FAILED(hr
)) return hr
;
738 /* space separator in front of every attribute */
739 xmlOutputBufferWriteString(This
->buffer
, " ");
741 s
= xmlchar_from_wcharn(str
, len
);
742 xmlOutputBufferWriteString(This
->buffer
, (char*)s
);
745 xmlOutputBufferWriteString(This
->buffer
, "=\"");
748 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
749 if (FAILED(hr
)) return hr
;
751 s
= xmlchar_from_wcharn(str
, len
);
752 xmlOutputBufferWriteString(This
->buffer
, (char*)s
);
755 xmlOutputBufferWriteString(This
->buffer
, "\"");
762 static HRESULT WINAPI
mxwriter_saxcontent_endElement(
763 ISAXContentHandler
*iface
,
764 const WCHAR
*namespaceUri
,
766 const WCHAR
* local_name
,
771 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
773 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
774 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
776 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
779 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
781 xmlOutputBufferWriteString(This
->buffer
, "/>");
785 xmlChar
*s
= xmlchar_from_wcharn(QName
, nQName
);
787 xmlOutputBufferWriteString(This
->buffer
, "</");
788 xmlOutputBufferWriteString(This
->buffer
, (char*)s
);
789 xmlOutputBufferWriteString(This
->buffer
, ">");
794 set_element_name(This
, NULL
, 0);
799 static HRESULT WINAPI
mxwriter_saxcontent_characters(
800 ISAXContentHandler
*iface
,
804 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
806 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
808 if (!chars
) return E_INVALIDARG
;
810 close_element_starttag(This
);
811 set_element_name(This
, NULL
, 0);
815 xmlChar
*s
= xmlchar_from_wcharn(chars
, nchars
);
816 xmlOutputBufferWriteString(This
->buffer
, (char*)s
);
823 static HRESULT WINAPI
mxwriter_saxcontent_ignorableWhitespace(
824 ISAXContentHandler
*iface
,
828 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
829 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
833 static HRESULT WINAPI
mxwriter_saxcontent_processingInstruction(
834 ISAXContentHandler
*iface
,
840 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
841 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
845 static HRESULT WINAPI
mxwriter_saxcontent_skippedEntity(
846 ISAXContentHandler
*iface
,
850 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
851 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
855 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl
=
857 mxwriter_saxcontent_QueryInterface
,
858 mxwriter_saxcontent_AddRef
,
859 mxwriter_saxcontent_Release
,
860 mxwriter_saxcontent_putDocumentLocator
,
861 mxwriter_saxcontent_startDocument
,
862 mxwriter_saxcontent_endDocument
,
863 mxwriter_saxcontent_startPrefixMapping
,
864 mxwriter_saxcontent_endPrefixMapping
,
865 mxwriter_saxcontent_startElement
,
866 mxwriter_saxcontent_endElement
,
867 mxwriter_saxcontent_characters
,
868 mxwriter_saxcontent_ignorableWhitespace
,
869 mxwriter_saxcontent_processingInstruction
,
870 mxwriter_saxcontent_skippedEntity
873 static const tid_t mxwriter_iface_tids
[] = {
878 static dispex_static_data_t mxwriter_dispex
= {
885 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
887 static const WCHAR version10W
[] = {'1','.','0',0};
890 TRACE("(%p, %p)\n", outer
, ppObj
);
892 if (outer
) FIXME("support aggregation, outer\n");
894 This
= heap_alloc( sizeof (*This
) );
896 return E_OUTOFMEMORY
;
898 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
899 This
->ISAXContentHandler_iface
.lpVtbl
= &mxwriter_saxcontent_vtbl
;
901 This
->class_version
= version
;
903 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
904 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
905 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
906 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
907 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
908 This
->prop_changed
= FALSE
;
909 This
->encoding
= xmlParseCharEncoding("UTF-16");
910 This
->version
= SysAllocString(version10W
);
912 This
->element
= NULL
;
915 This
->dest_written
= 0;
917 This
->buffer
= xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This
->encoding
));
919 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
921 *ppObj
= &This
->IMXWriter_iface
;
923 TRACE("returning iface %p\n", *ppObj
);
930 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **obj
)
932 MESSAGE("This program tried to use a MXXMLWriter object, but\n"
933 "libxml2 support was not present at compile time.\n");
937 #endif /* HAVE_LIBXML2 */