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
,
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 int decl_count
; /* practically how many times startDocument was called */
82 int decl_written
; /* byte length of document prolog */
84 xmlOutputBufferPtr buffer
;
87 static HRESULT
bstr_from_xmlCharEncoding(xmlCharEncoding enc
, BSTR
*encoding
)
89 const char *encodingA
;
91 if (enc
!= XML_CHAR_ENCODING_UTF16LE
&& enc
!= XML_CHAR_ENCODING_UTF8
) {
92 FIXME("Unsupported xmlCharEncoding: %d\n", enc
);
97 encodingA
= xmlGetCharEncodingName(enc
);
99 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, encodingA
, -1, NULL
, 0);
100 *encoding
= SysAllocStringLen(NULL
, len
-1);
102 MultiByteToWideChar( CP_ACP
, 0, encodingA
, -1, *encoding
, len
);
104 *encoding
= SysAllocStringLen(NULL
, 0);
106 return *encoding
? S_OK
: E_OUTOFMEMORY
;
109 /* escapes special characters like:
115 static WCHAR
*get_escaped_string(const WCHAR
*str
, int *len
)
117 static const WCHAR ltW
[] = {'&','l','t',';'};
118 static const WCHAR ampW
[] = {'&','a','m','p',';'};
119 static const WCHAR quotW
[] = {'&','q','u','o','t',';'};
120 static const WCHAR gtW
[] = {'&','g','t',';'};
122 const int default_alloc
= 100;
123 const int grow_thresh
= 10;
124 int p
= *len
, conv_len
;
127 /* default buffer size to something if length is unknown */
128 conv_len
= *len
== -1 ? default_alloc
: max(2**len
, default_alloc
);
129 ptr
= ret
= heap_alloc(conv_len
*sizeof(WCHAR
));
133 if (ptr
- ret
> conv_len
- grow_thresh
)
135 int written
= ptr
- ret
;
137 ptr
= ret
= heap_realloc(ret
, conv_len
*sizeof(WCHAR
));
144 memcpy(ptr
, ltW
, sizeof(ltW
));
145 ptr
+= sizeof(ltW
)/sizeof(WCHAR
);
148 memcpy(ptr
, ampW
, sizeof(ampW
));
149 ptr
+= sizeof(ampW
)/sizeof(WCHAR
);
152 memcpy(ptr
, quotW
, sizeof(quotW
));
153 ptr
+= sizeof(quotW
)/sizeof(WCHAR
);
156 memcpy(ptr
, gtW
, sizeof(gtW
));
157 ptr
+= sizeof(gtW
)/sizeof(WCHAR
);
168 if (*len
!= -1) *len
= ptr
-ret
;
174 /* creates UTF-8 encoded prolog string with specified or store encoding value */
175 static int write_prolog_buffer(const mxwriter
*This
, xmlCharEncoding enc
, xmlOutputBufferPtr buffer
)
177 static const char version
[] = "<?xml version=\"";
178 static const char encoding
[] = " encoding=\"";
179 static const char standalone
[] = " standalone=\"";
180 static const char yes
[] = "yes\"?>";
181 static const char no
[] = "no\"?>";
186 if (enc
== XML_CHAR_ENCODING_UTF8
)
187 buf
= buffer
->buffer
;
194 xmlOutputBufferWrite(buffer
, sizeof(version
)-1, version
);
195 s
= xmlchar_from_wchar(This
->version
);
196 xmlOutputBufferWriteString(buffer
, (char*)s
);
198 xmlOutputBufferWrite(buffer
, 1, "\"");
201 xmlOutputBufferWrite(buffer
, sizeof(encoding
)-1, encoding
);
202 xmlOutputBufferWriteString(buffer
, xmlGetCharEncodingName(enc
));
203 xmlOutputBufferWrite(buffer
, 1, "\"");
206 xmlOutputBufferWrite(buffer
, sizeof(standalone
)-1, standalone
);
207 if (This
->props
[MXWriter_Standalone
] == VARIANT_TRUE
)
208 xmlOutputBufferWrite(buffer
, sizeof(yes
)-1, yes
);
210 xmlOutputBufferWrite(buffer
, sizeof(no
)-1, no
);
212 xmlOutputBufferWrite(buffer
, sizeof(crlfA
)-1, crlfA
);
213 xmlOutputBufferFlush(buffer
);
215 return buf
->use
- use
;
218 /* Attempts to the write data from the mxwriter's buffer to
219 * the destination stream (if there is one).
221 static HRESULT
write_data_to_stream(mxwriter
*This
)
230 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
231 * 'conv' buffer when UTF8 encoding is used.
233 if (This
->encoding
== XML_CHAR_ENCODING_UTF8
)
234 buffer
= This
->buffer
->buffer
;
236 buffer
= This
->buffer
->conv
;
238 if (This
->dest_written
> buffer
->use
) {
239 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This
->dest_written
, buffer
->use
);
241 } else if (This
->dest_written
== buffer
->use
&& This
->encoding
!= XML_CHAR_ENCODING_UTF8
)
242 /* Windows seems to make an empty write call when the encoding is UTF-8 and
243 * all the data has been written to the stream. It doesn't seem make this call
244 * for any other encodings.
248 /* Write the current content from the output buffer into 'dest'.
249 * TODO: Check what Windows does if the IStream doesn't write all of
250 * the data we give it at once.
252 hr
= IStream_Write(This
->dest
, buffer
->content
+This
->dest_written
,
253 buffer
->use
-This
->dest_written
, &written
);
255 WARN("Failed to write data to IStream (0x%08x)\n", hr
);
259 This
->dest_written
+= written
;
263 static void write_output_buffer(const mxwriter
*This
, const char *data
, int len
)
265 xmlOutputBufferWrite(This
->buffer
, len
, data
);
268 static void write_output_buffer_str(const mxwriter
*This
, const char *data
)
270 xmlOutputBufferWriteString(This
->buffer
, data
);
273 /* Newly added element start tag left unclosed cause for empty elements
274 we have to close it differently. */
275 static void close_element_starttag(const mxwriter
*This
)
277 static const char gt
= '>';
278 if (!This
->element
) return;
279 write_output_buffer(This
, >
, 1);
282 static void set_element_name(mxwriter
*This
, const WCHAR
*name
, int len
)
284 SysFreeString(This
->element
);
285 This
->element
= name
? SysAllocStringLen(name
, len
) : NULL
;
288 static inline HRESULT
flush_output_buffer(mxwriter
*This
)
290 close_element_starttag(This
);
291 set_element_name(This
, NULL
, 0);
292 xmlOutputBufferFlush(This
->buffer
);
293 return write_data_to_stream(This
);
296 /* Resets the mxwriter's output buffer by closing it, then creating a new
297 * output buffer using the given encoding.
299 static inline void reset_output_buffer(mxwriter
*This
)
301 xmlOutputBufferClose(This
->buffer
);
302 This
->buffer
= xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This
->encoding
));
303 This
->dest_written
= 0;
304 This
->decl_count
= 0;
305 This
->decl_written
= 0;
308 static HRESULT
writer_set_property(mxwriter
*writer
, MXWRITER_PROPS property
, VARIANT_BOOL value
)
310 writer
->props
[property
] = value
;
311 writer
->prop_changed
= TRUE
;
315 static HRESULT
writer_get_property(const mxwriter
*writer
, MXWRITER_PROPS property
, VARIANT_BOOL
*value
)
317 if (!value
) return E_POINTER
;
318 *value
= writer
->props
[property
];
322 static inline mxwriter
*impl_from_IMXWriter(IMXWriter
*iface
)
324 return CONTAINING_RECORD(iface
, mxwriter
, IMXWriter_iface
);
327 static inline mxwriter
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
329 return CONTAINING_RECORD(iface
, mxwriter
, ISAXContentHandler_iface
);
332 static HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
334 mxwriter
*This
= impl_from_IMXWriter( iface
);
336 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
340 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
341 IsEqualGUID( riid
, &IID_IDispatch
) ||
342 IsEqualGUID( riid
, &IID_IUnknown
) )
344 *obj
= &This
->IMXWriter_iface
;
346 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
348 *obj
= &This
->ISAXContentHandler_iface
;
350 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
352 return *obj
? S_OK
: E_NOINTERFACE
;
356 ERR("interface %s not implemented\n", debugstr_guid(riid
));
358 return E_NOINTERFACE
;
361 IMXWriter_AddRef(iface
);
365 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
367 mxwriter
*This
= impl_from_IMXWriter( iface
);
368 LONG ref
= InterlockedIncrement(&This
->ref
);
370 TRACE("(%p)->(%d)\n", This
, ref
);
375 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
377 mxwriter
*This
= impl_from_IMXWriter( iface
);
378 ULONG ref
= InterlockedDecrement(&This
->ref
);
380 TRACE("(%p)->(%d)\n", This
, ref
);
384 /* Windows flushes the buffer when the interface is destroyed. */
385 flush_output_buffer(This
);
387 if (This
->dest
) IStream_Release(This
->dest
);
388 SysFreeString(This
->version
);
390 xmlOutputBufferClose(This
->buffer
);
391 SysFreeString(This
->element
);
392 release_dispex(&This
->dispex
);
399 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
401 mxwriter
*This
= impl_from_IMXWriter( iface
);
402 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
405 static HRESULT WINAPI
mxwriter_GetTypeInfo(
407 UINT iTInfo
, LCID lcid
,
408 ITypeInfo
** ppTInfo
)
410 mxwriter
*This
= impl_from_IMXWriter( iface
);
411 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
412 iTInfo
, lcid
, ppTInfo
);
415 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
417 REFIID riid
, LPOLESTR
* rgszNames
,
418 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
420 mxwriter
*This
= impl_from_IMXWriter( iface
);
421 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
422 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
425 static HRESULT WINAPI
mxwriter_Invoke(
427 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
428 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
429 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
431 mxwriter
*This
= impl_from_IMXWriter( iface
);
432 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
433 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
436 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
438 mxwriter
*This
= impl_from_IMXWriter( iface
);
441 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
443 hr
= flush_output_buffer(This
);
451 if (This
->dest
) IStream_Release(This
->dest
);
453 reset_output_buffer(This
);
460 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
463 /* Recreate the output buffer to make sure it's using the correct encoding. */
464 reset_output_buffer(This
);
466 if (This
->dest
) IStream_Release(This
->dest
);
471 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
475 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
482 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
484 mxwriter
*This
= impl_from_IMXWriter( iface
);
486 TRACE("(%p)->(%p)\n", This
, dest
);
490 xmlOutputBufferPtr prolog
;
491 BSTR output
, body
= NULL
;
497 hr
= flush_output_buffer(This
);
501 if (This
->decl_count
)
503 prolog
= xmlAllocOutputBuffer(xmlGetCharEncodingHandler(xmlParseCharEncoding("UTF-16")));
504 write_prolog_buffer(This
, xmlParseCharEncoding("UTF-16"), prolog
);
509 /* optimize some paticular cases */
510 /* 1. no prolog and UTF-8 buffer */
511 if (This
->encoding
== XML_CHAR_ENCODING_UTF8
&& !prolog
)
513 V_VT(dest
) = VT_BSTR
;
514 V_BSTR(dest
) = bstr_from_xmlChar(This
->buffer
->buffer
->content
);
518 /* 2. no prolog and UTF-16 buffer */
521 V_VT(dest
) = VT_BSTR
;
522 V_BSTR(dest
) = SysAllocStringLen((const WCHAR
*)This
->buffer
->conv
->content
,
523 This
->buffer
->conv
->use
/sizeof(WCHAR
));
529 if (This
->encoding
== XML_CHAR_ENCODING_UTF8
)
531 buffer
= This
->buffer
->buffer
;
532 body
= bstr_from_xmlChar(buffer
->content
+This
->decl_written
);
533 ptr
= output
= SysAllocStringByteLen(NULL
, prolog
->conv
->use
*This
->decl_count
+
534 SysStringByteLen(body
));
538 buffer
= This
->buffer
->conv
;
539 ptr
= output
= SysAllocStringByteLen(NULL
, prolog
->conv
->use
*This
->decl_count
+
540 buffer
->use
- This
->decl_written
);
543 /* write prolog part */
544 i
= This
->decl_count
;
547 memcpy(ptr
, prolog
->conv
->content
, prolog
->conv
->use
);
548 ptr
+= prolog
->conv
->use
/sizeof(WCHAR
);
550 xmlOutputBufferClose(prolog
);
552 /* write main part */
555 memcpy(ptr
, body
, SysStringByteLen(body
));
559 memcpy(ptr
, buffer
->content
+ This
->decl_written
, buffer
->use
-This
->decl_written
);
561 V_VT(dest
) = VT_BSTR
;
562 V_BSTR(dest
) = output
;
567 FIXME("not implemented when stream is set up\n");
572 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
574 mxwriter
*This
= impl_from_IMXWriter( iface
);
576 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
578 /* FIXME: filter all supported encodings */
579 if (!strcmpW(encoding
, utf16W
) || !strcmpW(encoding
, utf8W
))
584 hr
= flush_output_buffer(This
);
588 enc
= heap_strdupWtoA(encoding
);
590 return E_OUTOFMEMORY
;
592 This
->encoding
= xmlParseCharEncoding(enc
);
595 TRACE("got encoding %d\n", This
->encoding
);
596 reset_output_buffer(This
);
601 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
606 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
608 mxwriter
*This
= impl_from_IMXWriter( iface
);
610 TRACE("(%p)->(%p)\n", This
, encoding
);
612 if (!encoding
) return E_POINTER
;
614 return bstr_from_xmlCharEncoding(This
->encoding
, encoding
);
617 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
619 mxwriter
*This
= impl_from_IMXWriter( iface
);
621 TRACE("(%p)->(%d)\n", This
, value
);
622 return writer_set_property(This
, MXWriter_BOM
, value
);
625 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
627 mxwriter
*This
= impl_from_IMXWriter( iface
);
629 TRACE("(%p)->(%p)\n", This
, value
);
630 return writer_get_property(This
, MXWriter_BOM
, value
);
633 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
635 mxwriter
*This
= impl_from_IMXWriter( iface
);
637 TRACE("(%p)->(%d)\n", This
, value
);
638 return writer_set_property(This
, MXWriter_Indent
, value
);
641 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
643 mxwriter
*This
= impl_from_IMXWriter( iface
);
645 TRACE("(%p)->(%p)\n", This
, value
);
646 return writer_get_property(This
, MXWriter_Indent
, value
);
649 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
651 mxwriter
*This
= impl_from_IMXWriter( iface
);
653 TRACE("(%p)->(%d)\n", This
, value
);
654 return writer_set_property(This
, MXWriter_Standalone
, value
);
657 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
659 mxwriter
*This
= impl_from_IMXWriter( iface
);
661 TRACE("(%p)->(%p)\n", This
, value
);
662 return writer_get_property(This
, MXWriter_Standalone
, value
);
665 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
667 mxwriter
*This
= impl_from_IMXWriter( iface
);
669 TRACE("(%p)->(%d)\n", This
, value
);
670 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
673 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
675 mxwriter
*This
= impl_from_IMXWriter( iface
);
677 TRACE("(%p)->(%p)\n", This
, value
);
678 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
681 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
683 mxwriter
*This
= impl_from_IMXWriter( iface
);
685 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
687 if (!version
) return E_INVALIDARG
;
689 SysFreeString(This
->version
);
690 This
->version
= SysAllocString(version
);
695 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
697 mxwriter
*This
= impl_from_IMXWriter( iface
);
699 TRACE("(%p)->(%p)\n", This
, version
);
701 if (!version
) return E_POINTER
;
703 return return_bstr(This
->version
, version
);
706 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
708 mxwriter
*This
= impl_from_IMXWriter( iface
);
710 TRACE("(%p)->(%d)\n", This
, value
);
711 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
714 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
716 mxwriter
*This
= impl_from_IMXWriter( iface
);
718 TRACE("(%p)->(%p)\n", This
, value
);
719 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
722 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
724 mxwriter
*This
= impl_from_IMXWriter( iface
);
725 TRACE("(%p)\n", This
);
726 return flush_output_buffer(This
);
729 static const struct IMXWriterVtbl MXWriterVtbl
=
731 mxwriter_QueryInterface
,
734 mxwriter_GetTypeInfoCount
,
735 mxwriter_GetTypeInfo
,
736 mxwriter_GetIDsOfNames
,
740 mxwriter_put_encoding
,
741 mxwriter_get_encoding
,
742 mxwriter_put_byteOrderMark
,
743 mxwriter_get_byteOrderMark
,
746 mxwriter_put_standalone
,
747 mxwriter_get_standalone
,
748 mxwriter_put_omitXMLDeclaration
,
749 mxwriter_get_omitXMLDeclaration
,
750 mxwriter_put_version
,
751 mxwriter_get_version
,
752 mxwriter_put_disableOutputEscaping
,
753 mxwriter_get_disableOutputEscaping
,
757 /*** ISAXContentHandler ***/
758 static HRESULT WINAPI
mxwriter_saxcontent_QueryInterface(
759 ISAXContentHandler
*iface
,
763 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
764 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
767 static ULONG WINAPI
mxwriter_saxcontent_AddRef(ISAXContentHandler
*iface
)
769 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
770 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
773 static ULONG WINAPI
mxwriter_saxcontent_Release(ISAXContentHandler
*iface
)
775 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
776 return IMXWriter_Release(&This
->IMXWriter_iface
);
779 static HRESULT WINAPI
mxwriter_saxcontent_putDocumentLocator(
780 ISAXContentHandler
*iface
,
781 ISAXLocator
*locator
)
783 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
784 FIXME("(%p)->(%p)\n", This
, locator
);
788 static HRESULT WINAPI
mxwriter_saxcontent_startDocument(ISAXContentHandler
*iface
)
790 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
792 TRACE("(%p)\n", This
);
794 /* If properties have been changed since the last "endDocument" call
795 * we need to reset the output buffer. If we don't the output buffer
796 * could end up with multiple XML documents in it, plus this seems to
797 * be how Windows works.
799 if (This
->prop_changed
) {
800 reset_output_buffer(This
);
801 This
->prop_changed
= FALSE
;
804 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
807 This
->decl_written
+= write_prolog_buffer(This
, This
->encoding
, This
->buffer
);
809 if (This
->dest
&& This
->encoding
== XML_CHAR_ENCODING_UTF16LE
) {
810 static const CHAR utf16BOM
[] = {0xff,0xfe};
812 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
813 /* Windows passes a NULL pointer as the pcbWritten parameter and
814 * ignores any error codes returned from this Write call.
816 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
822 static HRESULT WINAPI
mxwriter_saxcontent_endDocument(ISAXContentHandler
*iface
)
824 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
825 TRACE("(%p)\n", This
);
826 This
->prop_changed
= FALSE
;
827 return flush_output_buffer(This
);
830 static HRESULT WINAPI
mxwriter_saxcontent_startPrefixMapping(
831 ISAXContentHandler
*iface
,
837 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
838 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
842 static HRESULT WINAPI
mxwriter_saxcontent_endPrefixMapping(
843 ISAXContentHandler
*iface
,
847 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
848 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
852 static HRESULT WINAPI
mxwriter_saxcontent_startElement(
853 ISAXContentHandler
*iface
,
854 const WCHAR
*namespaceUri
,
856 const WCHAR
*local_name
,
860 ISAXAttributes
*attr
)
862 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
865 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
866 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
868 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
871 close_element_starttag(This
);
872 set_element_name(This
, QName
? QName
: emptyW
,
875 write_output_buffer(This
, "<", 1);
876 s
= xmlchar_from_wcharn(QName
, nQName
);
877 write_output_buffer_str(This
, (char*)s
);
886 hr
= ISAXAttributes_getLength(attr
, &length
);
887 if (FAILED(hr
)) return hr
;
889 for (i
= 0; i
< length
; i
++)
895 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
896 if (FAILED(hr
)) return hr
;
898 /* space separator in front of every attribute */
899 write_output_buffer(This
, " ", 1);
901 s
= xmlchar_from_wcharn(str
, len
);
902 write_output_buffer_str(This
, (char*)s
);
905 write_output_buffer(This
, "=\"", 2);
908 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
909 if (FAILED(hr
)) return hr
;
911 escaped
= get_escaped_string(str
, &len
);
912 s
= xmlchar_from_wcharn(escaped
, len
);
913 write_output_buffer_str(This
, (char*)s
);
917 write_output_buffer(This
, "\"", 1);
924 static HRESULT WINAPI
mxwriter_saxcontent_endElement(
925 ISAXContentHandler
*iface
,
926 const WCHAR
*namespaceUri
,
928 const WCHAR
* local_name
,
933 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
935 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
936 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
938 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
941 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
943 write_output_buffer(This
, "/>", 2);
947 xmlChar
*s
= xmlchar_from_wcharn(QName
, nQName
);
949 write_output_buffer(This
, "</", 2);
950 write_output_buffer_str(This
, (char*)s
);
951 write_output_buffer(This
, ">", 1);
956 set_element_name(This
, NULL
, 0);
961 static HRESULT WINAPI
mxwriter_saxcontent_characters(
962 ISAXContentHandler
*iface
,
966 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
968 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
970 if (!chars
) return E_INVALIDARG
;
972 close_element_starttag(This
);
973 set_element_name(This
, NULL
, 0);
977 xmlChar
*s
= xmlchar_from_wcharn(chars
, nchars
);
978 write_output_buffer_str(This
, (char*)s
);
985 static HRESULT WINAPI
mxwriter_saxcontent_ignorableWhitespace(
986 ISAXContentHandler
*iface
,
990 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
991 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
995 static HRESULT WINAPI
mxwriter_saxcontent_processingInstruction(
996 ISAXContentHandler
*iface
,
1002 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1003 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
1007 static HRESULT WINAPI
mxwriter_saxcontent_skippedEntity(
1008 ISAXContentHandler
*iface
,
1012 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1013 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
1017 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl
=
1019 mxwriter_saxcontent_QueryInterface
,
1020 mxwriter_saxcontent_AddRef
,
1021 mxwriter_saxcontent_Release
,
1022 mxwriter_saxcontent_putDocumentLocator
,
1023 mxwriter_saxcontent_startDocument
,
1024 mxwriter_saxcontent_endDocument
,
1025 mxwriter_saxcontent_startPrefixMapping
,
1026 mxwriter_saxcontent_endPrefixMapping
,
1027 mxwriter_saxcontent_startElement
,
1028 mxwriter_saxcontent_endElement
,
1029 mxwriter_saxcontent_characters
,
1030 mxwriter_saxcontent_ignorableWhitespace
,
1031 mxwriter_saxcontent_processingInstruction
,
1032 mxwriter_saxcontent_skippedEntity
1035 static const tid_t mxwriter_iface_tids
[] = {
1040 static dispex_static_data_t mxwriter_dispex
= {
1047 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
1049 static const WCHAR version10W
[] = {'1','.','0',0};
1052 TRACE("(%p, %p)\n", outer
, ppObj
);
1054 if (outer
) FIXME("support aggregation, outer\n");
1056 This
= heap_alloc( sizeof (*This
) );
1058 return E_OUTOFMEMORY
;
1060 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
1061 This
->ISAXContentHandler_iface
.lpVtbl
= &mxwriter_saxcontent_vtbl
;
1063 This
->class_version
= version
;
1065 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
1066 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
1067 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
1068 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
1069 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
1070 This
->prop_changed
= FALSE
;
1071 This
->encoding
= xmlParseCharEncoding("UTF-16");
1072 This
->version
= SysAllocString(version10W
);
1074 This
->element
= NULL
;
1076 This
->decl_count
= 0;
1077 This
->decl_written
= 0;
1080 This
->dest_written
= 0;
1082 This
->buffer
= xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This
->encoding
));
1084 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
1086 *ppObj
= &This
->IMXWriter_iface
;
1088 TRACE("returning iface %p\n", *ppObj
);
1095 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **obj
)
1097 MESSAGE("This program tried to use a MXXMLWriter object, but\n"
1098 "libxml2 support was not present at compile time.\n");
1102 #endif /* HAVE_LIBXML2 */