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};
54 OutputBuffer_Native
= 0x001,
55 OutputBuffer_Encoded
= 0x010,
56 OutputBuffer_Both
= 0x100
62 MXWriter_DisableEscaping
,
72 unsigned int allocated
;
79 encoded_buffer encoded
;
86 IMXWriter IMXWriter_iface
;
87 ISAXContentHandler ISAXContentHandler_iface
;
88 ISAXLexicalHandler ISAXLexicalHandler_iface
;
91 MSXML_VERSION class_version
;
93 VARIANT_BOOL props
[MXWriter_LastProp
];
98 BSTR encoding
; /* exact property value */
101 /* contains a pending (or not closed yet) element name or NULL if
102 we don't have to close */
108 output_buffer
*buffer
;
111 static xml_encoding
parse_encoding_name(const WCHAR
*encoding
)
113 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
114 if (!strcmpiW(encoding
, utf8W
)) return XmlEncoding_UTF8
;
115 if (!strcmpiW(encoding
, utf16W
)) return XmlEncoding_UTF16
;
116 return XmlEncoding_Unknown
;
119 static HRESULT
init_encoded_buffer(encoded_buffer
*buffer
)
121 const int initial_len
= 0x2000;
122 buffer
->data
= heap_alloc(initial_len
);
123 if (!buffer
->data
) return E_OUTOFMEMORY
;
125 memset(buffer
->data
, 0, 4);
126 buffer
->allocated
= initial_len
;
132 static void free_encoded_buffer(encoded_buffer
*buffer
)
134 heap_free(buffer
->data
);
137 static HRESULT
get_code_page(xml_encoding encoding
, UINT
*cp
)
141 case XmlEncoding_UTF8
:
144 case XmlEncoding_UTF16
:
148 FIXME("unsupported encoding %d\n", encoding
);
155 static HRESULT
alloc_output_buffer(xml_encoding encoding
, output_buffer
**buffer
)
160 ret
= heap_alloc(sizeof(*ret
));
161 if (!ret
) return E_OUTOFMEMORY
;
163 hr
= get_code_page(encoding
, &ret
->code_page
);
169 hr
= init_encoded_buffer(&ret
->utf16
);
175 if (ret
->code_page
== CP_UTF8
) {
176 hr
= init_encoded_buffer(&ret
->encoded
);
178 free_encoded_buffer(&ret
->utf16
);
184 memset(&ret
->encoded
, 0, sizeof(ret
->encoded
));
191 static void free_output_buffer(output_buffer
*buffer
)
193 free_encoded_buffer(&buffer
->encoded
);
194 free_encoded_buffer(&buffer
->utf16
);
198 static void grow_buffer(encoded_buffer
*buffer
, int length
)
200 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
201 if (buffer
->allocated
< buffer
->written
+ length
+ 4)
203 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
204 buffer
->data
= heap_realloc(buffer
->data
, grown_size
);
205 buffer
->allocated
= grown_size
;
209 static HRESULT
write_output_buffer_mode(output_buffer
*buffer
, output_mode mode
, const WCHAR
*data
, int len
)
214 if (mode
& (OutputBuffer_Encoded
| OutputBuffer_Both
)) {
215 if (buffer
->code_page
== CP_UTF8
)
217 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
218 grow_buffer(&buffer
->encoded
, length
);
219 ptr
= buffer
->encoded
.data
+ buffer
->encoded
.written
;
220 length
= WideCharToMultiByte(buffer
->code_page
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
221 buffer
->encoded
.written
+= len
== -1 ? length
-1 : length
;
225 if (mode
& (OutputBuffer_Native
| OutputBuffer_Both
)) {
226 /* WCHAR data just copied */
227 length
= len
== -1 ? strlenW(data
) : len
;
230 length
*= sizeof(WCHAR
);
232 grow_buffer(&buffer
->utf16
, length
);
233 ptr
= buffer
->utf16
.data
+ buffer
->utf16
.written
;
235 memcpy(ptr
, data
, length
);
236 buffer
->utf16
.written
+= length
;
238 /* null termination */
239 memset(ptr
, 0, sizeof(WCHAR
));
246 static HRESULT
write_output_buffer(output_buffer
*buffer
, const WCHAR
*data
, int len
)
248 return write_output_buffer_mode(buffer
, OutputBuffer_Both
, data
, len
);
251 /* frees buffer data, reallocates with a default lengths */
252 static void close_output_buffer(mxwriter
*This
)
254 heap_free(This
->buffer
->utf16
.data
);
255 heap_free(This
->buffer
->encoded
.data
);
256 init_encoded_buffer(&This
->buffer
->utf16
);
257 init_encoded_buffer(&This
->buffer
->encoded
);
258 get_code_page(This
->xml_enc
, &This
->buffer
->code_page
);
261 /* escapes special characters like:
267 static WCHAR
*get_escaped_string(const WCHAR
*str
, int *len
)
269 static const WCHAR ltW
[] = {'&','l','t',';'};
270 static const WCHAR ampW
[] = {'&','a','m','p',';'};
271 static const WCHAR quotW
[] = {'&','q','u','o','t',';'};
272 static const WCHAR gtW
[] = {'&','g','t',';'};
274 const int default_alloc
= 100;
275 const int grow_thresh
= 10;
276 int p
= *len
, conv_len
;
279 /* default buffer size to something if length is unknown */
280 conv_len
= *len
== -1 ? default_alloc
: max(2**len
, default_alloc
);
281 ptr
= ret
= heap_alloc(conv_len
*sizeof(WCHAR
));
285 if (ptr
- ret
> conv_len
- grow_thresh
)
287 int written
= ptr
- ret
;
289 ptr
= ret
= heap_realloc(ret
, conv_len
*sizeof(WCHAR
));
296 memcpy(ptr
, ltW
, sizeof(ltW
));
297 ptr
+= sizeof(ltW
)/sizeof(WCHAR
);
300 memcpy(ptr
, ampW
, sizeof(ampW
));
301 ptr
+= sizeof(ampW
)/sizeof(WCHAR
);
304 memcpy(ptr
, quotW
, sizeof(quotW
));
305 ptr
+= sizeof(quotW
)/sizeof(WCHAR
);
308 memcpy(ptr
, gtW
, sizeof(gtW
));
309 ptr
+= sizeof(gtW
)/sizeof(WCHAR
);
320 if (*len
!= -1) *len
= ptr
-ret
;
326 static void write_prolog_buffer(const mxwriter
*This
)
328 static const WCHAR versionW
[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"'};
329 static const WCHAR encodingW
[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
330 static const WCHAR standaloneW
[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
331 static const WCHAR yesW
[] = {'y','e','s','\"','?','>'};
332 static const WCHAR noW
[] = {'n','o','\"','?','>'};
333 static const WCHAR quotW
[] = {'\"'};
334 static const WCHAR crlfW
[] = {'\r','\n'};
337 write_output_buffer(This
->buffer
, versionW
, sizeof(versionW
)/sizeof(WCHAR
));
338 write_output_buffer(This
->buffer
, This
->version
, -1);
339 write_output_buffer(This
->buffer
, quotW
, 1);
342 write_output_buffer(This
->buffer
, encodingW
, sizeof(encodingW
)/sizeof(WCHAR
));
344 /* always write UTF-16 to WCHAR buffer */
345 write_output_buffer_mode(This
->buffer
, OutputBuffer_Native
, utf16W
, sizeof(utf16W
)/sizeof(WCHAR
) - 1);
346 write_output_buffer_mode(This
->buffer
, OutputBuffer_Encoded
, This
->encoding
, -1);
347 write_output_buffer(This
->buffer
, quotW
, 1);
350 write_output_buffer(This
->buffer
, standaloneW
, sizeof(standaloneW
)/sizeof(WCHAR
));
351 if (This
->props
[MXWriter_Standalone
] == VARIANT_TRUE
)
352 write_output_buffer(This
->buffer
, yesW
, sizeof(yesW
)/sizeof(WCHAR
));
354 write_output_buffer(This
->buffer
, noW
, sizeof(noW
)/sizeof(WCHAR
));
356 write_output_buffer(This
->buffer
, crlfW
, sizeof(crlfW
)/sizeof(WCHAR
));
359 /* Attempts to the write data from the mxwriter's buffer to
360 * the destination stream (if there is one).
362 static HRESULT
write_data_to_stream(mxwriter
*This
)
364 encoded_buffer
*buffer
;
371 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
372 * 'conv' buffer when UTF8 encoding is used.
374 if (This
->xml_enc
!= XmlEncoding_UTF16
)
375 buffer
= &This
->buffer
->encoded
;
377 buffer
= &This
->buffer
->utf16
;
379 if (This
->dest_written
> buffer
->written
) {
380 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This
->dest_written
, buffer
->written
);
382 } else if (This
->dest_written
== buffer
->written
&& This
->xml_enc
!= XmlEncoding_UTF8
)
383 /* Windows seems to make an empty write call when the encoding is UTF-8 and
384 * all the data has been written to the stream. It doesn't seem make this call
385 * for any other encodings.
389 /* Write the current content from the output buffer into 'dest'.
390 * TODO: Check what Windows does if the IStream doesn't write all of
391 * the data we give it at once.
393 hr
= IStream_Write(This
->dest
, buffer
->data
+This
->dest_written
,
394 buffer
->written
-This
->dest_written
, &written
);
396 WARN("Failed to write data to IStream (0x%08x)\n", hr
);
400 This
->dest_written
+= written
;
404 /* Newly added element start tag left unclosed cause for empty elements
405 we have to close it differently. */
406 static void close_element_starttag(const mxwriter
*This
)
408 static const WCHAR gtW
[] = {'>'};
409 if (!This
->element
) return;
410 write_output_buffer(This
->buffer
, gtW
, 1);
413 static void set_element_name(mxwriter
*This
, const WCHAR
*name
, int len
)
415 SysFreeString(This
->element
);
416 This
->element
= name
? SysAllocStringLen(name
, len
) : NULL
;
419 static inline HRESULT
flush_output_buffer(mxwriter
*This
)
421 close_element_starttag(This
);
422 set_element_name(This
, NULL
, 0);
423 return write_data_to_stream(This
);
426 /* Resets the mxwriter's output buffer by closing it, then creating a new
427 * output buffer using the given encoding.
429 static inline void reset_output_buffer(mxwriter
*This
)
431 close_output_buffer(This
);
432 This
->dest_written
= 0;
435 static HRESULT
writer_set_property(mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL value
)
437 writer
->props
[property
] = value
;
438 writer
->prop_changed
= TRUE
;
442 static HRESULT
writer_get_property(const mxwriter
*writer
, mxwriter_prop property
, VARIANT_BOOL
*value
)
444 if (!value
) return E_POINTER
;
445 *value
= writer
->props
[property
];
449 static inline mxwriter
*impl_from_IMXWriter(IMXWriter
*iface
)
451 return CONTAINING_RECORD(iface
, mxwriter
, IMXWriter_iface
);
454 static inline mxwriter
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
456 return CONTAINING_RECORD(iface
, mxwriter
, ISAXContentHandler_iface
);
459 static inline mxwriter
*impl_from_ISAXLexicalHandler(ISAXLexicalHandler
*iface
)
461 return CONTAINING_RECORD(iface
, mxwriter
, ISAXLexicalHandler_iface
);
464 static HRESULT WINAPI
mxwriter_QueryInterface(IMXWriter
*iface
, REFIID riid
, void **obj
)
466 mxwriter
*This
= impl_from_IMXWriter( iface
);
468 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
472 if ( IsEqualGUID( riid
, &IID_IMXWriter
) ||
473 IsEqualGUID( riid
, &IID_IDispatch
) ||
474 IsEqualGUID( riid
, &IID_IUnknown
) )
476 *obj
= &This
->IMXWriter_iface
;
478 else if ( IsEqualGUID( riid
, &IID_ISAXContentHandler
) )
480 *obj
= &This
->ISAXContentHandler_iface
;
482 else if ( IsEqualGUID( riid
, &IID_ISAXLexicalHandler
) )
484 *obj
= &This
->ISAXLexicalHandler_iface
;
486 else if (dispex_query_interface(&This
->dispex
, riid
, obj
))
488 return *obj
? S_OK
: E_NOINTERFACE
;
492 ERR("interface %s not implemented\n", debugstr_guid(riid
));
494 return E_NOINTERFACE
;
497 IMXWriter_AddRef(iface
);
501 static ULONG WINAPI
mxwriter_AddRef(IMXWriter
*iface
)
503 mxwriter
*This
= impl_from_IMXWriter( iface
);
504 LONG ref
= InterlockedIncrement(&This
->ref
);
506 TRACE("(%p)->(%d)\n", This
, ref
);
511 static ULONG WINAPI
mxwriter_Release(IMXWriter
*iface
)
513 mxwriter
*This
= impl_from_IMXWriter( iface
);
514 ULONG ref
= InterlockedDecrement(&This
->ref
);
516 TRACE("(%p)->(%d)\n", This
, ref
);
520 /* Windows flushes the buffer when the interface is destroyed. */
521 flush_output_buffer(This
);
522 free_output_buffer(This
->buffer
);
524 if (This
->dest
) IStream_Release(This
->dest
);
525 SysFreeString(This
->version
);
526 SysFreeString(This
->encoding
);
528 SysFreeString(This
->element
);
529 release_dispex(&This
->dispex
);
536 static HRESULT WINAPI
mxwriter_GetTypeInfoCount(IMXWriter
*iface
, UINT
* pctinfo
)
538 mxwriter
*This
= impl_from_IMXWriter( iface
);
539 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
542 static HRESULT WINAPI
mxwriter_GetTypeInfo(
544 UINT iTInfo
, LCID lcid
,
545 ITypeInfo
** ppTInfo
)
547 mxwriter
*This
= impl_from_IMXWriter( iface
);
548 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
549 iTInfo
, lcid
, ppTInfo
);
552 static HRESULT WINAPI
mxwriter_GetIDsOfNames(
554 REFIID riid
, LPOLESTR
* rgszNames
,
555 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
557 mxwriter
*This
= impl_from_IMXWriter( iface
);
558 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
559 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
562 static HRESULT WINAPI
mxwriter_Invoke(
564 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
565 WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarResult
,
566 EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
568 mxwriter
*This
= impl_from_IMXWriter( iface
);
569 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
570 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
573 static HRESULT WINAPI
mxwriter_put_output(IMXWriter
*iface
, VARIANT dest
)
575 mxwriter
*This
= impl_from_IMXWriter( iface
);
578 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&dest
));
580 hr
= flush_output_buffer(This
);
588 if (This
->dest
) IStream_Release(This
->dest
);
590 reset_output_buffer(This
);
597 hr
= IUnknown_QueryInterface(V_UNKNOWN(&dest
), &IID_IStream
, (void**)&stream
);
600 /* Recreate the output buffer to make sure it's using the correct encoding. */
601 reset_output_buffer(This
);
603 if (This
->dest
) IStream_Release(This
->dest
);
608 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
612 FIXME("unhandled destination type %s\n", debugstr_variant(&dest
));
619 static HRESULT WINAPI
mxwriter_get_output(IMXWriter
*iface
, VARIANT
*dest
)
621 mxwriter
*This
= impl_from_IMXWriter( iface
);
623 TRACE("(%p)->(%p)\n", This
, dest
);
627 HRESULT hr
= flush_output_buffer(This
);
631 V_VT(dest
) = VT_BSTR
;
632 V_BSTR(dest
) = SysAllocString((WCHAR
*)This
->buffer
->utf16
.data
);
637 FIXME("not implemented when stream is set up\n");
642 static HRESULT WINAPI
mxwriter_put_encoding(IMXWriter
*iface
, BSTR encoding
)
644 mxwriter
*This
= impl_from_IMXWriter( iface
);
648 TRACE("(%p)->(%s)\n", This
, debugstr_w(encoding
));
650 enc
= parse_encoding_name(encoding
);
651 if (enc
== XmlEncoding_Unknown
)
653 FIXME("unsupported encoding %s\n", debugstr_w(encoding
));
657 hr
= flush_output_buffer(This
);
661 SysReAllocString(&This
->encoding
, encoding
);
664 TRACE("got encoding %d\n", This
->xml_enc
);
665 reset_output_buffer(This
);
669 static HRESULT WINAPI
mxwriter_get_encoding(IMXWriter
*iface
, BSTR
*encoding
)
671 mxwriter
*This
= impl_from_IMXWriter( iface
);
673 TRACE("(%p)->(%p)\n", This
, encoding
);
675 if (!encoding
) return E_POINTER
;
677 *encoding
= SysAllocString(This
->encoding
);
678 if (!*encoding
) return E_OUTOFMEMORY
;
683 static HRESULT WINAPI
mxwriter_put_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL value
)
685 mxwriter
*This
= impl_from_IMXWriter( iface
);
687 TRACE("(%p)->(%d)\n", This
, value
);
688 return writer_set_property(This
, MXWriter_BOM
, value
);
691 static HRESULT WINAPI
mxwriter_get_byteOrderMark(IMXWriter
*iface
, VARIANT_BOOL
*value
)
693 mxwriter
*This
= impl_from_IMXWriter( iface
);
695 TRACE("(%p)->(%p)\n", This
, value
);
696 return writer_get_property(This
, MXWriter_BOM
, value
);
699 static HRESULT WINAPI
mxwriter_put_indent(IMXWriter
*iface
, VARIANT_BOOL value
)
701 mxwriter
*This
= impl_from_IMXWriter( iface
);
703 TRACE("(%p)->(%d)\n", This
, value
);
704 return writer_set_property(This
, MXWriter_Indent
, value
);
707 static HRESULT WINAPI
mxwriter_get_indent(IMXWriter
*iface
, VARIANT_BOOL
*value
)
709 mxwriter
*This
= impl_from_IMXWriter( iface
);
711 TRACE("(%p)->(%p)\n", This
, value
);
712 return writer_get_property(This
, MXWriter_Indent
, value
);
715 static HRESULT WINAPI
mxwriter_put_standalone(IMXWriter
*iface
, VARIANT_BOOL value
)
717 mxwriter
*This
= impl_from_IMXWriter( iface
);
719 TRACE("(%p)->(%d)\n", This
, value
);
720 return writer_set_property(This
, MXWriter_Standalone
, value
);
723 static HRESULT WINAPI
mxwriter_get_standalone(IMXWriter
*iface
, VARIANT_BOOL
*value
)
725 mxwriter
*This
= impl_from_IMXWriter( iface
);
727 TRACE("(%p)->(%p)\n", This
, value
);
728 return writer_get_property(This
, MXWriter_Standalone
, value
);
731 static HRESULT WINAPI
mxwriter_put_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL value
)
733 mxwriter
*This
= impl_from_IMXWriter( iface
);
735 TRACE("(%p)->(%d)\n", This
, value
);
736 return writer_set_property(This
, MXWriter_OmitXmlDecl
, value
);
739 static HRESULT WINAPI
mxwriter_get_omitXMLDeclaration(IMXWriter
*iface
, VARIANT_BOOL
*value
)
741 mxwriter
*This
= impl_from_IMXWriter( iface
);
743 TRACE("(%p)->(%p)\n", This
, value
);
744 return writer_get_property(This
, MXWriter_OmitXmlDecl
, value
);
747 static HRESULT WINAPI
mxwriter_put_version(IMXWriter
*iface
, BSTR version
)
749 mxwriter
*This
= impl_from_IMXWriter( iface
);
751 TRACE("(%p)->(%s)\n", This
, debugstr_w(version
));
753 if (!version
) return E_INVALIDARG
;
755 SysFreeString(This
->version
);
756 This
->version
= SysAllocString(version
);
761 static HRESULT WINAPI
mxwriter_get_version(IMXWriter
*iface
, BSTR
*version
)
763 mxwriter
*This
= impl_from_IMXWriter( iface
);
765 TRACE("(%p)->(%p)\n", This
, version
);
767 if (!version
) return E_POINTER
;
769 return return_bstr(This
->version
, version
);
772 static HRESULT WINAPI
mxwriter_put_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL value
)
774 mxwriter
*This
= impl_from_IMXWriter( iface
);
776 TRACE("(%p)->(%d)\n", This
, value
);
777 return writer_set_property(This
, MXWriter_DisableEscaping
, value
);
780 static HRESULT WINAPI
mxwriter_get_disableOutputEscaping(IMXWriter
*iface
, VARIANT_BOOL
*value
)
782 mxwriter
*This
= impl_from_IMXWriter( iface
);
784 TRACE("(%p)->(%p)\n", This
, value
);
785 return writer_get_property(This
, MXWriter_DisableEscaping
, value
);
788 static HRESULT WINAPI
mxwriter_flush(IMXWriter
*iface
)
790 mxwriter
*This
= impl_from_IMXWriter( iface
);
791 TRACE("(%p)\n", This
);
792 return flush_output_buffer(This
);
795 static const struct IMXWriterVtbl MXWriterVtbl
=
797 mxwriter_QueryInterface
,
800 mxwriter_GetTypeInfoCount
,
801 mxwriter_GetTypeInfo
,
802 mxwriter_GetIDsOfNames
,
806 mxwriter_put_encoding
,
807 mxwriter_get_encoding
,
808 mxwriter_put_byteOrderMark
,
809 mxwriter_get_byteOrderMark
,
812 mxwriter_put_standalone
,
813 mxwriter_get_standalone
,
814 mxwriter_put_omitXMLDeclaration
,
815 mxwriter_get_omitXMLDeclaration
,
816 mxwriter_put_version
,
817 mxwriter_get_version
,
818 mxwriter_put_disableOutputEscaping
,
819 mxwriter_get_disableOutputEscaping
,
823 /*** ISAXContentHandler ***/
824 static HRESULT WINAPI
SAXContentHandler_QueryInterface(
825 ISAXContentHandler
*iface
,
829 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
830 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
833 static ULONG WINAPI
SAXContentHandler_AddRef(ISAXContentHandler
*iface
)
835 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
836 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
839 static ULONG WINAPI
SAXContentHandler_Release(ISAXContentHandler
*iface
)
841 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
842 return IMXWriter_Release(&This
->IMXWriter_iface
);
845 static HRESULT WINAPI
SAXContentHandler_putDocumentLocator(
846 ISAXContentHandler
*iface
,
847 ISAXLocator
*locator
)
849 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
850 FIXME("(%p)->(%p)\n", This
, locator
);
854 static HRESULT WINAPI
SAXContentHandler_startDocument(ISAXContentHandler
*iface
)
856 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
858 TRACE("(%p)\n", This
);
860 /* If properties have been changed since the last "endDocument" call
861 * we need to reset the output buffer. If we don't the output buffer
862 * could end up with multiple XML documents in it, plus this seems to
863 * be how Windows works.
865 if (This
->prop_changed
) {
866 reset_output_buffer(This
);
867 This
->prop_changed
= FALSE
;
870 if (This
->props
[MXWriter_OmitXmlDecl
] == VARIANT_TRUE
) return S_OK
;
872 write_prolog_buffer(This
);
874 if (This
->dest
&& This
->xml_enc
== XmlEncoding_UTF16
) {
875 static const char utf16BOM
[] = {0xff,0xfe};
877 if (This
->props
[MXWriter_BOM
] == VARIANT_TRUE
)
878 /* Windows passes a NULL pointer as the pcbWritten parameter and
879 * ignores any error codes returned from this Write call.
881 IStream_Write(This
->dest
, utf16BOM
, sizeof(utf16BOM
), NULL
);
887 static HRESULT WINAPI
SAXContentHandler_endDocument(ISAXContentHandler
*iface
)
889 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
890 TRACE("(%p)\n", This
);
891 This
->prop_changed
= FALSE
;
892 return flush_output_buffer(This
);
895 static HRESULT WINAPI
SAXContentHandler_startPrefixMapping(
896 ISAXContentHandler
*iface
,
902 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
903 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(prefix
, nprefix
), debugstr_wn(uri
, nuri
));
907 static HRESULT WINAPI
SAXContentHandler_endPrefixMapping(
908 ISAXContentHandler
*iface
,
912 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
913 FIXME("(%p)->(%s)\n", This
, debugstr_wn(prefix
, nprefix
));
917 static HRESULT WINAPI
SAXContentHandler_startElement(
918 ISAXContentHandler
*iface
,
919 const WCHAR
*namespaceUri
,
921 const WCHAR
*local_name
,
925 ISAXAttributes
*attr
)
927 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
928 static const WCHAR ltW
[] = {'<'};
930 TRACE("(%p)->(%s %s %s %p)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
),
931 debugstr_wn(local_name
, nlocal_name
), debugstr_wn(QName
, nQName
), attr
);
933 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
936 close_element_starttag(This
);
937 set_element_name(This
, QName
? QName
: emptyW
,
940 write_output_buffer(This
->buffer
, ltW
, 1);
941 write_output_buffer(This
->buffer
, QName
, nQName
);
949 hr
= ISAXAttributes_getLength(attr
, &length
);
950 if (FAILED(hr
)) return hr
;
952 for (i
= 0; i
< length
; i
++)
954 static const WCHAR spaceW
[] = {' '};
955 static const WCHAR eqqW
[] = {'=','\"'};
956 static const WCHAR quotW
[] = {'\"'};
961 hr
= ISAXAttributes_getQName(attr
, i
, &str
, &len
);
962 if (FAILED(hr
)) return hr
;
964 /* space separator in front of every attribute */
965 write_output_buffer(This
->buffer
, spaceW
, 1);
966 write_output_buffer(This
->buffer
, str
, len
);
968 write_output_buffer(This
->buffer
, eqqW
, 2);
971 hr
= ISAXAttributes_getValue(attr
, i
, &str
, &len
);
972 if (FAILED(hr
)) return hr
;
974 escaped
= get_escaped_string(str
, &len
);
975 write_output_buffer(This
->buffer
, escaped
, len
);
978 write_output_buffer(This
->buffer
, quotW
, 1);
985 static HRESULT WINAPI
SAXContentHandler_endElement(
986 ISAXContentHandler
*iface
,
987 const WCHAR
*namespaceUri
,
989 const WCHAR
* local_name
,
994 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
996 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This
, debugstr_wn(namespaceUri
, nnamespaceUri
), nnamespaceUri
,
997 debugstr_wn(local_name
, nlocal_name
), nlocal_name
, debugstr_wn(QName
, nQName
), nQName
);
999 if ((!namespaceUri
|| !local_name
|| !QName
) && This
->class_version
!= MSXML6
)
1000 return E_INVALIDARG
;
1002 if (This
->element
&& QName
&& !strncmpW(This
->element
, QName
, nQName
))
1004 static const WCHAR closeW
[] = {'/','>'};
1006 write_output_buffer(This
->buffer
, closeW
, 2);
1010 static const WCHAR closetagW
[] = {'<','/'};
1011 static const WCHAR gtW
[] = {'>'};
1013 write_output_buffer(This
->buffer
, closetagW
, 2);
1014 write_output_buffer(This
->buffer
, QName
, nQName
);
1015 write_output_buffer(This
->buffer
, gtW
, 1);
1018 set_element_name(This
, NULL
, 0);
1023 static HRESULT WINAPI
SAXContentHandler_characters(
1024 ISAXContentHandler
*iface
,
1028 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1030 TRACE("(%p)->(%s:%d)\n", This
, debugstr_wn(chars
, nchars
), nchars
);
1032 if (!chars
) return E_INVALIDARG
;
1034 close_element_starttag(This
);
1035 set_element_name(This
, NULL
, 0);
1038 write_output_buffer(This
->buffer
, chars
, nchars
);
1043 static HRESULT WINAPI
SAXContentHandler_ignorableWhitespace(
1044 ISAXContentHandler
*iface
,
1048 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1049 FIXME("(%p)->(%s)\n", This
, debugstr_wn(chars
, nchars
));
1053 static HRESULT WINAPI
SAXContentHandler_processingInstruction(
1054 ISAXContentHandler
*iface
,
1055 const WCHAR
*target
,
1060 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1061 FIXME("(%p)->(%s %s)\n", This
, debugstr_wn(target
, ntarget
), debugstr_wn(data
, ndata
));
1065 static HRESULT WINAPI
SAXContentHandler_skippedEntity(
1066 ISAXContentHandler
*iface
,
1070 mxwriter
*This
= impl_from_ISAXContentHandler( iface
);
1071 FIXME("(%p)->(%s)\n", This
, debugstr_wn(name
, nname
));
1075 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl
=
1077 SAXContentHandler_QueryInterface
,
1078 SAXContentHandler_AddRef
,
1079 SAXContentHandler_Release
,
1080 SAXContentHandler_putDocumentLocator
,
1081 SAXContentHandler_startDocument
,
1082 SAXContentHandler_endDocument
,
1083 SAXContentHandler_startPrefixMapping
,
1084 SAXContentHandler_endPrefixMapping
,
1085 SAXContentHandler_startElement
,
1086 SAXContentHandler_endElement
,
1087 SAXContentHandler_characters
,
1088 SAXContentHandler_ignorableWhitespace
,
1089 SAXContentHandler_processingInstruction
,
1090 SAXContentHandler_skippedEntity
1093 /*** ISAXLexicalHandler ***/
1094 static HRESULT WINAPI
SAXLexicalHandler_QueryInterface(ISAXLexicalHandler
*iface
,
1095 REFIID riid
, void **obj
)
1097 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1098 return IMXWriter_QueryInterface(&This
->IMXWriter_iface
, riid
, obj
);
1101 static ULONG WINAPI
SAXLexicalHandler_AddRef(ISAXLexicalHandler
*iface
)
1103 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1104 return IMXWriter_AddRef(&This
->IMXWriter_iface
);
1107 static ULONG WINAPI
SAXLexicalHandler_Release(ISAXLexicalHandler
*iface
)
1109 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1110 return IMXWriter_Release(&This
->IMXWriter_iface
);
1113 static HRESULT WINAPI
SAXLexicalHandler_startDTD(ISAXLexicalHandler
*iface
,
1114 const WCHAR
*name
, int name_len
, const WCHAR
*publicId
, int publicId_len
,
1115 const WCHAR
*systemId
, int systemId_len
)
1117 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1118 FIXME("(%p)->(%s %s %s): stub\n", This
, debugstr_wn(name
, name_len
), debugstr_wn(publicId
, publicId_len
),
1119 debugstr_wn(systemId
, systemId_len
));
1123 static HRESULT WINAPI
SAXLexicalHandler_endDTD(ISAXLexicalHandler
*iface
)
1125 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1126 FIXME("(%p): stub\n", This
);
1130 static HRESULT WINAPI
SAXLexicalHandler_startEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1132 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1133 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1137 static HRESULT WINAPI
SAXLexicalHandler_endEntity(ISAXLexicalHandler
*iface
, const WCHAR
*name
, int len
)
1139 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1140 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(name
, len
));
1144 static HRESULT WINAPI
SAXLexicalHandler_startCDATA(ISAXLexicalHandler
*iface
)
1146 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1147 FIXME("(%p): stub\n", This
);
1151 static HRESULT WINAPI
SAXLexicalHandler_endCDATA(ISAXLexicalHandler
*iface
)
1153 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1154 FIXME("(%p): stub\n", This
);
1158 static HRESULT WINAPI
SAXLexicalHandler_comment(ISAXLexicalHandler
*iface
, const WCHAR
*chars
, int len
)
1160 mxwriter
*This
= impl_from_ISAXLexicalHandler( iface
);
1161 FIXME("(%p)->(%s): stub\n", This
, debugstr_wn(chars
, len
));
1165 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl
=
1167 SAXLexicalHandler_QueryInterface
,
1168 SAXLexicalHandler_AddRef
,
1169 SAXLexicalHandler_Release
,
1170 SAXLexicalHandler_startDTD
,
1171 SAXLexicalHandler_endDTD
,
1172 SAXLexicalHandler_startEntity
,
1173 SAXLexicalHandler_endEntity
,
1174 SAXLexicalHandler_startCDATA
,
1175 SAXLexicalHandler_endCDATA
,
1176 SAXLexicalHandler_comment
1179 static const tid_t mxwriter_iface_tids
[] = {
1184 static dispex_static_data_t mxwriter_dispex
= {
1191 HRESULT
MXWriter_create(MSXML_VERSION version
, IUnknown
*outer
, void **ppObj
)
1193 static const WCHAR version10W
[] = {'1','.','0',0};
1197 TRACE("(%p, %p)\n", outer
, ppObj
);
1199 if (outer
) FIXME("support aggregation, outer\n");
1201 This
= heap_alloc( sizeof (*This
) );
1203 return E_OUTOFMEMORY
;
1205 This
->IMXWriter_iface
.lpVtbl
= &MXWriterVtbl
;
1206 This
->ISAXContentHandler_iface
.lpVtbl
= &SAXContentHandlerVtbl
;
1207 This
->ISAXLexicalHandler_iface
.lpVtbl
= &SAXLexicalHandlerVtbl
;
1209 This
->class_version
= version
;
1211 This
->props
[MXWriter_BOM
] = VARIANT_TRUE
;
1212 This
->props
[MXWriter_DisableEscaping
] = VARIANT_FALSE
;
1213 This
->props
[MXWriter_Indent
] = VARIANT_FALSE
;
1214 This
->props
[MXWriter_OmitXmlDecl
] = VARIANT_FALSE
;
1215 This
->props
[MXWriter_Standalone
] = VARIANT_FALSE
;
1216 This
->prop_changed
= FALSE
;
1217 This
->encoding
= SysAllocString(utf16W
);
1218 This
->version
= SysAllocString(version10W
);
1219 This
->xml_enc
= XmlEncoding_UTF16
;
1221 This
->element
= NULL
;
1224 This
->dest_written
= 0;
1226 hr
= alloc_output_buffer(This
->xml_enc
, &This
->buffer
);
1228 SysFreeString(This
->encoding
);
1229 SysFreeString(This
->version
);
1234 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IMXWriter_iface
, &mxwriter_dispex
);
1236 *ppObj
= &This
->IMXWriter_iface
;
1238 TRACE("returning iface %p\n", *ppObj
);