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
);
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
,
74 unsigned int allocated
;
81 encoded_buffer encoded
;
88 IMXWriter IMXWriter_iface
;
89 ISAXContentHandler ISAXContentHandler_iface
;
90 ISAXLexicalHandler ISAXLexicalHandler_iface
;
93 MSXML_VERSION class_version
;
95 VARIANT_BOOL props
[MXWriter_LastProp
];
100 BSTR encoding
; /* exact property value */
101 xml_encoding xml_enc
;
103 /* contains a pending (or not closed yet) element name or NULL if
104 we don't have to close */
110 output_buffer
*buffer
;
113 static xml_encoding
parse_encoding_name(const WCHAR
*encoding
)
115 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
116 if (!strcmpiW(encoding
, utf8W
)) return XmlEncoding_UTF8
;
117 if (!strcmpiW(encoding
, utf16W
)) return XmlEncoding_UTF16
;
118 return XmlEncoding_Unknown
;
121 static HRESULT
init_encoded_buffer(encoded_buffer
*buffer
)
123 const int initial_len
= 0x2000;
124 buffer
->data
= heap_alloc(initial_len
);
125 if (!buffer
->data
) return E_OUTOFMEMORY
;
127 memset(buffer
->data
, 0, 4);
128 buffer
->allocated
= initial_len
;
134 static void free_encoded_buffer(encoded_buffer
*buffer
)
136 heap_free(buffer
->data
);
139 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
143 case XmlEncoding_UTF8
:
146 case XmlEncoding_UTF16
:
150 FIXME("unsupported encoding %d\n", encoding
);
157 static HRESULT
alloc_output_buffer(xml_encoding encoding
, output_buffer
**buffer
)
162 ret
= heap_alloc(sizeof(*ret
));
163 if (!ret
) return E_OUTOFMEMORY
;
165 hr
= get_code_page(encoding
, &ret
->code_page
);
171 hr
= init_encoded_buffer(&ret
->utf16
);
177 if (ret
->code_page
== CP_UTF8
) {
178 hr
= init_encoded_buffer(&ret
->encoded
);
180 free_encoded_buffer(&ret
->utf16
);
186 memset(&ret
->encoded
, 0, sizeof(ret
->encoded
));
193 static void free_output_buffer(output_buffer
*buffer
)
195 free_encoded_buffer(&buffer
->encoded
);
196 free_encoded_buffer(&buffer
->utf16
);
200 static void grow_buffer(encoded_buffer
*buffer
, int length
)
202 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
203 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
205 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
206 buffer
->data
= heap_realloc(buffer
->data
, grown_size
);
207 buffer
->allocated
= grown_size
;
211 static HRESULT
write_output_buffer_mode(output_buffer
*buffer
, output_mode mode
, const WCHAR
*data
, int len
)
216 if (mode
& (OutputBuffer_Encoded
| OutputBuffer_Both
)) {
217 if (buffer
->code_page
== CP_UTF8
)
219 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
220 grow_buffer(&buffer
->encoded
, length
);
221 ptr
= buffer
->encoded
.data
+ buffer
->encoded
.written
;
222 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
223 buffer
->encoded
.written
+= len
== -1 ? length
-1 : length
;
227 if (mode
& (OutputBuffer_Native
| OutputBuffer_Both
)) {
228 /* WCHAR data just copied */
229 length
= len
== -1 ? strlenW(data
) : len
;
232 length
*= sizeof(WCHAR
);
234 grow_buffer(&buffer
->utf16
, length
);
235 ptr
= buffer
->utf16
.data
+ buffer
->utf16
.written
;
237 memcpy(ptr
, data
, length
);
238 buffer
->utf16
.written
+= length
;
240 /* null termination */
241 memset(ptr
, 0, sizeof(WCHAR
));
248 static HRESULT
write_output_buffer(output_buffer
*buffer
, const WCHAR
*data
, int len
)
250 return write_output_buffer_mode(buffer
, OutputBuffer_Both
, data
, len
);
253 /* frees buffer data, reallocates with a default lengths */
254 static void close_output_buffer(mxwriter
*This
)
256 heap_free(This
->buffer
->utf16
.data
);
257 heap_free(This
->buffer
->encoded
.data
);
258 init_encoded_buffer(&This
->buffer
->utf16
);
259 init_encoded_buffer(&This
->buffer
->encoded
);
260 get_code_page(This
->xml_enc
, &This
->buffer
->code_page
);
263 /* escapes special characters like:
269 static WCHAR
*get_escaped_string(const WCHAR
*str
, int *len
)
271 static const WCHAR ltW
[] = {'&','l','t',';'};
272 static const WCHAR ampW
[] = {'&','a','m','p',';'};
273 static const WCHAR equotW
[] = {'&','q','u','o','t',';'};
274 static const WCHAR gtW
[] = {'&','g','t',';'};
276 const int default_alloc
= 100;
277 const int grow_thresh
= 10;
278 int p
= *len
, conv_len
;
281 /* default buffer size to something if length is unknown */
282 conv_len
= *len
== -1 ? default_alloc
: max(2**len
, default_alloc
);
283 ptr
= ret
= heap_alloc(conv_len
*sizeof(WCHAR
));
287 if (ptr
- ret
> conv_len
- grow_thresh
)
289 int written
= ptr
- ret
;
291 ptr
= ret
= heap_realloc(ret
, conv_len
*sizeof(WCHAR
));
298 memcpy(ptr
, ltW
, sizeof(ltW
));
299 ptr
+= sizeof(ltW
)/sizeof(WCHAR
);
302 memcpy(ptr
, ampW
, sizeof(ampW
));
303 ptr
+= sizeof(ampW
)/sizeof(WCHAR
);
306 memcpy(ptr
, equotW
, sizeof(equotW
));
307 ptr
+= sizeof(equotW
)/sizeof(WCHAR
);
310 memcpy(ptr
, gtW
, sizeof(gtW
));
311 ptr
+= sizeof(gtW
)/sizeof(WCHAR
);
322 if (*len
!= -1) *len
= ptr
-ret
;
328 static void write_prolog_buffer(const mxwriter
*This
)
330 static const WCHAR versionW
[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"'};
331 static const WCHAR encodingW
[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
332 static const WCHAR standaloneW
[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
333 static const WCHAR yesW
[] = {'y','e','s','\"','?','>'};
334 static const WCHAR noW
[] = {'n','o','\"','?','>'};
335 static const WCHAR crlfW
[] = {'\r','\n'};
338 write_output_buffer(This
->buffer
, versionW
, sizeof(versionW
)/sizeof(WCHAR
));
339 write_output_buffer(This
->buffer
, This
->version
, -1);
340 write_output_buffer(This
->buffer
, quotW
, 1);
343 write_output_buffer(This
->buffer
, encodingW
, sizeof(encodingW
)/sizeof(WCHAR
));
345 /* always write UTF-16 to WCHAR buffer */
346 write_output_buffer_mode(This
->buffer
, OutputBuffer_Native
, utf16W
, sizeof(utf16W
)/sizeof(WCHAR
) - 1);
347 write_output_buffer_mode(This
->buffer
, OutputBuffer_Encoded
, This
->encoding
, -1);
348 write_output_buffer(This
->buffer
, quotW
, 1);
351 write_output_buffer(This
->buffer
, standaloneW
, sizeof(standaloneW
)/sizeof(WCHAR
));
352 if (This
->props
[MXWriter_Standalone
] == VARIANT_TRUE
)
353 write_output_buffer(This
->buffer
, yesW
, sizeof(yesW
)/sizeof(WCHAR
));
355 write_output_buffer(This
->buffer
, noW
, sizeof(noW
)/sizeof(WCHAR
));
357 write_output_buffer(This
->buffer
, crlfW
, sizeof(crlfW
)/sizeof(WCHAR
));
360 /* Attempts to the write data from the mxwriter's buffer to
361 * the destination stream (if there is one).
363 static HRESULT
write_data_to_stream(mxwriter
*This
)
365 encoded_buffer
*buffer
;
372 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
373 * 'conv' buffer when UTF8 encoding is used.
375 if (This
->xml_enc
!= XmlEncoding_UTF16
)
376 buffer
= &This
->buffer
->encoded
;
378 buffer
= &This
->buffer
->utf16
;
380 if (This
->dest_written
> buffer
->written
) {
381 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This
->dest_written
, buffer
->written
);
383 } else if (This
->dest_written
== buffer
->written
&& This
->xml_enc
!= XmlEncoding_UTF8
)
384 /* Windows seems to make an empty write call when the encoding is UTF-8 and
385 * all the data has been written to the stream. It doesn't seem make this call
386 * for any other encodings.
390 /* Write the current content from the output buffer into 'dest'.
391 * TODO: Check what Windows does if the IStream doesn't write all of
392 * the data we give it at once.
394 hr
= IStream_Write(This
->dest
, buffer
->data
+This
->dest_written
,
395 buffer
->written
-This
->dest_written
, &written
);
397 WARN("Failed to write data to IStream (0x%08x)\n", hr
);
401 This
->dest_written
+= written
;
405 /* Newly added element start tag left unclosed cause for empty elements
406 we have to close it differently. */
407 static void close_element_starttag(const mxwriter
*This
)
409 static const WCHAR gtW
[] = {'>'};
410 if (!This
->element
) return;
411 write_output_buffer(This
->buffer
, gtW
, 1);
414 static void set_element_name(mxwriter
*This
, const WCHAR
*name
, int len
)
416 SysFreeString(This
->element
);
417 This
->element
= name
? SysAllocStringLen(name
, len
) : NULL
;
420 static inline HRESULT
flush_output_buffer(mxwriter
*This
)
422 close_element_starttag(This
);
423 set_element_name(This
, NULL
, 0);
424 return write_data_to_stream(This
);
427 /* Resets the mxwriter's output buffer by closing it, then creating a new
428 * output buffer using the given encoding.
430 static inline void reset_output_buffer(mxwriter
*This
)
432 close_output_buffer(This
);
433 This
->dest_written
= 0;
436 static HRESULT
writer_set_property(mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL value
)
438 writer
->props
[property
] = value
;
439 writer
->prop_changed
= TRUE
;
443 static HRESULT
writer_get_property(const mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL
*value
)
445 if (!value
) return E_POINTER
;
446 *value
= writer
->props
[property
];
450 static inline mxwriter
*impl_from_IMXWriter(IMXWriter
*iface
)
452 return CONTAINING_RECORD(iface
, mxwriter
, IMXWriter_iface
);
455 static inline mxwriter
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
457 return CONTAINING_RECORD(iface
, mxwriter
, ISAXContentHandler_iface
);
460 static inline mxwriter
*impl_from_ISAXLexicalHandler(ISAXLexicalHandler
*iface
)
462 return CONTAINING_RECORD(iface
, mxwriter
, ISAXLexicalHandler_iface
);
465 static HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
467 mxwriter
*This
= impl_from_IMXWriter( iface
);
469 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
473 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
474 IsEqualGUID( riid
, &IID_IDispatch
) ||
475 IsEqualGUID( riid
, &IID_IUnknown
) )
477 *obj
= &This
->IMXWriter_iface
;
479 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
481 *obj
= &This
->ISAXContentHandler_iface
;
483 else if ( IsEqualGUID( riid
, &IID_ISAXLexicalHandler
) )
485 *obj
= &This
->ISAXLexicalHandler_iface
;
487 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
489 return *obj
? S_OK
: E_NOINTERFACE
;
493 ERR("interface %s not implemented\n", debugstr_guid(riid
));
495 return E_NOINTERFACE
;
498 IMXWriter_AddRef(iface
);
502 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
504 mxwriter
*This
= impl_from_IMXWriter( iface
);
505 LONG ref
= InterlockedIncrement(&This
->ref
);
507 TRACE("(%p)->(%d)\n", This
, ref
);
512 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
514 mxwriter
*This
= impl_from_IMXWriter( iface
);
515 ULONG ref
= InterlockedDecrement(&This
->ref
);
517 TRACE("(%p)->(%d)\n", This
, ref
);
521 /* Windows flushes the buffer when the interface is destroyed. */
522 flush_output_buffer(This
);
523 free_output_buffer(This
->buffer
);
525 if (This
->dest
) IStream_Release(This
->dest
);
526 SysFreeString(This
->version
);
527 SysFreeString(This
->encoding
);
529 SysFreeString(This
->element
);
530 release_dispex(&This
->dispex
);
537 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
539 mxwriter
*This
= impl_from_IMXWriter( iface
);
540 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
543 static HRESULT WINAPI
mxwriter_GetTypeInfo(
545 UINT iTInfo
, LCID lcid
,
546 ITypeInfo
** ppTInfo
)
548 mxwriter
*This
= impl_from_IMXWriter( iface
);
549 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
550 iTInfo
, lcid
, ppTInfo
);
553 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
555 REFIID riid
, LPOLESTR
* rgszNames
,
556 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
558 mxwriter
*This
= impl_from_IMXWriter( iface
);
559 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
560 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
563 static HRESULT WINAPI
mxwriter_Invoke(
565 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
566 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
567 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
569 mxwriter
*This
= impl_from_IMXWriter( iface
);
570 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
571 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
574 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
576 mxwriter
*This
= impl_from_IMXWriter( iface
);
579 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
581 hr
= flush_output_buffer(This
);
589 if (This
->dest
) IStream_Release(This
->dest
);
591 reset_output_buffer(This
);
598 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
601 /* Recreate the output buffer to make sure it's using the correct encoding. */
602 reset_output_buffer(This
);
604 if (This
->dest
) IStream_Release(This
->dest
);
609 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
613 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
620 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
622 mxwriter
*This
= impl_from_IMXWriter( iface
);
624 TRACE("(%p)->(%p)\n", This
, dest
);
628 HRESULT hr
= flush_output_buffer(This
);
632 V_VT(dest
) = VT_BSTR
;
633 V_BSTR(dest
) = SysAllocString((WCHAR
*)This
->buffer
->utf16
.data
);
638 FIXME("not implemented when stream is set up\n");
643 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
645 mxwriter
*This
= impl_from_IMXWriter( iface
);
649 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
651 enc
= parse_encoding_name(encoding
);
652 if (enc
== XmlEncoding_Unknown
)
654 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
658 hr
= flush_output_buffer(This
);
662 SysReAllocString(&This
->encoding
, encoding
);
665 TRACE("got encoding %d\n", This
->xml_enc
);
666 reset_output_buffer(This
);
670 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
672 mxwriter
*This
= impl_from_IMXWriter( iface
);
674 TRACE("(%p)->(%p)\n", This
, encoding
);
676 if (!encoding
) return E_POINTER
;
678 *encoding
= SysAllocString(This
->encoding
);
679 if (!*encoding
) return E_OUTOFMEMORY
;
684 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
686 mxwriter
*This
= impl_from_IMXWriter( iface
);
688 TRACE("(%p)->(%d)\n", This
, value
);
689 return writer_set_property(This
, MXWriter_BOM
, value
);
692 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
694 mxwriter
*This
= impl_from_IMXWriter( iface
);
696 TRACE("(%p)->(%p)\n", This
, value
);
697 return writer_get_property(This
, MXWriter_BOM
, value
);
700 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
702 mxwriter
*This
= impl_from_IMXWriter( iface
);
704 TRACE("(%p)->(%d)\n", This
, value
);
705 return writer_set_property(This
, MXWriter_Indent
, value
);
708 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
710 mxwriter
*This
= impl_from_IMXWriter( iface
);
712 TRACE("(%p)->(%p)\n", This
, value
);
713 return writer_get_property(This
, MXWriter_Indent
, value
);
716 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
718 mxwriter
*This
= impl_from_IMXWriter( iface
);
720 TRACE("(%p)->(%d)\n", This
, value
);
721 return writer_set_property(This
, MXWriter_Standalone
, value
);
724 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
726 mxwriter
*This
= impl_from_IMXWriter( iface
);
728 TRACE("(%p)->(%p)\n", This
, value
);
729 return writer_get_property(This
, MXWriter_Standalone
, value
);
732 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
734 mxwriter
*This
= impl_from_IMXWriter( iface
);
736 TRACE("(%p)->(%d)\n", This
, value
);
737 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
740 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
742 mxwriter
*This
= impl_from_IMXWriter( iface
);
744 TRACE("(%p)->(%p)\n", This
, value
);
745 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
748 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
750 mxwriter
*This
= impl_from_IMXWriter( iface
);
752 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
754 if (!version
) return E_INVALIDARG
;
756 SysFreeString(This
->version
);
757 This
->version
= SysAllocString(version
);
762 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
764 mxwriter
*This
= impl_from_IMXWriter( iface
);
766 TRACE("(%p)->(%p)\n", This
, version
);
768 if (!version
) return E_POINTER
;
770 return return_bstr(This
->version
, version
);
773 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
775 mxwriter
*This
= impl_from_IMXWriter( iface
);
777 TRACE("(%p)->(%d)\n", This
, value
);
778 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
781 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
783 mxwriter
*This
= impl_from_IMXWriter( iface
);
785 TRACE("(%p)->(%p)\n", This
, value
);
786 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
789 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
791 mxwriter
*This
= impl_from_IMXWriter( iface
);
792 TRACE("(%p)\n", This
);
793 return flush_output_buffer(This
);
796 static const struct IMXWriterVtbl MXWriterVtbl
=
798 mxwriter_QueryInterface
,
801 mxwriter_GetTypeInfoCount
,
802 mxwriter_GetTypeInfo
,
803 mxwriter_GetIDsOfNames
,
807 mxwriter_put_encoding
,
808 mxwriter_get_encoding
,
809 mxwriter_put_byteOrderMark
,
810 mxwriter_get_byteOrderMark
,
813 mxwriter_put_standalone
,
814 mxwriter_get_standalone
,
815 mxwriter_put_omitXMLDeclaration
,
816 mxwriter_get_omitXMLDeclaration
,
817 mxwriter_put_version
,
818 mxwriter_get_version
,
819 mxwriter_put_disableOutputEscaping
,
820 mxwriter_get_disableOutputEscaping
,
824 /*** ISAXContentHandler ***/
825 static HRESULT WINAPI
SAXContentHandler_QueryInterface(
826 ISAXContentHandler
*iface
,
830 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
831 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
834 static ULONG WINAPI
SAXContentHandler_AddRef(ISAXContentHandler
*iface
)
836 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
837 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
840 static ULONG WINAPI
SAXContentHandler_Release(ISAXContentHandler
*iface
)
842 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
843 return IMXWriter_Release(&This
->IMXWriter_iface
);
846 static HRESULT WINAPI
SAXContentHandler_putDocumentLocator(
847 ISAXContentHandler
*iface
,
848 ISAXLocator
*locator
)
850 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
851 FIXME("(%p)->(%p)\n", This
, locator
);
855 static HRESULT WINAPI
SAXContentHandler_startDocument(ISAXContentHandler
*iface
)
857 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
859 TRACE("(%p)\n", This
);
861 /* If properties have been changed since the last "endDocument" call
862 * we need to reset the output buffer. If we don't the output buffer
863 * could end up with multiple XML documents in it, plus this seems to
864 * be how Windows works.
866 if (This
->prop_changed
) {
867 reset_output_buffer(This
);
868 This
->prop_changed
= FALSE
;
871 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
873 write_prolog_buffer(This
);
875 if (This
->dest
&& This
->xml_enc
== XmlEncoding_UTF16
) {
876 static const char utf16BOM
[] = {0xff,0xfe};
878 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
879 /* Windows passes a NULL pointer as the pcbWritten parameter and
880 * ignores any error codes returned from this Write call.
882 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
888 static HRESULT WINAPI
SAXContentHandler_endDocument(ISAXContentHandler
*iface
)
890 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
891 TRACE("(%p)\n", This
);
892 This
->prop_changed
= FALSE
;
893 return flush_output_buffer(This
);
896 static HRESULT WINAPI
SAXContentHandler_startPrefixMapping(
897 ISAXContentHandler
*iface
,
903 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
904 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
908 static HRESULT WINAPI
SAXContentHandler_endPrefixMapping(
909 ISAXContentHandler
*iface
,
913 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
914 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
918 static HRESULT WINAPI
SAXContentHandler_startElement(
919 ISAXContentHandler
*iface
,
920 const WCHAR
*namespaceUri
,
922 const WCHAR
*local_name
,
926 ISAXAttributes
*attr
)
928 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
929 static const WCHAR ltW
[] = {'<'};
931 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
932 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
934 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
937 close_element_starttag(This
);
938 set_element_name(This
, QName
? QName
: emptyW
,
941 write_output_buffer(This
->buffer
, ltW
, 1);
942 write_output_buffer(This
->buffer
, QName
, nQName
);
950 hr
= ISAXAttributes_getLength(attr
, &length
);
951 if (FAILED(hr
)) return hr
;
953 for (i
= 0; i
< length
; i
++)
955 static const WCHAR eqqW
[] = {'=','\"'};
960 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
961 if (FAILED(hr
)) return hr
;
963 /* space separator in front of every attribute */
964 write_output_buffer(This
->buffer
, spaceW
, 1);
965 write_output_buffer(This
->buffer
, str
, len
);
967 write_output_buffer(This
->buffer
, eqqW
, 2);
970 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
971 if (FAILED(hr
)) return hr
;
973 escaped
= get_escaped_string(str
, &len
);
974 write_output_buffer(This
->buffer
, escaped
, len
);
977 write_output_buffer(This
->buffer
, quotW
, 1);
984 static HRESULT WINAPI
SAXContentHandler_endElement(
985 ISAXContentHandler
*iface
,
986 const WCHAR
*namespaceUri
,
988 const WCHAR
* local_name
,
993 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
995 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
996 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
998 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
1001 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
1003 static const WCHAR closeW
[] = {'/','>'};
1005 write_output_buffer(This
->buffer
, closeW
, 2);
1009 static const WCHAR closetagW
[] = {'<','/'};
1010 static const WCHAR gtW
[] = {'>'};
1012 write_output_buffer(This
->buffer
, closetagW
, 2);
1013 write_output_buffer(This
->buffer
, QName
, nQName
);
1014 write_output_buffer(This
->buffer
, gtW
, 1);
1017 set_element_name(This
, NULL
, 0);
1022 static HRESULT WINAPI
SAXContentHandler_characters(
1023 ISAXContentHandler
*iface
,
1027 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1029 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1031 if (!chars
) return E_INVALIDARG
;
1033 close_element_starttag(This
);
1034 set_element_name(This
, NULL
, 0);
1037 write_output_buffer(This
->buffer
, chars
, nchars
);
1042 static HRESULT WINAPI
SAXContentHandler_ignorableWhitespace(
1043 ISAXContentHandler
*iface
,
1047 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1048 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
1052 static HRESULT WINAPI
SAXContentHandler_processingInstruction(
1053 ISAXContentHandler
*iface
,
1054 const WCHAR
*target
,
1059 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1060 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
1064 static HRESULT WINAPI
SAXContentHandler_skippedEntity(
1065 ISAXContentHandler
*iface
,
1069 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1070 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
1074 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl
=
1076 SAXContentHandler_QueryInterface
,
1077 SAXContentHandler_AddRef
,
1078 SAXContentHandler_Release
,
1079 SAXContentHandler_putDocumentLocator
,
1080 SAXContentHandler_startDocument
,
1081 SAXContentHandler_endDocument
,
1082 SAXContentHandler_startPrefixMapping
,
1083 SAXContentHandler_endPrefixMapping
,
1084 SAXContentHandler_startElement
,
1085 SAXContentHandler_endElement
,
1086 SAXContentHandler_characters
,
1087 SAXContentHandler_ignorableWhitespace
,
1088 SAXContentHandler_processingInstruction
,
1089 SAXContentHandler_skippedEntity
1092 /*** ISAXLexicalHandler ***/
1093 static HRESULT WINAPI
SAXLexicalHandler_QueryInterface(ISAXLexicalHandler
*iface
,
1094 REFIID riid
, void **obj
)
1096 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1097 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
1100 static ULONG WINAPI
SAXLexicalHandler_AddRef(ISAXLexicalHandler
*iface
)
1102 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1103 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
1106 static ULONG WINAPI
SAXLexicalHandler_Release(ISAXLexicalHandler
*iface
)
1108 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1109 return IMXWriter_Release(&This
->IMXWriter_iface
);
1112 static HRESULT WINAPI
SAXLexicalHandler_startDTD(ISAXLexicalHandler
*iface
,
1113 const WCHAR
*name
, int name_len
, const WCHAR
*publicId
, int publicId_len
,
1114 const WCHAR
*systemId
, int systemId_len
)
1116 static const WCHAR doctypeW
[] = {'<','!','D','O','C','T','Y','P','E',' '};
1117 static const WCHAR openintW
[] = {'[','\r','\n'};
1119 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1121 TRACE("(%p)->(%s %s %s)\n", This
, debugstr_wn(name
, name_len
), debugstr_wn(publicId
, publicId_len
),
1122 debugstr_wn(systemId
, systemId_len
));
1124 if (!name
) return E_INVALIDARG
;
1126 write_output_buffer(This
->buffer
, doctypeW
, sizeof(doctypeW
)/sizeof(WCHAR
));
1130 write_output_buffer(This
->buffer
, name
, name_len
);
1131 write_output_buffer(This
->buffer
, spaceW
, 1);
1136 static const WCHAR publicW
[] = {'P','U','B','L','I','C',' '};
1138 write_output_buffer(This
->buffer
, publicW
, sizeof(publicW
)/sizeof(WCHAR
));
1139 write_output_buffer(This
->buffer
, quotW
, 1);
1140 write_output_buffer(This
->buffer
, publicId
, publicId_len
);
1141 write_output_buffer(This
->buffer
, quotW
, 1);
1143 if (!systemId
) return E_INVALIDARG
;
1146 write_output_buffer(This
->buffer
, spaceW
, 1);
1148 write_output_buffer(This
->buffer
, quotW
, 1);
1149 write_output_buffer(This
->buffer
, systemId
, systemId_len
);
1150 write_output_buffer(This
->buffer
, quotW
, 1);
1153 write_output_buffer(This
->buffer
, spaceW
, 1);
1157 static const WCHAR systemW
[] = {'S','Y','S','T','E','M',' '};
1159 write_output_buffer(This
->buffer
, systemW
, sizeof(systemW
)/sizeof(WCHAR
));
1160 write_output_buffer(This
->buffer
, quotW
, 1);
1161 write_output_buffer(This
->buffer
, systemId
, systemId_len
);
1162 write_output_buffer(This
->buffer
, quotW
, 1);
1164 write_output_buffer(This
->buffer
, spaceW
, 1);
1167 write_output_buffer(This
->buffer
, openintW
, sizeof(openintW
)/sizeof(WCHAR
));
1172 static HRESULT WINAPI
SAXLexicalHandler_endDTD(ISAXLexicalHandler
*iface
)
1174 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1175 static const WCHAR closedtdW
[] = {']','>','\r','\n'};
1177 TRACE("(%p)\n", This
);
1179 write_output_buffer(This
->buffer
, closedtdW
, sizeof(closedtdW
)/sizeof(WCHAR
));
1184 static HRESULT WINAPI
SAXLexicalHandler_startEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1186 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1187 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1191 static HRESULT WINAPI
SAXLexicalHandler_endEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1193 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1194 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1198 static HRESULT WINAPI
SAXLexicalHandler_startCDATA(ISAXLexicalHandler
*iface
)
1200 static const WCHAR scdataW
[] = {'<','!','[','C','D','A','T','A','['};
1201 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1203 TRACE("(%p)\n", This
);
1205 write_output_buffer(This
->buffer
, scdataW
, sizeof(scdataW
)/sizeof(WCHAR
));
1210 static HRESULT WINAPI
SAXLexicalHandler_endCDATA(ISAXLexicalHandler
*iface
)
1212 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1213 static const WCHAR ecdataW
[] = {']',']','>'};
1215 TRACE("(%p)\n", This
);
1217 write_output_buffer(This
->buffer
, ecdataW
, sizeof(ecdataW
)/sizeof(WCHAR
));
1222 static HRESULT WINAPI
SAXLexicalHandler_comment(ISAXLexicalHandler
*iface
, const WCHAR
*chars
, int nchars
)
1224 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1225 static const WCHAR copenW
[] = {'<','!','-','-'};
1226 static const WCHAR ccloseW
[] = {'-','-','>','\r','\n'};
1228 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1230 if (!chars
) return E_INVALIDARG
;
1232 close_element_starttag(This
);
1234 write_output_buffer(This
->buffer
, copenW
, sizeof(copenW
)/sizeof(WCHAR
));
1236 write_output_buffer(This
->buffer
, chars
, nchars
);
1237 write_output_buffer(This
->buffer
, ccloseW
, sizeof(ccloseW
)/sizeof(WCHAR
));
1242 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl
=
1244 SAXLexicalHandler_QueryInterface
,
1245 SAXLexicalHandler_AddRef
,
1246 SAXLexicalHandler_Release
,
1247 SAXLexicalHandler_startDTD
,
1248 SAXLexicalHandler_endDTD
,
1249 SAXLexicalHandler_startEntity
,
1250 SAXLexicalHandler_endEntity
,
1251 SAXLexicalHandler_startCDATA
,
1252 SAXLexicalHandler_endCDATA
,
1253 SAXLexicalHandler_comment
1256 static const tid_t mxwriter_iface_tids
[] = {
1261 static dispex_static_data_t mxwriter_dispex
= {
1268 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
1270 static const WCHAR version10W
[] = {'1','.','0',0};
1274 TRACE("(%p, %p)\n", outer
, ppObj
);
1276 if (outer
) FIXME("support aggregation, outer\n");
1278 This
= heap_alloc( sizeof (*This
) );
1280 return E_OUTOFMEMORY
;
1282 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
1283 This
->ISAXContentHandler_iface
.lpVtbl
= &SAXContentHandlerVtbl
;
1284 This
->ISAXLexicalHandler_iface
.lpVtbl
= &SAXLexicalHandlerVtbl
;
1286 This
->class_version
= version
;
1288 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
1289 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
1290 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
1291 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
1292 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
1293 This
->prop_changed
= FALSE
;
1294 This
->encoding
= SysAllocString(utf16W
);
1295 This
->version
= SysAllocString(version10W
);
1296 This
->xml_enc
= XmlEncoding_UTF16
;
1298 This
->element
= NULL
;
1301 This
->dest_written
= 0;
1303 hr
= alloc_output_buffer(This
->xml_enc
, &This
->buffer
);
1305 SysFreeString(This
->encoding
);
1306 SysFreeString(This
->version
);
1311 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
1313 *ppObj
= &This
->IMXWriter_iface
;
1315 TRACE("returning iface %p\n", *ppObj
);