2 * MXWriter implementation
4 * Copyright 2011-2012 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
);
42 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
43 static const WCHAR emptyW
[] = {0};
44 static const WCHAR spaceW
[] = {' '};
45 static const WCHAR quotW
[] = {'\"'};
56 OutputBuffer_Native
= 0x001,
57 OutputBuffer_Encoded
= 0x010,
58 OutputBuffer_Both
= 0x100
64 MXWriter_DisableEscaping
,
80 unsigned int allocated
;
87 encoded_buffer encoded
;
94 IMXWriter IMXWriter_iface
;
95 ISAXContentHandler ISAXContentHandler_iface
;
96 ISAXLexicalHandler ISAXLexicalHandler_iface
;
97 ISAXDeclHandler ISAXDeclHandler_iface
;
100 MSXML_VERSION class_version
;
102 VARIANT_BOOL props
[MXWriter_LastProp
];
108 BSTR encoding
; /* exact property value */
109 xml_encoding xml_enc
;
111 /* contains a pending (or not closed yet) element name or NULL if
112 we don't have to close */
118 output_buffer
*buffer
;
121 static xml_encoding
parse_encoding_name(const WCHAR
*encoding
)
123 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
124 if (!strcmpiW(encoding
, utf8W
)) return XmlEncoding_UTF8
;
125 if (!strcmpiW(encoding
, utf16W
)) return XmlEncoding_UTF16
;
126 return XmlEncoding_Unknown
;
129 static HRESULT
init_encoded_buffer(encoded_buffer
*buffer
)
131 const int initial_len
= 0x2000;
132 buffer
->data
= heap_alloc(initial_len
);
133 if (!buffer
->data
) return E_OUTOFMEMORY
;
135 memset(buffer
->data
, 0, 4);
136 buffer
->allocated
= initial_len
;
142 static void free_encoded_buffer(encoded_buffer
*buffer
)
144 heap_free(buffer
->data
);
147 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
151 case XmlEncoding_UTF8
:
154 case XmlEncoding_UTF16
:
158 FIXME("unsupported encoding %d\n", encoding
);
165 static HRESULT
alloc_output_buffer(xml_encoding encoding
, output_buffer
**buffer
)
170 ret
= heap_alloc(sizeof(*ret
));
171 if (!ret
) return E_OUTOFMEMORY
;
173 hr
= get_code_page(encoding
, &ret
->code_page
);
179 hr
= init_encoded_buffer(&ret
->utf16
);
185 if (ret
->code_page
== CP_UTF8
) {
186 hr
= init_encoded_buffer(&ret
->encoded
);
188 free_encoded_buffer(&ret
->utf16
);
194 memset(&ret
->encoded
, 0, sizeof(ret
->encoded
));
201 static void free_output_buffer(output_buffer
*buffer
)
203 free_encoded_buffer(&buffer
->encoded
);
204 free_encoded_buffer(&buffer
->utf16
);
208 static void grow_buffer(encoded_buffer
*buffer
, int length
)
210 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
211 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
213 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
214 buffer
->data
= heap_realloc(buffer
->data
, grown_size
);
215 buffer
->allocated
= grown_size
;
219 static HRESULT
write_output_buffer_mode(output_buffer
*buffer
, output_mode mode
, const WCHAR
*data
, int len
)
224 if (mode
& (OutputBuffer_Encoded
| OutputBuffer_Both
)) {
225 if (buffer
->code_page
== CP_UTF8
)
227 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
228 grow_buffer(&buffer
->encoded
, length
);
229 ptr
= buffer
->encoded
.data
+ buffer
->encoded
.written
;
230 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
231 buffer
->encoded
.written
+= len
== -1 ? length
-1 : length
;
235 if (mode
& (OutputBuffer_Native
| OutputBuffer_Both
)) {
236 /* WCHAR data just copied */
237 length
= len
== -1 ? strlenW(data
) : len
;
240 length
*= sizeof(WCHAR
);
242 grow_buffer(&buffer
->utf16
, length
);
243 ptr
= buffer
->utf16
.data
+ buffer
->utf16
.written
;
245 memcpy(ptr
, data
, length
);
246 buffer
->utf16
.written
+= length
;
248 /* null termination */
249 memset(ptr
, 0, sizeof(WCHAR
));
256 static HRESULT
write_output_buffer(output_buffer
*buffer
, const WCHAR
*data
, int len
)
258 return write_output_buffer_mode(buffer
, OutputBuffer_Both
, data
, len
);
261 static HRESULT
write_output_buffer_quoted(output_buffer
*buffer
, const WCHAR
*data
, int len
)
263 write_output_buffer(buffer
, quotW
, 1);
264 write_output_buffer(buffer
, data
, len
);
265 write_output_buffer(buffer
, quotW
, 1);
270 /* frees buffer data, reallocates with a default lengths */
271 static void close_output_buffer(mxwriter
*This
)
273 heap_free(This
->buffer
->utf16
.data
);
274 heap_free(This
->buffer
->encoded
.data
);
275 init_encoded_buffer(&This
->buffer
->utf16
);
276 init_encoded_buffer(&This
->buffer
->encoded
);
277 get_code_page(This
->xml_enc
, &This
->buffer
->code_page
);
280 /* escapes special characters like:
286 static WCHAR
*get_escaped_string(const WCHAR
*str
, escape_mode mode
, int *len
)
288 static const WCHAR ltW
[] = {'&','l','t',';'};
289 static const WCHAR ampW
[] = {'&','a','m','p',';'};
290 static const WCHAR equotW
[] = {'&','q','u','o','t',';'};
291 static const WCHAR gtW
[] = {'&','g','t',';'};
293 const int default_alloc
= 100;
294 const int grow_thresh
= 10;
295 int p
= *len
, conv_len
;
298 /* default buffer size to something if length is unknown */
299 conv_len
= *len
== -1 ? default_alloc
: max(2**len
, default_alloc
);
300 ptr
= ret
= heap_alloc(conv_len
*sizeof(WCHAR
));
304 if (ptr
- ret
> conv_len
- grow_thresh
)
306 int written
= ptr
- ret
;
308 ptr
= ret
= heap_realloc(ret
, conv_len
*sizeof(WCHAR
));
315 memcpy(ptr
, ltW
, sizeof(ltW
));
316 ptr
+= sizeof(ltW
)/sizeof(WCHAR
);
319 memcpy(ptr
, ampW
, sizeof(ampW
));
320 ptr
+= sizeof(ampW
)/sizeof(WCHAR
);
323 memcpy(ptr
, gtW
, sizeof(gtW
));
324 ptr
+= sizeof(gtW
)/sizeof(WCHAR
);
327 if (mode
== EscapeValue
)
329 memcpy(ptr
, equotW
, sizeof(equotW
));
330 ptr
+= sizeof(equotW
)/sizeof(WCHAR
);
333 /* fallthrough for text mode */
343 if (*len
!= -1) *len
= ptr
-ret
;
349 static void write_prolog_buffer(const mxwriter
*This
)
351 static const WCHAR versionW
[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','='};
352 static const WCHAR encodingW
[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
353 static const WCHAR standaloneW
[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
354 static const WCHAR yesW
[] = {'y','e','s','\"','?','>'};
355 static const WCHAR noW
[] = {'n','o','\"','?','>'};
356 static const WCHAR crlfW
[] = {'\r','\n'};
359 write_output_buffer(This
->buffer
, versionW
, sizeof(versionW
)/sizeof(WCHAR
));
360 write_output_buffer_quoted(This
->buffer
, This
->version
, -1);
363 write_output_buffer(This
->buffer
, encodingW
, sizeof(encodingW
)/sizeof(WCHAR
));
365 /* always write UTF-16 to WCHAR buffer */
366 write_output_buffer_mode(This
->buffer
, OutputBuffer_Native
, utf16W
, sizeof(utf16W
)/sizeof(WCHAR
) - 1);
367 write_output_buffer_mode(This
->buffer
, OutputBuffer_Encoded
, This
->encoding
, -1);
368 write_output_buffer(This
->buffer
, quotW
, 1);
371 write_output_buffer(This
->buffer
, standaloneW
, sizeof(standaloneW
)/sizeof(WCHAR
));
372 if (This
->props
[MXWriter_Standalone
] == VARIANT_TRUE
)
373 write_output_buffer(This
->buffer
, yesW
, sizeof(yesW
)/sizeof(WCHAR
));
375 write_output_buffer(This
->buffer
, noW
, sizeof(noW
)/sizeof(WCHAR
));
377 write_output_buffer(This
->buffer
, crlfW
, sizeof(crlfW
)/sizeof(WCHAR
));
380 /* Attempts to the write data from the mxwriter's buffer to
381 * the destination stream (if there is one).
383 static HRESULT
write_data_to_stream(mxwriter
*This
)
385 encoded_buffer
*buffer
;
392 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
393 * 'conv' buffer when UTF8 encoding is used.
395 if (This
->xml_enc
!= XmlEncoding_UTF16
)
396 buffer
= &This
->buffer
->encoded
;
398 buffer
= &This
->buffer
->utf16
;
400 if (This
->dest_written
> buffer
->written
) {
401 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This
->dest_written
, buffer
->written
);
403 } else if (This
->dest_written
== buffer
->written
&& This
->xml_enc
!= XmlEncoding_UTF8
)
404 /* Windows seems to make an empty write call when the encoding is UTF-8 and
405 * all the data has been written to the stream. It doesn't seem make this call
406 * for any other encodings.
410 /* Write the current content from the output buffer into 'dest'.
411 * TODO: Check what Windows does if the IStream doesn't write all of
412 * the data we give it at once.
414 hr
= IStream_Write(This
->dest
, buffer
->data
+This
->dest_written
,
415 buffer
->written
-This
->dest_written
, &written
);
417 WARN("Failed to write data to IStream (0x%08x)\n", hr
);
421 This
->dest_written
+= written
;
425 /* Newly added element start tag left unclosed cause for empty elements
426 we have to close it differently. */
427 static void close_element_starttag(const mxwriter
*This
)
429 static const WCHAR gtW
[] = {'>'};
430 if (!This
->element
) return;
431 write_output_buffer(This
->buffer
, gtW
, 1);
434 static void set_element_name(mxwriter
*This
, const WCHAR
*name
, int len
)
436 SysFreeString(This
->element
);
437 This
->element
= name
? SysAllocStringLen(name
, len
) : NULL
;
440 static inline HRESULT
flush_output_buffer(mxwriter
*This
)
442 close_element_starttag(This
);
443 set_element_name(This
, NULL
, 0);
445 return write_data_to_stream(This
);
448 /* Resets the mxwriter's output buffer by closing it, then creating a new
449 * output buffer using the given encoding.
451 static inline void reset_output_buffer(mxwriter
*This
)
453 close_output_buffer(This
);
454 This
->dest_written
= 0;
457 static HRESULT
writer_set_property(mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL value
)
459 writer
->props
[property
] = value
;
460 writer
->prop_changed
= TRUE
;
464 static HRESULT
writer_get_property(const mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL
*value
)
466 if (!value
) return E_POINTER
;
467 *value
= writer
->props
[property
];
471 static inline mxwriter
*impl_from_IMXWriter(IMXWriter
*iface
)
473 return CONTAINING_RECORD(iface
, mxwriter
, IMXWriter_iface
);
476 static inline mxwriter
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
478 return CONTAINING_RECORD(iface
, mxwriter
, ISAXContentHandler_iface
);
481 static inline mxwriter
*impl_from_ISAXLexicalHandler(ISAXLexicalHandler
*iface
)
483 return CONTAINING_RECORD(iface
, mxwriter
, ISAXLexicalHandler_iface
);
486 static inline mxwriter
*impl_from_ISAXDeclHandler(ISAXDeclHandler
*iface
)
488 return CONTAINING_RECORD(iface
, mxwriter
, ISAXDeclHandler_iface
);
491 static HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
493 mxwriter
*This
= impl_from_IMXWriter( iface
);
495 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
499 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
500 IsEqualGUID( riid
, &IID_IDispatch
) ||
501 IsEqualGUID( riid
, &IID_IUnknown
) )
503 *obj
= &This
->IMXWriter_iface
;
505 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
507 *obj
= &This
->ISAXContentHandler_iface
;
509 else if ( IsEqualGUID( riid
, &IID_ISAXLexicalHandler
) )
511 *obj
= &This
->ISAXLexicalHandler_iface
;
513 else if ( IsEqualGUID( riid
, &IID_ISAXDeclHandler
) )
515 *obj
= &This
->ISAXDeclHandler_iface
;
517 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
519 return *obj
? S_OK
: E_NOINTERFACE
;
523 ERR("interface %s not implemented\n", debugstr_guid(riid
));
525 return E_NOINTERFACE
;
528 IMXWriter_AddRef(iface
);
532 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
534 mxwriter
*This
= impl_from_IMXWriter( iface
);
535 LONG ref
= InterlockedIncrement(&This
->ref
);
537 TRACE("(%p)->(%d)\n", This
, ref
);
542 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
544 mxwriter
*This
= impl_from_IMXWriter( iface
);
545 ULONG ref
= InterlockedDecrement(&This
->ref
);
547 TRACE("(%p)->(%d)\n", This
, ref
);
551 /* Windows flushes the buffer when the interface is destroyed. */
552 flush_output_buffer(This
);
553 free_output_buffer(This
->buffer
);
555 if (This
->dest
) IStream_Release(This
->dest
);
556 SysFreeString(This
->version
);
557 SysFreeString(This
->encoding
);
559 SysFreeString(This
->element
);
560 release_dispex(&This
->dispex
);
567 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
569 mxwriter
*This
= impl_from_IMXWriter( iface
);
570 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
573 static HRESULT WINAPI
mxwriter_GetTypeInfo(
575 UINT iTInfo
, LCID lcid
,
576 ITypeInfo
** ppTInfo
)
578 mxwriter
*This
= impl_from_IMXWriter( iface
);
579 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
580 iTInfo
, lcid
, ppTInfo
);
583 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
585 REFIID riid
, LPOLESTR
* rgszNames
,
586 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
588 mxwriter
*This
= impl_from_IMXWriter( iface
);
589 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
590 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
593 static HRESULT WINAPI
mxwriter_Invoke(
595 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
596 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
597 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
599 mxwriter
*This
= impl_from_IMXWriter( iface
);
600 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
601 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
604 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
606 mxwriter
*This
= impl_from_IMXWriter( iface
);
609 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
611 hr
= flush_output_buffer(This
);
619 if (This
->dest
) IStream_Release(This
->dest
);
621 reset_output_buffer(This
);
628 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
631 /* Recreate the output buffer to make sure it's using the correct encoding. */
632 reset_output_buffer(This
);
634 if (This
->dest
) IStream_Release(This
->dest
);
639 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
643 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
650 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
652 mxwriter
*This
= impl_from_IMXWriter( iface
);
654 TRACE("(%p)->(%p)\n", This
, dest
);
658 HRESULT hr
= flush_output_buffer(This
);
662 V_VT(dest
) = VT_BSTR
;
663 V_BSTR(dest
) = SysAllocString((WCHAR
*)This
->buffer
->utf16
.data
);
668 FIXME("not implemented when stream is set up\n");
673 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
675 mxwriter
*This
= impl_from_IMXWriter( iface
);
679 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
681 enc
= parse_encoding_name(encoding
);
682 if (enc
== XmlEncoding_Unknown
)
684 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
688 hr
= flush_output_buffer(This
);
692 SysReAllocString(&This
->encoding
, encoding
);
695 TRACE("got encoding %d\n", This
->xml_enc
);
696 reset_output_buffer(This
);
700 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
702 mxwriter
*This
= impl_from_IMXWriter( iface
);
704 TRACE("(%p)->(%p)\n", This
, encoding
);
706 if (!encoding
) return E_POINTER
;
708 *encoding
= SysAllocString(This
->encoding
);
709 if (!*encoding
) return E_OUTOFMEMORY
;
714 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
716 mxwriter
*This
= impl_from_IMXWriter( iface
);
718 TRACE("(%p)->(%d)\n", This
, value
);
719 return writer_set_property(This
, MXWriter_BOM
, value
);
722 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
724 mxwriter
*This
= impl_from_IMXWriter( iface
);
726 TRACE("(%p)->(%p)\n", This
, value
);
727 return writer_get_property(This
, MXWriter_BOM
, value
);
730 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
732 mxwriter
*This
= impl_from_IMXWriter( iface
);
734 TRACE("(%p)->(%d)\n", This
, value
);
735 return writer_set_property(This
, MXWriter_Indent
, value
);
738 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
740 mxwriter
*This
= impl_from_IMXWriter( iface
);
742 TRACE("(%p)->(%p)\n", This
, value
);
743 return writer_get_property(This
, MXWriter_Indent
, value
);
746 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
748 mxwriter
*This
= impl_from_IMXWriter( iface
);
750 TRACE("(%p)->(%d)\n", This
, value
);
751 return writer_set_property(This
, MXWriter_Standalone
, value
);
754 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
756 mxwriter
*This
= impl_from_IMXWriter( iface
);
758 TRACE("(%p)->(%p)\n", This
, value
);
759 return writer_get_property(This
, MXWriter_Standalone
, value
);
762 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
764 mxwriter
*This
= impl_from_IMXWriter( iface
);
766 TRACE("(%p)->(%d)\n", This
, value
);
767 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
770 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
772 mxwriter
*This
= impl_from_IMXWriter( iface
);
774 TRACE("(%p)->(%p)\n", This
, value
);
775 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
778 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
780 mxwriter
*This
= impl_from_IMXWriter( iface
);
782 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
784 if (!version
) return E_INVALIDARG
;
786 SysFreeString(This
->version
);
787 This
->version
= SysAllocString(version
);
792 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
794 mxwriter
*This
= impl_from_IMXWriter( iface
);
796 TRACE("(%p)->(%p)\n", This
, version
);
798 if (!version
) return E_POINTER
;
800 return return_bstr(This
->version
, version
);
803 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
805 mxwriter
*This
= impl_from_IMXWriter( iface
);
807 TRACE("(%p)->(%d)\n", This
, value
);
808 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
811 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
813 mxwriter
*This
= impl_from_IMXWriter( iface
);
815 TRACE("(%p)->(%p)\n", This
, value
);
816 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
819 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
821 mxwriter
*This
= impl_from_IMXWriter( iface
);
822 TRACE("(%p)\n", This
);
823 return flush_output_buffer(This
);
826 static const struct IMXWriterVtbl MXWriterVtbl
=
828 mxwriter_QueryInterface
,
831 mxwriter_GetTypeInfoCount
,
832 mxwriter_GetTypeInfo
,
833 mxwriter_GetIDsOfNames
,
837 mxwriter_put_encoding
,
838 mxwriter_get_encoding
,
839 mxwriter_put_byteOrderMark
,
840 mxwriter_get_byteOrderMark
,
843 mxwriter_put_standalone
,
844 mxwriter_get_standalone
,
845 mxwriter_put_omitXMLDeclaration
,
846 mxwriter_get_omitXMLDeclaration
,
847 mxwriter_put_version
,
848 mxwriter_get_version
,
849 mxwriter_put_disableOutputEscaping
,
850 mxwriter_get_disableOutputEscaping
,
854 /*** ISAXContentHandler ***/
855 static HRESULT WINAPI
SAXContentHandler_QueryInterface(
856 ISAXContentHandler
*iface
,
860 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
861 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
864 static ULONG WINAPI
SAXContentHandler_AddRef(ISAXContentHandler
*iface
)
866 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
867 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
870 static ULONG WINAPI
SAXContentHandler_Release(ISAXContentHandler
*iface
)
872 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
873 return IMXWriter_Release(&This
->IMXWriter_iface
);
876 static HRESULT WINAPI
SAXContentHandler_putDocumentLocator(
877 ISAXContentHandler
*iface
,
878 ISAXLocator
*locator
)
880 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
881 FIXME("(%p)->(%p)\n", This
, locator
);
885 static HRESULT WINAPI
SAXContentHandler_startDocument(ISAXContentHandler
*iface
)
887 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
889 TRACE("(%p)\n", This
);
891 /* If properties have been changed since the last "endDocument" call
892 * we need to reset the output buffer. If we don't the output buffer
893 * could end up with multiple XML documents in it, plus this seems to
894 * be how Windows works.
896 if (This
->prop_changed
) {
897 reset_output_buffer(This
);
898 This
->prop_changed
= FALSE
;
901 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
903 write_prolog_buffer(This
);
905 if (This
->dest
&& This
->xml_enc
== XmlEncoding_UTF16
) {
906 static const char utf16BOM
[] = {0xff,0xfe};
908 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
909 /* Windows passes a NULL pointer as the pcbWritten parameter and
910 * ignores any error codes returned from this Write call.
912 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
918 static HRESULT WINAPI
SAXContentHandler_endDocument(ISAXContentHandler
*iface
)
920 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
921 TRACE("(%p)\n", This
);
922 This
->prop_changed
= FALSE
;
923 return flush_output_buffer(This
);
926 static HRESULT WINAPI
SAXContentHandler_startPrefixMapping(
927 ISAXContentHandler
*iface
,
933 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
934 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
938 static HRESULT WINAPI
SAXContentHandler_endPrefixMapping(
939 ISAXContentHandler
*iface
,
943 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
944 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
948 static HRESULT WINAPI
SAXContentHandler_startElement(
949 ISAXContentHandler
*iface
,
950 const WCHAR
*namespaceUri
,
952 const WCHAR
*local_name
,
956 ISAXAttributes
*attr
)
958 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
959 static const WCHAR ltW
[] = {'<'};
961 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
962 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
964 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
967 close_element_starttag(This
);
968 set_element_name(This
, QName
? QName
: emptyW
,
971 write_output_buffer(This
->buffer
, ltW
, 1);
972 write_output_buffer(This
->buffer
, QName
, nQName
);
980 hr
= ISAXAttributes_getLength(attr
, &length
);
981 if (FAILED(hr
)) return hr
;
983 for (i
= 0; i
< length
; i
++)
985 static const WCHAR eqW
[] = {'='};
990 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
991 if (FAILED(hr
)) return hr
;
993 /* space separator in front of every attribute */
994 write_output_buffer(This
->buffer
, spaceW
, 1);
995 write_output_buffer(This
->buffer
, str
, len
);
997 write_output_buffer(This
->buffer
, eqW
, 1);
1000 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
1001 if (FAILED(hr
)) return hr
;
1003 escaped
= get_escaped_string(str
, EscapeValue
, &len
);
1004 write_output_buffer_quoted(This
->buffer
, escaped
, len
);
1012 static HRESULT WINAPI
SAXContentHandler_endElement(
1013 ISAXContentHandler
*iface
,
1014 const WCHAR
*namespaceUri
,
1016 const WCHAR
* local_name
,
1021 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1023 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
1024 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
1026 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
1027 return E_INVALIDARG
;
1029 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
1031 static const WCHAR closeW
[] = {'/','>'};
1033 write_output_buffer(This
->buffer
, closeW
, 2);
1037 static const WCHAR closetagW
[] = {'<','/'};
1038 static const WCHAR gtW
[] = {'>'};
1040 write_output_buffer(This
->buffer
, closetagW
, 2);
1041 write_output_buffer(This
->buffer
, QName
, nQName
);
1042 write_output_buffer(This
->buffer
, gtW
, 1);
1045 set_element_name(This
, NULL
, 0);
1050 static HRESULT WINAPI
SAXContentHandler_characters(
1051 ISAXContentHandler
*iface
,
1055 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1057 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1059 if (!chars
) return E_INVALIDARG
;
1061 close_element_starttag(This
);
1062 set_element_name(This
, NULL
, 0);
1067 write_output_buffer(This
->buffer
, chars
, nchars
);
1073 escaped
= get_escaped_string(chars
, EscapeText
, &len
);
1074 write_output_buffer(This
->buffer
, escaped
, len
);
1082 static HRESULT WINAPI
SAXContentHandler_ignorableWhitespace(
1083 ISAXContentHandler
*iface
,
1087 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1088 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
1092 static HRESULT WINAPI
SAXContentHandler_processingInstruction(
1093 ISAXContentHandler
*iface
,
1094 const WCHAR
*target
,
1099 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1100 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
1104 static HRESULT WINAPI
SAXContentHandler_skippedEntity(
1105 ISAXContentHandler
*iface
,
1109 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1110 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
1114 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl
=
1116 SAXContentHandler_QueryInterface
,
1117 SAXContentHandler_AddRef
,
1118 SAXContentHandler_Release
,
1119 SAXContentHandler_putDocumentLocator
,
1120 SAXContentHandler_startDocument
,
1121 SAXContentHandler_endDocument
,
1122 SAXContentHandler_startPrefixMapping
,
1123 SAXContentHandler_endPrefixMapping
,
1124 SAXContentHandler_startElement
,
1125 SAXContentHandler_endElement
,
1126 SAXContentHandler_characters
,
1127 SAXContentHandler_ignorableWhitespace
,
1128 SAXContentHandler_processingInstruction
,
1129 SAXContentHandler_skippedEntity
1132 /*** ISAXLexicalHandler ***/
1133 static HRESULT WINAPI
SAXLexicalHandler_QueryInterface(ISAXLexicalHandler
*iface
,
1134 REFIID riid
, void **obj
)
1136 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1137 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
1140 static ULONG WINAPI
SAXLexicalHandler_AddRef(ISAXLexicalHandler
*iface
)
1142 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1143 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
1146 static ULONG WINAPI
SAXLexicalHandler_Release(ISAXLexicalHandler
*iface
)
1148 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1149 return IMXWriter_Release(&This
->IMXWriter_iface
);
1152 static HRESULT WINAPI
SAXLexicalHandler_startDTD(ISAXLexicalHandler
*iface
,
1153 const WCHAR
*name
, int name_len
, const WCHAR
*publicId
, int publicId_len
,
1154 const WCHAR
*systemId
, int systemId_len
)
1156 static const WCHAR doctypeW
[] = {'<','!','D','O','C','T','Y','P','E',' '};
1157 static const WCHAR openintW
[] = {'[','\r','\n'};
1159 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1161 TRACE("(%p)->(%s %s %s)\n", This
, debugstr_wn(name
, name_len
), debugstr_wn(publicId
, publicId_len
),
1162 debugstr_wn(systemId
, systemId_len
));
1164 if (!name
) return E_INVALIDARG
;
1166 write_output_buffer(This
->buffer
, doctypeW
, sizeof(doctypeW
)/sizeof(WCHAR
));
1170 write_output_buffer(This
->buffer
, name
, name_len
);
1171 write_output_buffer(This
->buffer
, spaceW
, 1);
1176 static const WCHAR publicW
[] = {'P','U','B','L','I','C',' '};
1178 write_output_buffer(This
->buffer
, publicW
, sizeof(publicW
)/sizeof(WCHAR
));
1179 write_output_buffer_quoted(This
->buffer
, publicId
, publicId_len
);
1181 if (!systemId
) return E_INVALIDARG
;
1184 write_output_buffer(This
->buffer
, spaceW
, 1);
1186 write_output_buffer_quoted(This
->buffer
, systemId
, systemId_len
);
1189 write_output_buffer(This
->buffer
, spaceW
, 1);
1193 static const WCHAR systemW
[] = {'S','Y','S','T','E','M',' '};
1195 write_output_buffer(This
->buffer
, systemW
, sizeof(systemW
)/sizeof(WCHAR
));
1196 write_output_buffer_quoted(This
->buffer
, systemId
, systemId_len
);
1198 write_output_buffer(This
->buffer
, spaceW
, 1);
1201 write_output_buffer(This
->buffer
, openintW
, sizeof(openintW
)/sizeof(WCHAR
));
1206 static HRESULT WINAPI
SAXLexicalHandler_endDTD(ISAXLexicalHandler
*iface
)
1208 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1209 static const WCHAR closedtdW
[] = {']','>','\r','\n'};
1211 TRACE("(%p)\n", This
);
1213 write_output_buffer(This
->buffer
, closedtdW
, sizeof(closedtdW
)/sizeof(WCHAR
));
1218 static HRESULT WINAPI
SAXLexicalHandler_startEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1220 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1221 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1225 static HRESULT WINAPI
SAXLexicalHandler_endEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1227 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1228 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1232 static HRESULT WINAPI
SAXLexicalHandler_startCDATA(ISAXLexicalHandler
*iface
)
1234 static const WCHAR scdataW
[] = {'<','!','[','C','D','A','T','A','['};
1235 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1237 TRACE("(%p)\n", This
);
1239 write_output_buffer(This
->buffer
, scdataW
, sizeof(scdataW
)/sizeof(WCHAR
));
1245 static HRESULT WINAPI
SAXLexicalHandler_endCDATA(ISAXLexicalHandler
*iface
)
1247 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1248 static const WCHAR ecdataW
[] = {']',']','>'};
1250 TRACE("(%p)\n", This
);
1252 write_output_buffer(This
->buffer
, ecdataW
, sizeof(ecdataW
)/sizeof(WCHAR
));
1253 This
->cdata
= FALSE
;
1258 static HRESULT WINAPI
SAXLexicalHandler_comment(ISAXLexicalHandler
*iface
, const WCHAR
*chars
, int nchars
)
1260 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1261 static const WCHAR copenW
[] = {'<','!','-','-'};
1262 static const WCHAR ccloseW
[] = {'-','-','>','\r','\n'};
1264 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1266 if (!chars
) return E_INVALIDARG
;
1268 close_element_starttag(This
);
1270 write_output_buffer(This
->buffer
, copenW
, sizeof(copenW
)/sizeof(WCHAR
));
1272 write_output_buffer(This
->buffer
, chars
, nchars
);
1273 write_output_buffer(This
->buffer
, ccloseW
, sizeof(ccloseW
)/sizeof(WCHAR
));
1278 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl
=
1280 SAXLexicalHandler_QueryInterface
,
1281 SAXLexicalHandler_AddRef
,
1282 SAXLexicalHandler_Release
,
1283 SAXLexicalHandler_startDTD
,
1284 SAXLexicalHandler_endDTD
,
1285 SAXLexicalHandler_startEntity
,
1286 SAXLexicalHandler_endEntity
,
1287 SAXLexicalHandler_startCDATA
,
1288 SAXLexicalHandler_endCDATA
,
1289 SAXLexicalHandler_comment
1292 /*** ISAXDeclHandler ***/
1293 static HRESULT WINAPI
SAXDeclHandler_QueryInterface(ISAXDeclHandler
*iface
,
1294 REFIID riid
, void **obj
)
1296 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1297 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
1300 static ULONG WINAPI
SAXDeclHandler_AddRef(ISAXDeclHandler
*iface
)
1302 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1303 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
1306 static ULONG WINAPI
SAXDeclHandler_Release(ISAXDeclHandler
*iface
)
1308 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1309 return IMXWriter_Release(&This
->IMXWriter_iface
);
1312 static HRESULT WINAPI
SAXDeclHandler_elementDecl(ISAXDeclHandler
*iface
,
1313 const WCHAR
*name
, int n_name
, const WCHAR
*model
, int n_model
)
1315 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1316 FIXME("(%p)->(%s:%d %s:%d): stub\n", This
, debugstr_wn(name
, n_name
), n_name
,
1317 debugstr_wn(model
, n_model
), n_model
);
1321 static HRESULT WINAPI
SAXDeclHandler_attributeDecl(ISAXDeclHandler
*iface
,
1322 const WCHAR
*element
, int n_element
, const WCHAR
*attr
, int n_attr
,
1323 const WCHAR
*type
, int n_type
, const WCHAR
*Default
, int n_default
,
1324 const WCHAR
*value
, int n_value
)
1326 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1327 FIXME("(%p)->(%s:%d %s:%d %s:%d %s:%d %s:%d): stub\n", This
, debugstr_wn(element
, n_element
), n_element
,
1328 debugstr_wn(attr
, n_attr
), n_attr
, debugstr_wn(type
, n_type
), n_type
, debugstr_wn(Default
, n_default
), n_default
,
1329 debugstr_wn(value
, n_value
), n_value
);
1333 static HRESULT WINAPI
SAXDeclHandler_internalEntityDecl(ISAXDeclHandler
*iface
,
1334 const WCHAR
*name
, int n_name
, const WCHAR
*value
, int n_value
)
1336 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1337 FIXME("(%p)->(%s:%d %s:%d): stub\n", This
, debugstr_wn(name
, n_name
), n_name
,
1338 debugstr_wn(value
, n_value
), n_value
);
1342 static HRESULT WINAPI
SAXDeclHandler_externalEntityDecl(ISAXDeclHandler
*iface
,
1343 const WCHAR
*name
, int n_name
, const WCHAR
*publicId
, int n_publicId
,
1344 const WCHAR
*systemId
, int n_systemId
)
1346 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1347 FIXME("(%p)->(%s:%d %s:%d %s:%d): stub\n", This
, debugstr_wn(name
, n_name
), n_name
,
1348 debugstr_wn(publicId
, n_publicId
), n_publicId
, debugstr_wn(systemId
, n_systemId
), n_systemId
);
1352 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl
= {
1353 SAXDeclHandler_QueryInterface
,
1354 SAXDeclHandler_AddRef
,
1355 SAXDeclHandler_Release
,
1356 SAXDeclHandler_elementDecl
,
1357 SAXDeclHandler_attributeDecl
,
1358 SAXDeclHandler_internalEntityDecl
,
1359 SAXDeclHandler_externalEntityDecl
1362 static const tid_t mxwriter_iface_tids
[] = {
1367 static dispex_static_data_t mxwriter_dispex
= {
1374 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
1376 static const WCHAR version10W
[] = {'1','.','0',0};
1380 TRACE("(%p, %p)\n", outer
, ppObj
);
1382 if (outer
) FIXME("support aggregation, outer\n");
1384 This
= heap_alloc( sizeof (*This
) );
1386 return E_OUTOFMEMORY
;
1388 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
1389 This
->ISAXContentHandler_iface
.lpVtbl
= &SAXContentHandlerVtbl
;
1390 This
->ISAXLexicalHandler_iface
.lpVtbl
= &SAXLexicalHandlerVtbl
;
1391 This
->ISAXDeclHandler_iface
.lpVtbl
= &SAXDeclHandlerVtbl
;
1393 This
->class_version
= version
;
1395 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
1396 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
1397 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
1398 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
1399 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
1400 This
->prop_changed
= FALSE
;
1401 This
->encoding
= SysAllocString(utf16W
);
1402 This
->version
= SysAllocString(version10W
);
1403 This
->xml_enc
= XmlEncoding_UTF16
;
1405 This
->element
= NULL
;
1406 This
->cdata
= FALSE
;
1409 This
->dest_written
= 0;
1411 hr
= alloc_output_buffer(This
->xml_enc
, &This
->buffer
);
1413 SysFreeString(This
->encoding
);
1414 SysFreeString(This
->version
);
1419 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
1421 *ppObj
= &This
->IMXWriter_iface
;
1423 TRACE("returning iface %p\n", *ppObj
);