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 if (This
->xml_enc
!= XmlEncoding_UTF16
)
393 buffer
= &This
->buffer
->encoded
;
395 buffer
= &This
->buffer
->utf16
;
397 if (This
->dest_written
> buffer
->written
) {
398 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This
->dest_written
, buffer
->written
);
400 } else if (This
->dest_written
== buffer
->written
&& This
->xml_enc
!= XmlEncoding_UTF8
)
401 /* Windows seems to make an empty write call when the encoding is UTF-8 and
402 * all the data has been written to the stream. It doesn't seem make this call
403 * for any other encodings.
407 /* Write the current content from the output buffer into 'dest'.
408 * TODO: Check what Windows does if the IStream doesn't write all of
409 * the data we give it at once.
411 hr
= IStream_Write(This
->dest
, buffer
->data
+This
->dest_written
,
412 buffer
->written
-This
->dest_written
, &written
);
414 WARN("Failed to write data to IStream (0x%08x)\n", hr
);
418 This
->dest_written
+= written
;
422 /* Newly added element start tag left unclosed cause for empty elements
423 we have to close it differently. */
424 static void close_element_starttag(const mxwriter
*This
)
426 static const WCHAR gtW
[] = {'>'};
427 if (!This
->element
) return;
428 write_output_buffer(This
->buffer
, gtW
, 1);
431 static void set_element_name(mxwriter
*This
, const WCHAR
*name
, int len
)
433 SysFreeString(This
->element
);
434 This
->element
= name
? SysAllocStringLen(name
, len
) : NULL
;
437 static inline HRESULT
flush_output_buffer(mxwriter
*This
)
439 close_element_starttag(This
);
440 set_element_name(This
, NULL
, 0);
442 return write_data_to_stream(This
);
445 /* Resets the mxwriter's output buffer by closing it, then creating a new
446 * output buffer using the given encoding.
448 static inline void reset_output_buffer(mxwriter
*This
)
450 close_output_buffer(This
);
451 This
->dest_written
= 0;
454 static HRESULT
writer_set_property(mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL value
)
456 writer
->props
[property
] = value
;
457 writer
->prop_changed
= TRUE
;
461 static HRESULT
writer_get_property(const mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL
*value
)
463 if (!value
) return E_POINTER
;
464 *value
= writer
->props
[property
];
468 static inline mxwriter
*impl_from_IMXWriter(IMXWriter
*iface
)
470 return CONTAINING_RECORD(iface
, mxwriter
, IMXWriter_iface
);
473 static inline mxwriter
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
475 return CONTAINING_RECORD(iface
, mxwriter
, ISAXContentHandler_iface
);
478 static inline mxwriter
*impl_from_ISAXLexicalHandler(ISAXLexicalHandler
*iface
)
480 return CONTAINING_RECORD(iface
, mxwriter
, ISAXLexicalHandler_iface
);
483 static inline mxwriter
*impl_from_ISAXDeclHandler(ISAXDeclHandler
*iface
)
485 return CONTAINING_RECORD(iface
, mxwriter
, ISAXDeclHandler_iface
);
488 static HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
490 mxwriter
*This
= impl_from_IMXWriter( iface
);
492 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
496 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
497 IsEqualGUID( riid
, &IID_IDispatch
) ||
498 IsEqualGUID( riid
, &IID_IUnknown
) )
500 *obj
= &This
->IMXWriter_iface
;
502 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
504 *obj
= &This
->ISAXContentHandler_iface
;
506 else if ( IsEqualGUID( riid
, &IID_ISAXLexicalHandler
) )
508 *obj
= &This
->ISAXLexicalHandler_iface
;
510 else if ( IsEqualGUID( riid
, &IID_ISAXDeclHandler
) )
512 *obj
= &This
->ISAXDeclHandler_iface
;
514 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
516 return *obj
? S_OK
: E_NOINTERFACE
;
520 ERR("interface %s not implemented\n", debugstr_guid(riid
));
522 return E_NOINTERFACE
;
525 IMXWriter_AddRef(iface
);
529 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
531 mxwriter
*This
= impl_from_IMXWriter( iface
);
532 LONG ref
= InterlockedIncrement(&This
->ref
);
534 TRACE("(%p)->(%d)\n", This
, ref
);
539 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
541 mxwriter
*This
= impl_from_IMXWriter( iface
);
542 ULONG ref
= InterlockedDecrement(&This
->ref
);
544 TRACE("(%p)->(%d)\n", This
, ref
);
548 /* Windows flushes the buffer when the interface is destroyed. */
549 flush_output_buffer(This
);
550 free_output_buffer(This
->buffer
);
552 if (This
->dest
) IStream_Release(This
->dest
);
553 SysFreeString(This
->version
);
554 SysFreeString(This
->encoding
);
556 SysFreeString(This
->element
);
557 release_dispex(&This
->dispex
);
564 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
566 mxwriter
*This
= impl_from_IMXWriter( iface
);
567 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
570 static HRESULT WINAPI
mxwriter_GetTypeInfo(
572 UINT iTInfo
, LCID lcid
,
573 ITypeInfo
** ppTInfo
)
575 mxwriter
*This
= impl_from_IMXWriter( iface
);
576 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
577 iTInfo
, lcid
, ppTInfo
);
580 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
582 REFIID riid
, LPOLESTR
* rgszNames
,
583 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
585 mxwriter
*This
= impl_from_IMXWriter( iface
);
586 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
587 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
590 static HRESULT WINAPI
mxwriter_Invoke(
592 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
593 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
594 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
596 mxwriter
*This
= impl_from_IMXWriter( iface
);
597 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
598 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
601 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
603 mxwriter
*This
= impl_from_IMXWriter( iface
);
606 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
608 hr
= flush_output_buffer(This
);
616 if (This
->dest
) IStream_Release(This
->dest
);
618 reset_output_buffer(This
);
625 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
628 /* Recreate the output buffer to make sure it's using the correct encoding. */
629 reset_output_buffer(This
);
631 if (This
->dest
) IStream_Release(This
->dest
);
636 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
640 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
647 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
649 mxwriter
*This
= impl_from_IMXWriter( iface
);
651 TRACE("(%p)->(%p)\n", This
, dest
);
655 HRESULT hr
= flush_output_buffer(This
);
659 V_VT(dest
) = VT_BSTR
;
660 V_BSTR(dest
) = SysAllocString((WCHAR
*)This
->buffer
->utf16
.data
);
665 FIXME("not implemented when stream is set up\n");
670 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
672 mxwriter
*This
= impl_from_IMXWriter( iface
);
676 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
678 enc
= parse_encoding_name(encoding
);
679 if (enc
== XmlEncoding_Unknown
)
681 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
685 hr
= flush_output_buffer(This
);
689 SysReAllocString(&This
->encoding
, encoding
);
692 TRACE("got encoding %d\n", This
->xml_enc
);
693 reset_output_buffer(This
);
697 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
699 mxwriter
*This
= impl_from_IMXWriter( iface
);
701 TRACE("(%p)->(%p)\n", This
, encoding
);
703 if (!encoding
) return E_POINTER
;
705 *encoding
= SysAllocString(This
->encoding
);
706 if (!*encoding
) return E_OUTOFMEMORY
;
711 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
713 mxwriter
*This
= impl_from_IMXWriter( iface
);
715 TRACE("(%p)->(%d)\n", This
, value
);
716 return writer_set_property(This
, MXWriter_BOM
, value
);
719 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
721 mxwriter
*This
= impl_from_IMXWriter( iface
);
723 TRACE("(%p)->(%p)\n", This
, value
);
724 return writer_get_property(This
, MXWriter_BOM
, value
);
727 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
729 mxwriter
*This
= impl_from_IMXWriter( iface
);
731 TRACE("(%p)->(%d)\n", This
, value
);
732 return writer_set_property(This
, MXWriter_Indent
, value
);
735 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
737 mxwriter
*This
= impl_from_IMXWriter( iface
);
739 TRACE("(%p)->(%p)\n", This
, value
);
740 return writer_get_property(This
, MXWriter_Indent
, value
);
743 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
745 mxwriter
*This
= impl_from_IMXWriter( iface
);
747 TRACE("(%p)->(%d)\n", This
, value
);
748 return writer_set_property(This
, MXWriter_Standalone
, value
);
751 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
753 mxwriter
*This
= impl_from_IMXWriter( iface
);
755 TRACE("(%p)->(%p)\n", This
, value
);
756 return writer_get_property(This
, MXWriter_Standalone
, value
);
759 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
761 mxwriter
*This
= impl_from_IMXWriter( iface
);
763 TRACE("(%p)->(%d)\n", This
, value
);
764 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
767 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
769 mxwriter
*This
= impl_from_IMXWriter( iface
);
771 TRACE("(%p)->(%p)\n", This
, value
);
772 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
775 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
777 mxwriter
*This
= impl_from_IMXWriter( iface
);
779 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
781 if (!version
) return E_INVALIDARG
;
783 SysFreeString(This
->version
);
784 This
->version
= SysAllocString(version
);
789 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
791 mxwriter
*This
= impl_from_IMXWriter( iface
);
793 TRACE("(%p)->(%p)\n", This
, version
);
795 if (!version
) return E_POINTER
;
797 return return_bstr(This
->version
, version
);
800 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
802 mxwriter
*This
= impl_from_IMXWriter( iface
);
804 TRACE("(%p)->(%d)\n", This
, value
);
805 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
808 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
810 mxwriter
*This
= impl_from_IMXWriter( iface
);
812 TRACE("(%p)->(%p)\n", This
, value
);
813 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
816 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
818 mxwriter
*This
= impl_from_IMXWriter( iface
);
819 TRACE("(%p)\n", This
);
820 return flush_output_buffer(This
);
823 static const struct IMXWriterVtbl MXWriterVtbl
=
825 mxwriter_QueryInterface
,
828 mxwriter_GetTypeInfoCount
,
829 mxwriter_GetTypeInfo
,
830 mxwriter_GetIDsOfNames
,
834 mxwriter_put_encoding
,
835 mxwriter_get_encoding
,
836 mxwriter_put_byteOrderMark
,
837 mxwriter_get_byteOrderMark
,
840 mxwriter_put_standalone
,
841 mxwriter_get_standalone
,
842 mxwriter_put_omitXMLDeclaration
,
843 mxwriter_get_omitXMLDeclaration
,
844 mxwriter_put_version
,
845 mxwriter_get_version
,
846 mxwriter_put_disableOutputEscaping
,
847 mxwriter_get_disableOutputEscaping
,
851 /*** ISAXContentHandler ***/
852 static HRESULT WINAPI
SAXContentHandler_QueryInterface(
853 ISAXContentHandler
*iface
,
857 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
858 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
861 static ULONG WINAPI
SAXContentHandler_AddRef(ISAXContentHandler
*iface
)
863 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
864 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
867 static ULONG WINAPI
SAXContentHandler_Release(ISAXContentHandler
*iface
)
869 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
870 return IMXWriter_Release(&This
->IMXWriter_iface
);
873 static HRESULT WINAPI
SAXContentHandler_putDocumentLocator(
874 ISAXContentHandler
*iface
,
875 ISAXLocator
*locator
)
877 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
878 FIXME("(%p)->(%p)\n", This
, locator
);
882 static HRESULT WINAPI
SAXContentHandler_startDocument(ISAXContentHandler
*iface
)
884 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
886 TRACE("(%p)\n", This
);
888 /* If properties have been changed since the last "endDocument" call
889 * we need to reset the output buffer. If we don't the output buffer
890 * could end up with multiple XML documents in it, plus this seems to
891 * be how Windows works.
893 if (This
->prop_changed
) {
894 reset_output_buffer(This
);
895 This
->prop_changed
= FALSE
;
898 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
900 write_prolog_buffer(This
);
902 if (This
->dest
&& This
->xml_enc
== XmlEncoding_UTF16
) {
903 static const char utf16BOM
[] = {0xff,0xfe};
905 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
906 /* Windows passes a NULL pointer as the pcbWritten parameter and
907 * ignores any error codes returned from this Write call.
909 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
915 static HRESULT WINAPI
SAXContentHandler_endDocument(ISAXContentHandler
*iface
)
917 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
918 TRACE("(%p)\n", This
);
919 This
->prop_changed
= FALSE
;
920 return flush_output_buffer(This
);
923 static HRESULT WINAPI
SAXContentHandler_startPrefixMapping(
924 ISAXContentHandler
*iface
,
930 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
931 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
935 static HRESULT WINAPI
SAXContentHandler_endPrefixMapping(
936 ISAXContentHandler
*iface
,
940 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
941 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
945 static HRESULT WINAPI
SAXContentHandler_startElement(
946 ISAXContentHandler
*iface
,
947 const WCHAR
*namespaceUri
,
949 const WCHAR
*local_name
,
953 ISAXAttributes
*attr
)
955 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
956 static const WCHAR ltW
[] = {'<'};
958 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
959 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
961 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
964 close_element_starttag(This
);
965 set_element_name(This
, QName
? QName
: emptyW
,
968 write_output_buffer(This
->buffer
, ltW
, 1);
969 write_output_buffer(This
->buffer
, QName
, nQName
);
977 hr
= ISAXAttributes_getLength(attr
, &length
);
978 if (FAILED(hr
)) return hr
;
980 for (i
= 0; i
< length
; i
++)
982 static const WCHAR eqW
[] = {'='};
987 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
988 if (FAILED(hr
)) return hr
;
990 /* space separator in front of every attribute */
991 write_output_buffer(This
->buffer
, spaceW
, 1);
992 write_output_buffer(This
->buffer
, str
, len
);
994 write_output_buffer(This
->buffer
, eqW
, 1);
997 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
998 if (FAILED(hr
)) return hr
;
1000 escaped
= get_escaped_string(str
, EscapeValue
, &len
);
1001 write_output_buffer_quoted(This
->buffer
, escaped
, len
);
1009 static HRESULT WINAPI
SAXContentHandler_endElement(
1010 ISAXContentHandler
*iface
,
1011 const WCHAR
*namespaceUri
,
1013 const WCHAR
* local_name
,
1018 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1020 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
1021 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
1023 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
1024 return E_INVALIDARG
;
1026 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
1028 static const WCHAR closeW
[] = {'/','>'};
1030 write_output_buffer(This
->buffer
, closeW
, 2);
1034 static const WCHAR closetagW
[] = {'<','/'};
1035 static const WCHAR gtW
[] = {'>'};
1037 write_output_buffer(This
->buffer
, closetagW
, 2);
1038 write_output_buffer(This
->buffer
, QName
, nQName
);
1039 write_output_buffer(This
->buffer
, gtW
, 1);
1042 set_element_name(This
, NULL
, 0);
1047 static HRESULT WINAPI
SAXContentHandler_characters(
1048 ISAXContentHandler
*iface
,
1052 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1054 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1056 if (!chars
) return E_INVALIDARG
;
1058 close_element_starttag(This
);
1059 set_element_name(This
, NULL
, 0);
1064 write_output_buffer(This
->buffer
, chars
, nchars
);
1070 escaped
= get_escaped_string(chars
, EscapeText
, &len
);
1071 write_output_buffer(This
->buffer
, escaped
, len
);
1079 static HRESULT WINAPI
SAXContentHandler_ignorableWhitespace(
1080 ISAXContentHandler
*iface
,
1084 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1085 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
1089 static HRESULT WINAPI
SAXContentHandler_processingInstruction(
1090 ISAXContentHandler
*iface
,
1091 const WCHAR
*target
,
1096 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1097 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
1101 static HRESULT WINAPI
SAXContentHandler_skippedEntity(
1102 ISAXContentHandler
*iface
,
1106 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1107 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
1111 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl
=
1113 SAXContentHandler_QueryInterface
,
1114 SAXContentHandler_AddRef
,
1115 SAXContentHandler_Release
,
1116 SAXContentHandler_putDocumentLocator
,
1117 SAXContentHandler_startDocument
,
1118 SAXContentHandler_endDocument
,
1119 SAXContentHandler_startPrefixMapping
,
1120 SAXContentHandler_endPrefixMapping
,
1121 SAXContentHandler_startElement
,
1122 SAXContentHandler_endElement
,
1123 SAXContentHandler_characters
,
1124 SAXContentHandler_ignorableWhitespace
,
1125 SAXContentHandler_processingInstruction
,
1126 SAXContentHandler_skippedEntity
1129 /*** ISAXLexicalHandler ***/
1130 static HRESULT WINAPI
SAXLexicalHandler_QueryInterface(ISAXLexicalHandler
*iface
,
1131 REFIID riid
, void **obj
)
1133 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1134 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
1137 static ULONG WINAPI
SAXLexicalHandler_AddRef(ISAXLexicalHandler
*iface
)
1139 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1140 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
1143 static ULONG WINAPI
SAXLexicalHandler_Release(ISAXLexicalHandler
*iface
)
1145 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1146 return IMXWriter_Release(&This
->IMXWriter_iface
);
1149 static HRESULT WINAPI
SAXLexicalHandler_startDTD(ISAXLexicalHandler
*iface
,
1150 const WCHAR
*name
, int name_len
, const WCHAR
*publicId
, int publicId_len
,
1151 const WCHAR
*systemId
, int systemId_len
)
1153 static const WCHAR doctypeW
[] = {'<','!','D','O','C','T','Y','P','E',' '};
1154 static const WCHAR openintW
[] = {'[','\r','\n'};
1156 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1158 TRACE("(%p)->(%s %s %s)\n", This
, debugstr_wn(name
, name_len
), debugstr_wn(publicId
, publicId_len
),
1159 debugstr_wn(systemId
, systemId_len
));
1161 if (!name
) return E_INVALIDARG
;
1163 write_output_buffer(This
->buffer
, doctypeW
, sizeof(doctypeW
)/sizeof(WCHAR
));
1167 write_output_buffer(This
->buffer
, name
, name_len
);
1168 write_output_buffer(This
->buffer
, spaceW
, 1);
1173 static const WCHAR publicW
[] = {'P','U','B','L','I','C',' '};
1175 write_output_buffer(This
->buffer
, publicW
, sizeof(publicW
)/sizeof(WCHAR
));
1176 write_output_buffer_quoted(This
->buffer
, publicId
, publicId_len
);
1178 if (!systemId
) return E_INVALIDARG
;
1181 write_output_buffer(This
->buffer
, spaceW
, 1);
1183 write_output_buffer_quoted(This
->buffer
, systemId
, systemId_len
);
1186 write_output_buffer(This
->buffer
, spaceW
, 1);
1190 static const WCHAR systemW
[] = {'S','Y','S','T','E','M',' '};
1192 write_output_buffer(This
->buffer
, systemW
, sizeof(systemW
)/sizeof(WCHAR
));
1193 write_output_buffer_quoted(This
->buffer
, systemId
, systemId_len
);
1195 write_output_buffer(This
->buffer
, spaceW
, 1);
1198 write_output_buffer(This
->buffer
, openintW
, sizeof(openintW
)/sizeof(WCHAR
));
1203 static HRESULT WINAPI
SAXLexicalHandler_endDTD(ISAXLexicalHandler
*iface
)
1205 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1206 static const WCHAR closedtdW
[] = {']','>','\r','\n'};
1208 TRACE("(%p)\n", This
);
1210 write_output_buffer(This
->buffer
, closedtdW
, sizeof(closedtdW
)/sizeof(WCHAR
));
1215 static HRESULT WINAPI
SAXLexicalHandler_startEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1217 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1218 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1222 static HRESULT WINAPI
SAXLexicalHandler_endEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1224 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1225 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1229 static HRESULT WINAPI
SAXLexicalHandler_startCDATA(ISAXLexicalHandler
*iface
)
1231 static const WCHAR scdataW
[] = {'<','!','[','C','D','A','T','A','['};
1232 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1234 TRACE("(%p)\n", This
);
1236 write_output_buffer(This
->buffer
, scdataW
, sizeof(scdataW
)/sizeof(WCHAR
));
1242 static HRESULT WINAPI
SAXLexicalHandler_endCDATA(ISAXLexicalHandler
*iface
)
1244 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1245 static const WCHAR ecdataW
[] = {']',']','>'};
1247 TRACE("(%p)\n", This
);
1249 write_output_buffer(This
->buffer
, ecdataW
, sizeof(ecdataW
)/sizeof(WCHAR
));
1250 This
->cdata
= FALSE
;
1255 static HRESULT WINAPI
SAXLexicalHandler_comment(ISAXLexicalHandler
*iface
, const WCHAR
*chars
, int nchars
)
1257 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1258 static const WCHAR copenW
[] = {'<','!','-','-'};
1259 static const WCHAR ccloseW
[] = {'-','-','>','\r','\n'};
1261 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1263 if (!chars
) return E_INVALIDARG
;
1265 close_element_starttag(This
);
1267 write_output_buffer(This
->buffer
, copenW
, sizeof(copenW
)/sizeof(WCHAR
));
1269 write_output_buffer(This
->buffer
, chars
, nchars
);
1270 write_output_buffer(This
->buffer
, ccloseW
, sizeof(ccloseW
)/sizeof(WCHAR
));
1275 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl
=
1277 SAXLexicalHandler_QueryInterface
,
1278 SAXLexicalHandler_AddRef
,
1279 SAXLexicalHandler_Release
,
1280 SAXLexicalHandler_startDTD
,
1281 SAXLexicalHandler_endDTD
,
1282 SAXLexicalHandler_startEntity
,
1283 SAXLexicalHandler_endEntity
,
1284 SAXLexicalHandler_startCDATA
,
1285 SAXLexicalHandler_endCDATA
,
1286 SAXLexicalHandler_comment
1289 /*** ISAXDeclHandler ***/
1290 static HRESULT WINAPI
SAXDeclHandler_QueryInterface(ISAXDeclHandler
*iface
,
1291 REFIID riid
, void **obj
)
1293 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1294 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
1297 static ULONG WINAPI
SAXDeclHandler_AddRef(ISAXDeclHandler
*iface
)
1299 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1300 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
1303 static ULONG WINAPI
SAXDeclHandler_Release(ISAXDeclHandler
*iface
)
1305 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1306 return IMXWriter_Release(&This
->IMXWriter_iface
);
1309 static HRESULT WINAPI
SAXDeclHandler_elementDecl(ISAXDeclHandler
*iface
,
1310 const WCHAR
*name
, int n_name
, const WCHAR
*model
, int n_model
)
1312 static const WCHAR elementW
[] = {'<','!','E','L','E','M','E','N','T',' '};
1313 static const WCHAR closeelementW
[] = {'>','\r','\n'};
1314 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1316 TRACE("(%p)->(%s:%d %s:%d)\n", This
, debugstr_wn(name
, n_name
), n_name
,
1317 debugstr_wn(model
, n_model
), n_model
);
1319 if (!name
|| !model
) return E_INVALIDARG
;
1321 write_output_buffer(This
->buffer
, elementW
, sizeof(elementW
)/sizeof(WCHAR
));
1323 write_output_buffer(This
->buffer
, name
, n_name
);
1324 write_output_buffer(This
->buffer
, spaceW
, sizeof(spaceW
)/sizeof(WCHAR
));
1327 write_output_buffer(This
->buffer
, model
, n_model
);
1328 write_output_buffer(This
->buffer
, closeelementW
, sizeof(closeelementW
)/sizeof(WCHAR
));
1333 static HRESULT WINAPI
SAXDeclHandler_attributeDecl(ISAXDeclHandler
*iface
,
1334 const WCHAR
*element
, int n_element
, const WCHAR
*attr
, int n_attr
,
1335 const WCHAR
*type
, int n_type
, const WCHAR
*Default
, int n_default
,
1336 const WCHAR
*value
, int n_value
)
1338 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1339 FIXME("(%p)->(%s:%d %s:%d %s:%d %s:%d %s:%d): stub\n", This
, debugstr_wn(element
, n_element
), n_element
,
1340 debugstr_wn(attr
, n_attr
), n_attr
, debugstr_wn(type
, n_type
), n_type
, debugstr_wn(Default
, n_default
), n_default
,
1341 debugstr_wn(value
, n_value
), n_value
);
1345 static HRESULT WINAPI
SAXDeclHandler_internalEntityDecl(ISAXDeclHandler
*iface
,
1346 const WCHAR
*name
, int n_name
, const WCHAR
*value
, int n_value
)
1348 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1349 FIXME("(%p)->(%s:%d %s:%d): stub\n", This
, debugstr_wn(name
, n_name
), n_name
,
1350 debugstr_wn(value
, n_value
), n_value
);
1354 static HRESULT WINAPI
SAXDeclHandler_externalEntityDecl(ISAXDeclHandler
*iface
,
1355 const WCHAR
*name
, int n_name
, const WCHAR
*publicId
, int n_publicId
,
1356 const WCHAR
*systemId
, int n_systemId
)
1358 mxwriter
*This
= impl_from_ISAXDeclHandler( iface
);
1359 FIXME("(%p)->(%s:%d %s:%d %s:%d): stub\n", This
, debugstr_wn(name
, n_name
), n_name
,
1360 debugstr_wn(publicId
, n_publicId
), n_publicId
, debugstr_wn(systemId
, n_systemId
), n_systemId
);
1364 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl
= {
1365 SAXDeclHandler_QueryInterface
,
1366 SAXDeclHandler_AddRef
,
1367 SAXDeclHandler_Release
,
1368 SAXDeclHandler_elementDecl
,
1369 SAXDeclHandler_attributeDecl
,
1370 SAXDeclHandler_internalEntityDecl
,
1371 SAXDeclHandler_externalEntityDecl
1374 static const tid_t mxwriter_iface_tids
[] = {
1379 static dispex_static_data_t mxwriter_dispex
= {
1386 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
1388 static const WCHAR version10W
[] = {'1','.','0',0};
1392 TRACE("(%p, %p)\n", outer
, ppObj
);
1394 if (outer
) FIXME("support aggregation, outer\n");
1396 This
= heap_alloc( sizeof (*This
) );
1398 return E_OUTOFMEMORY
;
1400 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
1401 This
->ISAXContentHandler_iface
.lpVtbl
= &SAXContentHandlerVtbl
;
1402 This
->ISAXLexicalHandler_iface
.lpVtbl
= &SAXLexicalHandlerVtbl
;
1403 This
->ISAXDeclHandler_iface
.lpVtbl
= &SAXDeclHandlerVtbl
;
1405 This
->class_version
= version
;
1407 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
1408 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
1409 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
1410 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
1411 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
1412 This
->prop_changed
= FALSE
;
1413 This
->encoding
= SysAllocString(utf16W
);
1414 This
->version
= SysAllocString(version10W
);
1415 This
->xml_enc
= XmlEncoding_UTF16
;
1417 This
->element
= NULL
;
1418 This
->cdata
= FALSE
;
1421 This
->dest_written
= 0;
1423 hr
= alloc_output_buffer(This
->xml_enc
, &This
->buffer
);
1425 SysFreeString(This
->encoding
);
1426 SysFreeString(This
->version
);
1431 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
1433 *ppObj
= &This
->IMXWriter_iface
;
1435 TRACE("returning iface %p\n", *ppObj
);