2 * MXWriter implementation
4 * Copyright 2011 Nikolay Sivov for CodeWeavers
5 * Copyright 2011 Thomas Mullaly
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 # include <libxml/parser.h>
36 #include "wine/debug.h"
38 #include "msxml_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
44 static const WCHAR utf16W
[] = {'U','T','F','-','1','6',0};
45 static const WCHAR emptyW
[] = {0};
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
;
92 MSXML_VERSION class_version
;
94 VARIANT_BOOL props
[MXWriter_LastProp
];
99 BSTR encoding
; /* exact property value */
100 xml_encoding xml_enc
;
102 /* contains a pending (or not closed yet) element name or NULL if
103 we don't have to close */
109 output_buffer
*buffer
;
112 static xml_encoding
parse_encoding_name(const WCHAR
*encoding
)
114 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
115 if (!strcmpiW(encoding
, utf8W
)) return XmlEncoding_UTF8
;
116 if (!strcmpiW(encoding
, utf16W
)) return XmlEncoding_UTF16
;
117 return XmlEncoding_Unknown
;
120 static HRESULT
init_encoded_buffer(encoded_buffer
*buffer
)
122 const int initial_len
= 0x2000;
123 buffer
->data
= heap_alloc(initial_len
);
124 if (!buffer
->data
) return E_OUTOFMEMORY
;
126 memset(buffer
->data
, 0, 4);
127 buffer
->allocated
= initial_len
;
133 static void free_encoded_buffer(encoded_buffer
*buffer
)
135 heap_free(buffer
->data
);
138 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
142 case XmlEncoding_UTF8
:
145 case XmlEncoding_UTF16
:
149 FIXME("unsupported encoding %d\n", encoding
);
156 static HRESULT
alloc_output_buffer(xml_encoding encoding
, output_buffer
**buffer
)
161 ret
= heap_alloc(sizeof(*ret
));
162 if (!ret
) return E_OUTOFMEMORY
;
164 hr
= get_code_page(encoding
, &ret
->code_page
);
170 hr
= init_encoded_buffer(&ret
->utf16
);
176 if (ret
->code_page
== CP_UTF8
) {
177 hr
= init_encoded_buffer(&ret
->encoded
);
179 free_encoded_buffer(&ret
->utf16
);
185 memset(&ret
->encoded
, 0, sizeof(ret
->encoded
));
192 static void free_output_buffer(output_buffer
*buffer
)
194 free_encoded_buffer(&buffer
->encoded
);
195 free_encoded_buffer(&buffer
->utf16
);
199 static void grow_buffer(encoded_buffer
*buffer
, int length
)
201 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
202 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
204 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
205 buffer
->data
= heap_realloc(buffer
->data
, grown_size
);
206 buffer
->allocated
= grown_size
;
210 static HRESULT
write_output_buffer_mode(output_buffer
*buffer
, output_mode mode
, const WCHAR
*data
, int len
)
215 if (mode
& (OutputBuffer_Encoded
| OutputBuffer_Both
)) {
216 if (buffer
->code_page
== CP_UTF8
)
218 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
219 grow_buffer(&buffer
->encoded
, length
);
220 ptr
= buffer
->encoded
.data
+ buffer
->encoded
.written
;
221 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
222 buffer
->encoded
.written
+= len
== -1 ? length
-1 : length
;
226 if (mode
& (OutputBuffer_Native
| OutputBuffer_Both
)) {
227 /* WCHAR data just copied */
228 length
= len
== -1 ? strlenW(data
) : len
;
231 length
*= sizeof(WCHAR
);
233 grow_buffer(&buffer
->utf16
, length
);
234 ptr
= buffer
->utf16
.data
+ buffer
->utf16
.written
;
236 memcpy(ptr
, data
, length
);
237 buffer
->utf16
.written
+= length
;
239 /* null termination */
240 memset(ptr
, 0, sizeof(WCHAR
));
247 static HRESULT
write_output_buffer(output_buffer
*buffer
, const WCHAR
*data
, int len
)
249 return write_output_buffer_mode(buffer
, OutputBuffer_Both
, data
, len
);
252 /* frees buffer data, reallocates with a default lengths */
253 static void close_output_buffer(mxwriter
*This
)
255 heap_free(This
->buffer
->utf16
.data
);
256 heap_free(This
->buffer
->encoded
.data
);
257 init_encoded_buffer(&This
->buffer
->utf16
);
258 init_encoded_buffer(&This
->buffer
->encoded
);
259 get_code_page(This
->xml_enc
, &This
->buffer
->code_page
);
262 /* escapes special characters like:
268 static WCHAR
*get_escaped_string(const WCHAR
*str
, int *len
)
270 static const WCHAR ltW
[] = {'&','l','t',';'};
271 static const WCHAR ampW
[] = {'&','a','m','p',';'};
272 static const WCHAR quotW
[] = {'&','q','u','o','t',';'};
273 static const WCHAR gtW
[] = {'&','g','t',';'};
275 const int default_alloc
= 100;
276 const int grow_thresh
= 10;
277 int p
= *len
, conv_len
;
280 /* default buffer size to something if length is unknown */
281 conv_len
= *len
== -1 ? default_alloc
: max(2**len
, default_alloc
);
282 ptr
= ret
= heap_alloc(conv_len
*sizeof(WCHAR
));
286 if (ptr
- ret
> conv_len
- grow_thresh
)
288 int written
= ptr
- ret
;
290 ptr
= ret
= heap_realloc(ret
, conv_len
*sizeof(WCHAR
));
297 memcpy(ptr
, ltW
, sizeof(ltW
));
298 ptr
+= sizeof(ltW
)/sizeof(WCHAR
);
301 memcpy(ptr
, ampW
, sizeof(ampW
));
302 ptr
+= sizeof(ampW
)/sizeof(WCHAR
);
305 memcpy(ptr
, quotW
, sizeof(quotW
));
306 ptr
+= sizeof(quotW
)/sizeof(WCHAR
);
309 memcpy(ptr
, gtW
, sizeof(gtW
));
310 ptr
+= sizeof(gtW
)/sizeof(WCHAR
);
321 if (*len
!= -1) *len
= ptr
-ret
;
327 static void write_prolog_buffer(const mxwriter
*This
)
329 static const WCHAR versionW
[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"'};
330 static const WCHAR encodingW
[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
331 static const WCHAR standaloneW
[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
332 static const WCHAR yesW
[] = {'y','e','s','\"','?','>'};
333 static const WCHAR noW
[] = {'n','o','\"','?','>'};
334 static const WCHAR quotW
[] = {'\"'};
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 HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
462 mxwriter
*This
= impl_from_IMXWriter( iface
);
464 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
468 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
469 IsEqualGUID( riid
, &IID_IDispatch
) ||
470 IsEqualGUID( riid
, &IID_IUnknown
) )
472 *obj
= &This
->IMXWriter_iface
;
474 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
476 *obj
= &This
->ISAXContentHandler_iface
;
478 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
480 return *obj
? S_OK
: E_NOINTERFACE
;
484 ERR("interface %s not implemented\n", debugstr_guid(riid
));
486 return E_NOINTERFACE
;
489 IMXWriter_AddRef(iface
);
493 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
495 mxwriter
*This
= impl_from_IMXWriter( iface
);
496 LONG ref
= InterlockedIncrement(&This
->ref
);
498 TRACE("(%p)->(%d)\n", This
, ref
);
503 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
505 mxwriter
*This
= impl_from_IMXWriter( iface
);
506 ULONG ref
= InterlockedDecrement(&This
->ref
);
508 TRACE("(%p)->(%d)\n", This
, ref
);
512 /* Windows flushes the buffer when the interface is destroyed. */
513 flush_output_buffer(This
);
514 free_output_buffer(This
->buffer
);
516 if (This
->dest
) IStream_Release(This
->dest
);
517 SysFreeString(This
->version
);
518 SysFreeString(This
->encoding
);
520 SysFreeString(This
->element
);
521 release_dispex(&This
->dispex
);
528 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
530 mxwriter
*This
= impl_from_IMXWriter( iface
);
531 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
534 static HRESULT WINAPI
mxwriter_GetTypeInfo(
536 UINT iTInfo
, LCID lcid
,
537 ITypeInfo
** ppTInfo
)
539 mxwriter
*This
= impl_from_IMXWriter( iface
);
540 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
541 iTInfo
, lcid
, ppTInfo
);
544 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
546 REFIID riid
, LPOLESTR
* rgszNames
,
547 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
549 mxwriter
*This
= impl_from_IMXWriter( iface
);
550 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
551 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
554 static HRESULT WINAPI
mxwriter_Invoke(
556 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
557 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
558 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
560 mxwriter
*This
= impl_from_IMXWriter( iface
);
561 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
562 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
565 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
567 mxwriter
*This
= impl_from_IMXWriter( iface
);
570 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
572 hr
= flush_output_buffer(This
);
580 if (This
->dest
) IStream_Release(This
->dest
);
582 reset_output_buffer(This
);
589 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
592 /* Recreate the output buffer to make sure it's using the correct encoding. */
593 reset_output_buffer(This
);
595 if (This
->dest
) IStream_Release(This
->dest
);
600 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
604 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
611 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
613 mxwriter
*This
= impl_from_IMXWriter( iface
);
615 TRACE("(%p)->(%p)\n", This
, dest
);
619 HRESULT hr
= flush_output_buffer(This
);
623 V_VT(dest
) = VT_BSTR
;
624 V_BSTR(dest
) = SysAllocString((WCHAR
*)This
->buffer
->utf16
.data
);
629 FIXME("not implemented when stream is set up\n");
634 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
636 mxwriter
*This
= impl_from_IMXWriter( iface
);
640 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
642 enc
= parse_encoding_name(encoding
);
643 if (enc
== XmlEncoding_Unknown
)
645 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
649 hr
= flush_output_buffer(This
);
653 SysReAllocString(&This
->encoding
, encoding
);
656 TRACE("got encoding %d\n", This
->xml_enc
);
657 reset_output_buffer(This
);
661 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
663 mxwriter
*This
= impl_from_IMXWriter( iface
);
665 TRACE("(%p)->(%p)\n", This
, encoding
);
667 if (!encoding
) return E_POINTER
;
669 *encoding
= SysAllocString(This
->encoding
);
670 if (!*encoding
) return E_OUTOFMEMORY
;
675 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
677 mxwriter
*This
= impl_from_IMXWriter( iface
);
679 TRACE("(%p)->(%d)\n", This
, value
);
680 return writer_set_property(This
, MXWriter_BOM
, value
);
683 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
685 mxwriter
*This
= impl_from_IMXWriter( iface
);
687 TRACE("(%p)->(%p)\n", This
, value
);
688 return writer_get_property(This
, MXWriter_BOM
, value
);
691 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
693 mxwriter
*This
= impl_from_IMXWriter( iface
);
695 TRACE("(%p)->(%d)\n", This
, value
);
696 return writer_set_property(This
, MXWriter_Indent
, value
);
699 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
701 mxwriter
*This
= impl_from_IMXWriter( iface
);
703 TRACE("(%p)->(%p)\n", This
, value
);
704 return writer_get_property(This
, MXWriter_Indent
, value
);
707 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
709 mxwriter
*This
= impl_from_IMXWriter( iface
);
711 TRACE("(%p)->(%d)\n", This
, value
);
712 return writer_set_property(This
, MXWriter_Standalone
, value
);
715 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
717 mxwriter
*This
= impl_from_IMXWriter( iface
);
719 TRACE("(%p)->(%p)\n", This
, value
);
720 return writer_get_property(This
, MXWriter_Standalone
, value
);
723 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
725 mxwriter
*This
= impl_from_IMXWriter( iface
);
727 TRACE("(%p)->(%d)\n", This
, value
);
728 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
731 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
733 mxwriter
*This
= impl_from_IMXWriter( iface
);
735 TRACE("(%p)->(%p)\n", This
, value
);
736 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
739 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
741 mxwriter
*This
= impl_from_IMXWriter( iface
);
743 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
745 if (!version
) return E_INVALIDARG
;
747 SysFreeString(This
->version
);
748 This
->version
= SysAllocString(version
);
753 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
755 mxwriter
*This
= impl_from_IMXWriter( iface
);
757 TRACE("(%p)->(%p)\n", This
, version
);
759 if (!version
) return E_POINTER
;
761 return return_bstr(This
->version
, version
);
764 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
766 mxwriter
*This
= impl_from_IMXWriter( iface
);
768 TRACE("(%p)->(%d)\n", This
, value
);
769 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
772 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
774 mxwriter
*This
= impl_from_IMXWriter( iface
);
776 TRACE("(%p)->(%p)\n", This
, value
);
777 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
780 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
782 mxwriter
*This
= impl_from_IMXWriter( iface
);
783 TRACE("(%p)\n", This
);
784 return flush_output_buffer(This
);
787 static const struct IMXWriterVtbl MXWriterVtbl
=
789 mxwriter_QueryInterface
,
792 mxwriter_GetTypeInfoCount
,
793 mxwriter_GetTypeInfo
,
794 mxwriter_GetIDsOfNames
,
798 mxwriter_put_encoding
,
799 mxwriter_get_encoding
,
800 mxwriter_put_byteOrderMark
,
801 mxwriter_get_byteOrderMark
,
804 mxwriter_put_standalone
,
805 mxwriter_get_standalone
,
806 mxwriter_put_omitXMLDeclaration
,
807 mxwriter_get_omitXMLDeclaration
,
808 mxwriter_put_version
,
809 mxwriter_get_version
,
810 mxwriter_put_disableOutputEscaping
,
811 mxwriter_get_disableOutputEscaping
,
815 /*** ISAXContentHandler ***/
816 static HRESULT WINAPI
mxwriter_saxcontent_QueryInterface(
817 ISAXContentHandler
*iface
,
821 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
822 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
825 static ULONG WINAPI
mxwriter_saxcontent_AddRef(ISAXContentHandler
*iface
)
827 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
828 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
831 static ULONG WINAPI
mxwriter_saxcontent_Release(ISAXContentHandler
*iface
)
833 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
834 return IMXWriter_Release(&This
->IMXWriter_iface
);
837 static HRESULT WINAPI
mxwriter_saxcontent_putDocumentLocator(
838 ISAXContentHandler
*iface
,
839 ISAXLocator
*locator
)
841 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
842 FIXME("(%p)->(%p)\n", This
, locator
);
846 static HRESULT WINAPI
mxwriter_saxcontent_startDocument(ISAXContentHandler
*iface
)
848 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
850 TRACE("(%p)\n", This
);
852 /* If properties have been changed since the last "endDocument" call
853 * we need to reset the output buffer. If we don't the output buffer
854 * could end up with multiple XML documents in it, plus this seems to
855 * be how Windows works.
857 if (This
->prop_changed
) {
858 reset_output_buffer(This
);
859 This
->prop_changed
= FALSE
;
862 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
864 write_prolog_buffer(This
);
866 if (This
->dest
&& This
->xml_enc
== XmlEncoding_UTF16
) {
867 static const char utf16BOM
[] = {0xff,0xfe};
869 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
870 /* Windows passes a NULL pointer as the pcbWritten parameter and
871 * ignores any error codes returned from this Write call.
873 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
879 static HRESULT WINAPI
mxwriter_saxcontent_endDocument(ISAXContentHandler
*iface
)
881 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
882 TRACE("(%p)\n", This
);
883 This
->prop_changed
= FALSE
;
884 return flush_output_buffer(This
);
887 static HRESULT WINAPI
mxwriter_saxcontent_startPrefixMapping(
888 ISAXContentHandler
*iface
,
894 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
895 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
899 static HRESULT WINAPI
mxwriter_saxcontent_endPrefixMapping(
900 ISAXContentHandler
*iface
,
904 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
905 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
909 static HRESULT WINAPI
mxwriter_saxcontent_startElement(
910 ISAXContentHandler
*iface
,
911 const WCHAR
*namespaceUri
,
913 const WCHAR
*local_name
,
917 ISAXAttributes
*attr
)
919 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
920 static const WCHAR ltW
[] = {'<'};
922 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
923 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
925 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
928 close_element_starttag(This
);
929 set_element_name(This
, QName
? QName
: emptyW
,
932 write_output_buffer(This
->buffer
, ltW
, 1);
933 write_output_buffer(This
->buffer
, QName
, nQName
);
941 hr
= ISAXAttributes_getLength(attr
, &length
);
942 if (FAILED(hr
)) return hr
;
944 for (i
= 0; i
< length
; i
++)
946 static const WCHAR spaceW
[] = {' '};
947 static const WCHAR eqqW
[] = {'=','\"'};
948 static const WCHAR quotW
[] = {'\"'};
953 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
954 if (FAILED(hr
)) return hr
;
956 /* space separator in front of every attribute */
957 write_output_buffer(This
->buffer
, spaceW
, 1);
958 write_output_buffer(This
->buffer
, str
, len
);
960 write_output_buffer(This
->buffer
, eqqW
, 2);
963 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
964 if (FAILED(hr
)) return hr
;
966 escaped
= get_escaped_string(str
, &len
);
967 write_output_buffer(This
->buffer
, escaped
, len
);
970 write_output_buffer(This
->buffer
, quotW
, 1);
977 static HRESULT WINAPI
mxwriter_saxcontent_endElement(
978 ISAXContentHandler
*iface
,
979 const WCHAR
*namespaceUri
,
981 const WCHAR
* local_name
,
986 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
988 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
989 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
991 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
994 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
996 static const WCHAR closeW
[] = {'/','>'};
998 write_output_buffer(This
->buffer
, closeW
, 2);
1002 static const WCHAR closetagW
[] = {'<','/'};
1003 static const WCHAR gtW
[] = {'>'};
1005 write_output_buffer(This
->buffer
, closetagW
, 2);
1006 write_output_buffer(This
->buffer
, QName
, nQName
);
1007 write_output_buffer(This
->buffer
, gtW
, 1);
1010 set_element_name(This
, NULL
, 0);
1015 static HRESULT WINAPI
mxwriter_saxcontent_characters(
1016 ISAXContentHandler
*iface
,
1020 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1022 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1024 if (!chars
) return E_INVALIDARG
;
1026 close_element_starttag(This
);
1027 set_element_name(This
, NULL
, 0);
1030 write_output_buffer(This
->buffer
, chars
, nchars
);
1035 static HRESULT WINAPI
mxwriter_saxcontent_ignorableWhitespace(
1036 ISAXContentHandler
*iface
,
1040 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1041 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
1045 static HRESULT WINAPI
mxwriter_saxcontent_processingInstruction(
1046 ISAXContentHandler
*iface
,
1047 const WCHAR
*target
,
1052 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1053 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
1057 static HRESULT WINAPI
mxwriter_saxcontent_skippedEntity(
1058 ISAXContentHandler
*iface
,
1062 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1063 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
1067 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl
=
1069 mxwriter_saxcontent_QueryInterface
,
1070 mxwriter_saxcontent_AddRef
,
1071 mxwriter_saxcontent_Release
,
1072 mxwriter_saxcontent_putDocumentLocator
,
1073 mxwriter_saxcontent_startDocument
,
1074 mxwriter_saxcontent_endDocument
,
1075 mxwriter_saxcontent_startPrefixMapping
,
1076 mxwriter_saxcontent_endPrefixMapping
,
1077 mxwriter_saxcontent_startElement
,
1078 mxwriter_saxcontent_endElement
,
1079 mxwriter_saxcontent_characters
,
1080 mxwriter_saxcontent_ignorableWhitespace
,
1081 mxwriter_saxcontent_processingInstruction
,
1082 mxwriter_saxcontent_skippedEntity
1085 static const tid_t mxwriter_iface_tids
[] = {
1090 static dispex_static_data_t mxwriter_dispex
= {
1097 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
1099 static const WCHAR version10W
[] = {'1','.','0',0};
1103 TRACE("(%p, %p)\n", outer
, ppObj
);
1105 if (outer
) FIXME("support aggregation, outer\n");
1107 This
= heap_alloc( sizeof (*This
) );
1109 return E_OUTOFMEMORY
;
1111 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
1112 This
->ISAXContentHandler_iface
.lpVtbl
= &mxwriter_saxcontent_vtbl
;
1114 This
->class_version
= version
;
1116 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
1117 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
1118 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
1119 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
1120 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
1121 This
->prop_changed
= FALSE
;
1122 This
->encoding
= SysAllocString(utf16W
);
1123 This
->version
= SysAllocString(version10W
);
1124 This
->xml_enc
= XmlEncoding_UTF16
;
1126 This
->element
= NULL
;
1129 This
->dest_written
= 0;
1131 hr
= alloc_output_buffer(This
->xml_enc
, &This
->buffer
);
1133 SysFreeString(This
->encoding
);
1134 SysFreeString(This
->version
);
1139 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
1141 *ppObj
= &This
->IMXWriter_iface
;
1143 TRACE("returning iface %p\n", *ppObj
);
1150 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **obj
)
1152 MESSAGE("This program tried to use a MXXMLWriter object, but\n"
1153 "libxml2 support was not present at compile time.\n");
1157 #endif /* HAVE_LIBXML2 */