2 * IXmlWriter implementation
4 * Copyright 2011 Alistair Leslie-Hughes
5 * Copyright 2014-2018 Nikolay Sivov for CodeWeavers
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
30 #include "xmllite_private.h"
33 #include "wine/debug.h"
34 #include "wine/list.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(xmllite
);
38 /* not defined in public headers */
39 DEFINE_GUID(IID_IXmlWriterOutput
, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
41 static const WCHAR xmlnsuriW
[] = L
"http://www.w3.org/2000/xmlns/";
46 unsigned int allocated
;
53 XmlWriterState_Initial
, /* output is not set yet */
54 XmlWriterState_Ready
, /* SetOutput() was called, ready to start */
55 XmlWriterState_InvalidEncoding
, /* SetOutput() was called, but output had invalid encoding */
56 XmlWriterState_PIDocStarted
, /* document was started with manually added 'xml' PI */
57 XmlWriterState_DocStarted
, /* document was started with WriteStartDocument() */
58 XmlWriterState_ElemStarted
, /* writing element */
59 XmlWriterState_Content
, /* content is accepted at this point */
60 XmlWriterState_DocClosed
/* WriteEndDocument was called */
65 IXmlWriterOutput IXmlWriterOutput_iface
;
68 ISequentialStream
*stream
;
70 xml_encoding encoding
;
71 WCHAR
*encoding_name
; /* exactly as specified on output creation */
72 struct output_buffer buffer
;
76 static const struct IUnknownVtbl xmlwriteroutputvtbl
;
82 unsigned int len
; /* qname length in chars */
93 struct element
*element
;
96 typedef struct _xmlwriter
98 IXmlWriter IXmlWriter_iface
;
101 xmlwriteroutput
*output
;
102 unsigned int indent_level
;
106 XmlConformanceLevel conformance
;
107 XmlWriterState state
;
108 struct list elements
;
109 DWORD bomwritten
: 1;
110 DWORD starttagopen
: 1;
114 static inline xmlwriter
*impl_from_IXmlWriter(IXmlWriter
*iface
)
116 return CONTAINING_RECORD(iface
, xmlwriter
, IXmlWriter_iface
);
119 static inline xmlwriteroutput
*impl_from_IXmlWriterOutput(IXmlWriterOutput
*iface
)
121 return CONTAINING_RECORD(iface
, xmlwriteroutput
, IXmlWriterOutput_iface
);
124 static const char *debugstr_writer_prop(XmlWriterProperty prop
)
126 static const char * const prop_names
[] =
131 "OmitXmlDeclaration",
135 if (prop
> _XmlWriterProperty_Last
)
136 return wine_dbg_sprintf("unknown property=%d", prop
);
138 return prop_names
[prop
];
141 static HRESULT
create_writer_output(IUnknown
*stream
, IMalloc
*imalloc
, xml_encoding encoding
,
142 const WCHAR
*encoding_name
, xmlwriteroutput
**out
);
144 /* writer output memory allocation functions */
145 static inline void *writeroutput_alloc(xmlwriteroutput
*output
, size_t len
)
147 return m_alloc(output
->imalloc
, len
);
150 static inline void writeroutput_free(xmlwriteroutput
*output
, void *mem
)
152 m_free(output
->imalloc
, mem
);
155 static inline void *writeroutput_realloc(xmlwriteroutput
*output
, void *mem
, size_t len
)
157 return m_realloc(output
->imalloc
, mem
, len
);
160 /* writer memory allocation functions */
161 static inline void *writer_alloc(const xmlwriter
*writer
, size_t len
)
163 return m_alloc(writer
->imalloc
, len
);
166 static inline void writer_free(const xmlwriter
*writer
, void *mem
)
168 m_free(writer
->imalloc
, mem
);
171 static struct element
*alloc_element(xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*local
)
176 ret
= writer_alloc(writer
, sizeof(*ret
));
177 if (!ret
) return ret
;
179 len
= prefix
? lstrlenW(prefix
) + 1 /* ':' */ : 0;
180 len
+= lstrlenW(local
);
182 ret
->qname
= writer_alloc(writer
, (len
+ 1)*sizeof(WCHAR
));
186 lstrcpyW(ret
->qname
, prefix
);
187 lstrcatW(ret
->qname
, L
":");
191 lstrcatW(ret
->qname
, local
);
197 static void writer_free_element(xmlwriter
*writer
, struct element
*element
)
201 LIST_FOR_EACH_ENTRY_SAFE(ns
, ns2
, &element
->ns
, struct ns
, entry
)
203 list_remove(&ns
->entry
);
204 writer_free(writer
, ns
->prefix
);
205 writer_free(writer
, ns
->uri
);
206 writer_free(writer
, ns
);
209 writer_free(writer
, element
->qname
);
210 writer_free(writer
, element
);
213 static void writer_free_element_stack(xmlwriter
*writer
)
215 struct element
*element
, *element2
;
217 LIST_FOR_EACH_ENTRY_SAFE(element
, element2
, &writer
->elements
, struct element
, entry
)
219 list_remove(&element
->entry
);
220 writer_free_element(writer
, element
);
224 static void writer_push_element(xmlwriter
*writer
, struct element
*element
)
226 list_add_head(&writer
->elements
, &element
->entry
);
229 static struct element
*pop_element(xmlwriter
*writer
)
231 struct element
*element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
234 list_remove(&element
->entry
);
239 static WCHAR
*writer_strndupW(const xmlwriter
*writer
, const WCHAR
*str
, int len
)
250 size
= (len
+ 1) * sizeof(WCHAR
);
251 ret
= writer_alloc(writer
, size
);
252 memcpy(ret
, str
, size
);
256 static WCHAR
*writer_strdupW(const xmlwriter
*writer
, const WCHAR
*str
)
258 return writer_strndupW(writer
, str
, -1);
261 static struct ns
*writer_push_ns(xmlwriter
*writer
, const WCHAR
*prefix
, int prefix_len
, const WCHAR
*uri
)
263 struct element
*element
;
266 element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
270 if ((ns
= writer_alloc(writer
, sizeof(*ns
))))
272 ns
->prefix
= writer_strndupW(writer
, prefix
, prefix_len
);
273 ns
->prefix_len
= prefix_len
;
274 ns
->uri
= writer_strdupW(writer
, uri
);
276 ns
->element
= element
;
277 list_add_tail(&element
->ns
, &ns
->entry
);
283 static BOOL
is_empty_string(const WCHAR
*str
)
285 return !str
|| !*str
;
288 static struct ns
*writer_find_ns_current(const xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*uri
)
290 struct element
*element
;
293 if (is_empty_string(prefix
) || is_empty_string(uri
))
296 element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
298 LIST_FOR_EACH_ENTRY(ns
, &element
->ns
, struct ns
, entry
)
300 if (!wcscmp(uri
, ns
->uri
) && !wcscmp(prefix
, ns
->prefix
))
307 static struct ns
*writer_find_ns(const xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*uri
)
309 struct element
*element
;
312 if (is_empty_string(prefix
) && is_empty_string(uri
))
315 LIST_FOR_EACH_ENTRY(element
, &writer
->elements
, struct element
, entry
)
317 LIST_FOR_EACH_ENTRY(ns
, &element
->ns
, struct ns
, entry
)
321 if (!ns
->prefix
) continue;
322 if (!wcscmp(ns
->prefix
, prefix
))
325 else if (!wcscmp(uri
, ns
->uri
))
327 if (prefix
&& !*prefix
)
329 if (!prefix
|| !wcscmp(prefix
, ns
->prefix
))
338 static HRESULT
is_valid_ncname(const WCHAR
*str
, int *out
)
349 if (!is_ncnamechar(*str
))
350 return WC_E_NAMECHARACTER
;
359 static HRESULT
is_valid_name(const WCHAR
*str
, unsigned int *out
)
361 unsigned int len
= 1;
368 if (!is_namestartchar(*str
++))
369 return WC_E_NAMECHARACTER
;
373 if (!is_namechar(*str
))
374 return WC_E_NAMECHARACTER
;
382 static HRESULT
is_valid_pubid(const WCHAR
*str
, unsigned int *out
)
384 unsigned int len
= 0;
393 if (!is_pubchar(*str
++))
394 return WC_E_PUBLICID
;
403 static HRESULT
init_output_buffer(xmlwriteroutput
*output
)
405 struct output_buffer
*buffer
= &output
->buffer
;
406 const int initial_len
= 0x2000;
410 if (FAILED(hr
= get_code_page(output
->encoding
, &cp
)))
411 WARN("Failed to get code page for specified encoding.\n");
413 buffer
->data
= writeroutput_alloc(output
, initial_len
);
414 if (!buffer
->data
) return E_OUTOFMEMORY
;
416 memset(buffer
->data
, 0, 4);
417 buffer
->allocated
= initial_len
;
419 buffer
->codepage
= cp
;
424 static void free_output_buffer(xmlwriteroutput
*output
)
426 struct output_buffer
*buffer
= &output
->buffer
;
427 writeroutput_free(output
, buffer
->data
);
429 buffer
->allocated
= 0;
433 static HRESULT
grow_output_buffer(xmlwriteroutput
*output
, int length
)
435 struct output_buffer
*buffer
= &output
->buffer
;
436 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
437 if (buffer
->allocated
< buffer
->written
+ length
+ 4) {
438 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
439 char *ptr
= writeroutput_realloc(output
, buffer
->data
, grown_size
);
440 if (!ptr
) return E_OUTOFMEMORY
;
442 buffer
->allocated
= grown_size
;
448 static HRESULT
write_output_buffer(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
450 struct output_buffer
*buffer
= &output
->buffer
;
455 if (buffer
->codepage
== 1200) {
456 /* For UTF-16 encoding just copy. */
457 length
= len
== -1 ? lstrlenW(data
) : len
;
459 length
*= sizeof(WCHAR
);
461 hr
= grow_output_buffer(output
, length
);
462 if (FAILED(hr
)) return hr
;
463 ptr
= buffer
->data
+ buffer
->written
;
465 memcpy(ptr
, data
, length
);
466 buffer
->written
+= length
;
468 /* null termination */
473 length
= WideCharToMultiByte(buffer
->codepage
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
474 hr
= grow_output_buffer(output
, length
);
475 if (FAILED(hr
)) return hr
;
476 ptr
= buffer
->data
+ buffer
->written
;
477 length
= WideCharToMultiByte(buffer
->codepage
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
478 buffer
->written
+= len
== -1 ? length
-1 : length
;
480 output
->written
= length
!= 0;
485 static HRESULT
write_output_buffer_char(xmlwriteroutput
*output
, WCHAR ch
)
487 return write_output_buffer(output
, &ch
, 1);
490 static HRESULT
write_output_buffer_quoted(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
492 write_output_buffer_char(output
, '"');
493 if (!is_empty_string(data
))
494 write_output_buffer(output
, data
, len
);
495 write_output_buffer_char(output
, '"');
499 /* TODO: test if we need to validate char range */
500 static HRESULT
write_output_qname(xmlwriteroutput
*output
, const WCHAR
*prefix
, int prefix_len
,
501 const WCHAR
*local_name
, int local_len
)
503 assert(prefix_len
>= 0 && local_len
>= 0);
506 write_output_buffer(output
, prefix
, prefix_len
);
508 if (prefix_len
&& local_len
)
509 write_output_buffer_char(output
, ':');
511 write_output_buffer(output
, local_name
, local_len
);
516 static void writeroutput_release_stream(xmlwriteroutput
*writeroutput
)
518 if (writeroutput
->stream
) {
519 ISequentialStream_Release(writeroutput
->stream
);
520 writeroutput
->stream
= NULL
;
524 static inline HRESULT
writeroutput_query_for_stream(xmlwriteroutput
*writeroutput
)
528 writeroutput_release_stream(writeroutput
);
529 hr
= IUnknown_QueryInterface(writeroutput
->output
, &IID_IStream
, (void**)&writeroutput
->stream
);
531 hr
= IUnknown_QueryInterface(writeroutput
->output
, &IID_ISequentialStream
, (void**)&writeroutput
->stream
);
536 static HRESULT
writeroutput_flush_stream(xmlwriteroutput
*output
)
538 struct output_buffer
*buffer
;
539 ULONG written
, offset
= 0;
542 if (!output
|| !output
->stream
)
545 buffer
= &output
->buffer
;
547 /* It will loop forever until everything is written or an error occurred. */
550 hr
= ISequentialStream_Write(output
->stream
, buffer
->data
+ offset
, buffer
->written
, &written
);
552 WARN("write to stream failed (0x%08x)\n", hr
);
558 buffer
->written
-= written
;
559 } while (buffer
->written
> 0);
564 static HRESULT
write_encoding_bom(xmlwriter
*writer
)
566 if (!writer
->bom
|| writer
->bomwritten
) return S_OK
;
568 if (writer
->output
->encoding
== XmlEncoding_UTF16
) {
569 static const char utf16bom
[] = {0xff, 0xfe};
570 struct output_buffer
*buffer
= &writer
->output
->buffer
;
571 int len
= sizeof(utf16bom
);
574 hr
= grow_output_buffer(writer
->output
, len
);
575 if (FAILED(hr
)) return hr
;
576 memcpy(buffer
->data
+ buffer
->written
, utf16bom
, len
);
577 buffer
->written
+= len
;
580 writer
->bomwritten
= TRUE
;
584 static const WCHAR
*get_output_encoding_name(xmlwriteroutput
*output
)
586 if (output
->encoding_name
)
587 return output
->encoding_name
;
589 return get_encoding_name(output
->encoding
);
592 static HRESULT
write_xmldecl(xmlwriter
*writer
, XmlStandalone standalone
)
594 write_encoding_bom(writer
);
595 writer
->state
= XmlWriterState_DocStarted
;
596 if (writer
->omitxmldecl
) return S_OK
;
599 write_output_buffer(writer
->output
, L
"<?xml version=\"1.0\"", 19);
602 write_output_buffer(writer
->output
, L
" encoding=", 10);
603 write_output_buffer_quoted(writer
->output
, get_output_encoding_name(writer
->output
), -1);
606 if (standalone
== XmlStandalone_Omit
)
607 write_output_buffer(writer
->output
, L
"?>", 2);
610 write_output_buffer(writer
->output
, L
" standalone=\"", 13);
611 if (standalone
== XmlStandalone_Yes
)
612 write_output_buffer(writer
->output
, L
"yes\"?>", 6);
614 write_output_buffer(writer
->output
, L
"no\"?>", 5);
620 static void writer_output_ns(xmlwriter
*writer
, struct element
*element
)
624 LIST_FOR_EACH_ENTRY(ns
, &element
->ns
, struct ns
, entry
)
629 write_output_qname(writer
->output
, L
" xmlns", 6, ns
->prefix
, ns
->prefix_len
);
630 write_output_buffer_char(writer
->output
, '=');
631 write_output_buffer_quoted(writer
->output
, ns
->uri
, -1);
635 static HRESULT
writer_close_starttag(xmlwriter
*writer
)
639 if (!writer
->starttagopen
) return S_OK
;
641 writer_output_ns(writer
, LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
));
642 hr
= write_output_buffer_char(writer
->output
, '>');
643 writer
->starttagopen
= 0;
647 static void writer_inc_indent(xmlwriter
*writer
)
649 writer
->indent_level
++;
652 static void writer_dec_indent(xmlwriter
*writer
)
654 if (writer
->indent_level
)
655 writer
->indent_level
--;
658 static void write_node_indent(xmlwriter
*writer
)
660 unsigned int indent_level
= writer
->indent_level
;
662 if (!writer
->indent
|| writer
->textnode
)
664 writer
->textnode
= 0;
668 /* Do state check to prevent newline inserted after BOM. It is assumed that
669 state does not change between writing BOM and inserting indentation. */
670 if (writer
->output
->written
&& writer
->state
!= XmlWriterState_Ready
)
671 write_output_buffer(writer
->output
, L
"\r\n", 2);
672 while (indent_level
--)
673 write_output_buffer(writer
->output
, L
" ", 2);
675 writer
->textnode
= 0;
678 static HRESULT WINAPI
xmlwriter_QueryInterface(IXmlWriter
*iface
, REFIID riid
, void **ppvObject
)
680 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
682 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
684 if (IsEqualGUID(riid
, &IID_IXmlWriter
) ||
685 IsEqualGUID(riid
, &IID_IUnknown
))
691 FIXME("interface %s is not supported\n", debugstr_guid(riid
));
693 return E_NOINTERFACE
;
696 IXmlWriter_AddRef(iface
);
701 static ULONG WINAPI
xmlwriter_AddRef(IXmlWriter
*iface
)
703 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
704 ULONG ref
= InterlockedIncrement(&This
->ref
);
705 TRACE("(%p)->(%u)\n", This
, ref
);
709 static ULONG WINAPI
xmlwriter_Release(IXmlWriter
*iface
)
711 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
712 ULONG ref
= InterlockedDecrement(&This
->ref
);
714 TRACE("(%p)->(%u)\n", This
, ref
);
717 IMalloc
*imalloc
= This
->imalloc
;
719 writeroutput_flush_stream(This
->output
);
720 if (This
->output
) IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
722 writer_free_element_stack(This
);
724 writer_free(This
, This
);
725 if (imalloc
) IMalloc_Release(imalloc
);
731 /*** IXmlWriter methods ***/
732 static HRESULT WINAPI
xmlwriter_SetOutput(IXmlWriter
*iface
, IUnknown
*output
)
734 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
735 IXmlWriterOutput
*writeroutput
;
738 TRACE("(%p)->(%p)\n", This
, output
);
741 writeroutput_release_stream(This
->output
);
742 IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
744 This
->bomwritten
= 0;
746 This
->indent_level
= 0;
747 writer_free_element_stack(This
);
750 /* just reset current output */
752 This
->state
= XmlWriterState_Initial
;
756 /* now try IXmlWriterOutput, ISequentialStream, IStream */
757 hr
= IUnknown_QueryInterface(output
, &IID_IXmlWriterOutput
, (void**)&writeroutput
);
759 if (writeroutput
->lpVtbl
== &xmlwriteroutputvtbl
)
760 This
->output
= impl_from_IXmlWriterOutput(writeroutput
);
762 ERR("got external IXmlWriterOutput implementation: %p, vtbl=%p\n",
763 writeroutput
, writeroutput
->lpVtbl
);
764 IUnknown_Release(writeroutput
);
769 if (hr
!= S_OK
|| !writeroutput
) {
770 /* Create output for given stream. */
771 hr
= create_writer_output(output
, This
->imalloc
, XmlEncoding_UTF8
, NULL
, &This
->output
);
776 if (This
->output
->encoding
== XmlEncoding_Unknown
)
777 This
->state
= XmlWriterState_InvalidEncoding
;
779 This
->state
= XmlWriterState_Ready
;
780 return writeroutput_query_for_stream(This
->output
);
783 static HRESULT WINAPI
xmlwriter_GetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR
*value
)
785 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
787 TRACE("(%p)->(%s %p)\n", This
, debugstr_writer_prop(property
), value
);
789 if (!value
) return E_INVALIDARG
;
793 case XmlWriterProperty_Indent
:
794 *value
= This
->indent
;
796 case XmlWriterProperty_ByteOrderMark
:
799 case XmlWriterProperty_OmitXmlDeclaration
:
800 *value
= This
->omitxmldecl
;
802 case XmlWriterProperty_ConformanceLevel
:
803 *value
= This
->conformance
;
806 FIXME("Unimplemented property (%u)\n", property
);
813 static HRESULT WINAPI
xmlwriter_SetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR value
)
815 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
817 TRACE("(%p)->(%s %lu)\n", This
, debugstr_writer_prop(property
), value
);
821 case XmlWriterProperty_Indent
:
822 This
->indent
= !!value
;
824 case XmlWriterProperty_ByteOrderMark
:
827 case XmlWriterProperty_OmitXmlDeclaration
:
828 This
->omitxmldecl
= !!value
;
831 FIXME("Unimplemented property (%u)\n", property
);
838 static HRESULT WINAPI
xmlwriter_WriteAttributes(IXmlWriter
*iface
, IXmlReader
*pReader
,
839 BOOL fWriteDefaultAttributes
)
841 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
843 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
848 static void write_output_attribute(xmlwriter
*writer
, const WCHAR
*prefix
, int prefix_len
,
849 const WCHAR
*local
, int local_len
, const WCHAR
*value
)
851 write_output_buffer_char(writer
->output
, ' ');
852 write_output_qname(writer
->output
, prefix
, prefix_len
, local
, local_len
);
853 write_output_buffer_char(writer
->output
, '=');
854 write_output_buffer_quoted(writer
->output
, value
, -1);
857 static BOOL
is_valid_xml_space_value(const WCHAR
*value
)
859 return value
&& (!wcscmp(value
, L
"preserve") || !wcscmp(value
, L
"default"));
862 static HRESULT WINAPI
xmlwriter_WriteAttributeString(IXmlWriter
*iface
, LPCWSTR prefix
,
863 LPCWSTR local
, LPCWSTR uri
, LPCWSTR value
)
865 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
866 BOOL is_xmlns_prefix
, is_xmlns_local
;
867 int prefix_len
, local_len
;
871 TRACE("%p %s %s %s %s\n", This
, debugstr_w(prefix
), debugstr_w(local
), debugstr_w(uri
), debugstr_w(value
));
875 case XmlWriterState_Initial
:
877 case XmlWriterState_Ready
:
878 case XmlWriterState_DocClosed
:
879 This
->state
= XmlWriterState_DocClosed
;
880 return WR_E_INVALIDACTION
;
881 case XmlWriterState_InvalidEncoding
:
882 return MX_E_ENCODING
;
888 is_xmlns_prefix
= prefix
&& !wcscmp(prefix
, L
"xmlns");
889 if (is_xmlns_prefix
&& is_empty_string(uri
) && is_empty_string(local
))
890 return WR_E_NSPREFIXDECLARED
;
895 /* Validate prefix and local name */
896 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
899 if (FAILED(hr
= is_valid_ncname(local
, &local_len
)))
902 is_xmlns_local
= !wcscmp(local
, L
"xmlns");
904 /* Trivial case, no prefix. */
905 if (prefix_len
== 0 && is_empty_string(uri
))
907 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
911 /* Predefined "xml" prefix. */
912 if (prefix_len
&& !wcscmp(prefix
, L
"xml"))
914 /* Valid "space" value is enforced. */
915 if (!wcscmp(local
, L
"space") && !is_valid_xml_space_value(value
))
916 return WR_E_INVALIDXMLSPACE
;
918 /* Redefinition is not allowed. */
919 if (!is_empty_string(uri
))
920 return WR_E_XMLPREFIXDECLARATION
;
922 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
927 if (is_xmlns_prefix
|| (prefix_len
== 0 && uri
&& !wcscmp(uri
, xmlnsuriW
)))
929 if (prefix_len
&& !is_empty_string(uri
))
930 return WR_E_XMLNSPREFIXDECLARATION
;
932 /* Look for exact match defined in current element, and write it out. */
933 if (!(ns
= writer_find_ns_current(This
, prefix
, value
)))
934 ns
= writer_push_ns(This
, local
, local_len
, value
);
937 write_output_attribute(This
, L
"xmlns", 5, local
, local_len
, value
);
942 /* Ignore prefix is URI wasn't specified. */
943 if (is_xmlns_local
&& is_empty_string(uri
))
945 write_output_attribute(This
, NULL
, 0, L
"xmlns", 5, value
);
949 if (!(ns
= writer_find_ns(This
, prefix
, uri
)))
951 if (is_empty_string(prefix
) && !is_empty_string(uri
))
953 FIXME("Prefix autogeneration is not implemented.\n");
956 if (!is_empty_string(uri
))
957 ns
= writer_push_ns(This
, prefix
, prefix_len
, uri
);
961 write_output_attribute(This
, ns
->prefix
, ns
->prefix_len
, local
, local_len
, value
);
963 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
968 static void write_cdata_section(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
970 write_output_buffer(output
, L
"<![CDATA[", 9);
972 write_output_buffer(output
, data
, len
);
973 write_output_buffer(output
, L
"]]>", 3);
976 static HRESULT WINAPI
xmlwriter_WriteCData(IXmlWriter
*iface
, LPCWSTR data
)
978 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
981 TRACE("%p %s\n", This
, debugstr_w(data
));
985 case XmlWriterState_Initial
:
987 case XmlWriterState_ElemStarted
:
988 writer_close_starttag(This
);
990 case XmlWriterState_Ready
:
991 case XmlWriterState_DocClosed
:
992 This
->state
= XmlWriterState_DocClosed
;
993 return WR_E_INVALIDACTION
;
994 case XmlWriterState_InvalidEncoding
:
995 return MX_E_ENCODING
;
1000 len
= data
? lstrlenW(data
) : 0;
1002 write_node_indent(This
);
1004 write_cdata_section(This
->output
, NULL
, 0);
1009 const WCHAR
*str
= wcsstr(data
, L
"]]>");
1012 write_cdata_section(This
->output
, data
, str
- data
);
1017 write_cdata_section(This
->output
, data
, len
);
1026 static HRESULT WINAPI
xmlwriter_WriteCharEntity(IXmlWriter
*iface
, WCHAR ch
)
1028 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1031 TRACE("%p %#x\n", This
, ch
);
1033 switch (This
->state
)
1035 case XmlWriterState_Initial
:
1036 return E_UNEXPECTED
;
1037 case XmlWriterState_InvalidEncoding
:
1038 return MX_E_ENCODING
;
1039 case XmlWriterState_ElemStarted
:
1040 writer_close_starttag(This
);
1042 case XmlWriterState_DocClosed
:
1043 return WR_E_INVALIDACTION
;
1048 swprintf(bufW
, ARRAY_SIZE(bufW
), L
"&#x%x;", ch
);
1049 write_output_buffer(This
->output
, bufW
, -1);
1054 static HRESULT WINAPI
xmlwriter_WriteChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
1056 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1058 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
1060 switch (This
->state
)
1062 case XmlWriterState_Initial
:
1063 return E_UNEXPECTED
;
1064 case XmlWriterState_InvalidEncoding
:
1065 return MX_E_ENCODING
;
1066 case XmlWriterState_DocClosed
:
1067 return WR_E_INVALIDACTION
;
1076 static HRESULT WINAPI
xmlwriter_WriteComment(IXmlWriter
*iface
, LPCWSTR comment
)
1078 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1080 TRACE("%p %s\n", This
, debugstr_w(comment
));
1082 switch (This
->state
)
1084 case XmlWriterState_Initial
:
1085 return E_UNEXPECTED
;
1086 case XmlWriterState_InvalidEncoding
:
1087 return MX_E_ENCODING
;
1088 case XmlWriterState_ElemStarted
:
1089 writer_close_starttag(This
);
1091 case XmlWriterState_DocClosed
:
1092 return WR_E_INVALIDACTION
;
1097 write_node_indent(This
);
1098 write_output_buffer(This
->output
, L
"<!--", 4);
1100 int len
= lstrlenW(comment
), i
;
1102 /* Make sure there's no two hyphen sequences in a string, space is used as a separator to produce compliant
1105 for (i
= 0; i
< len
; i
++) {
1106 write_output_buffer(This
->output
, comment
+ i
, 1);
1107 if (comment
[i
] == '-' && (i
+ 1 < len
) && comment
[i
+1] == '-')
1108 write_output_buffer_char(This
->output
, ' ');
1112 write_output_buffer(This
->output
, comment
, len
);
1114 if (len
&& comment
[len
-1] == '-')
1115 write_output_buffer_char(This
->output
, ' ');
1117 write_output_buffer(This
->output
, L
"-->", 3);
1122 static HRESULT WINAPI
xmlwriter_WriteDocType(IXmlWriter
*iface
, LPCWSTR name
, LPCWSTR pubid
,
1123 LPCWSTR sysid
, LPCWSTR subset
)
1125 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1126 unsigned int name_len
, pubid_len
;
1129 TRACE("(%p)->(%s %s %s %s)\n", This
, wine_dbgstr_w(name
), wine_dbgstr_w(pubid
), wine_dbgstr_w(sysid
),
1130 wine_dbgstr_w(subset
));
1132 switch (This
->state
)
1134 case XmlWriterState_Initial
:
1135 return E_UNEXPECTED
;
1136 case XmlWriterState_InvalidEncoding
:
1137 return MX_E_ENCODING
;
1138 case XmlWriterState_Content
:
1139 case XmlWriterState_DocClosed
:
1140 return WR_E_INVALIDACTION
;
1145 if (is_empty_string(name
))
1146 return E_INVALIDARG
;
1148 if (FAILED(hr
= is_valid_name(name
, &name_len
)))
1151 if (FAILED(hr
= is_valid_pubid(pubid
, &pubid_len
)))
1154 write_output_buffer(This
->output
, L
"<!DOCTYPE ", 10);
1155 write_output_buffer(This
->output
, name
, name_len
);
1159 write_output_buffer(This
->output
, L
" PUBLIC ", 8);
1160 write_output_buffer_quoted(This
->output
, pubid
, pubid_len
);
1161 write_output_buffer_char(This
->output
, ' ');
1162 write_output_buffer_quoted(This
->output
, sysid
, -1);
1166 write_output_buffer(This
->output
, L
" SYSTEM ", 8);
1167 write_output_buffer_quoted(This
->output
, sysid
, -1);
1172 write_output_buffer_char(This
->output
, ' ');
1173 write_output_buffer_char(This
->output
, '[');
1174 write_output_buffer(This
->output
, subset
, -1);
1175 write_output_buffer_char(This
->output
, ']');
1177 write_output_buffer_char(This
->output
, '>');
1179 This
->state
= XmlWriterState_Content
;
1184 static HRESULT WINAPI
xmlwriter_WriteElementString(IXmlWriter
*iface
, LPCWSTR prefix
,
1185 LPCWSTR local_name
, LPCWSTR uri
, LPCWSTR value
)
1187 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1188 int prefix_len
, local_len
;
1192 TRACE("(%p)->(%s %s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
),
1193 wine_dbgstr_w(uri
), wine_dbgstr_w(value
));
1195 switch (This
->state
)
1197 case XmlWriterState_Initial
:
1198 return E_UNEXPECTED
;
1199 case XmlWriterState_InvalidEncoding
:
1200 return MX_E_ENCODING
;
1201 case XmlWriterState_ElemStarted
:
1202 writer_close_starttag(This
);
1204 case XmlWriterState_DocClosed
:
1205 return WR_E_INVALIDACTION
;
1211 return E_INVALIDARG
;
1213 /* Validate prefix and local name */
1214 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
1217 if (FAILED(hr
= is_valid_ncname(local_name
, &local_len
)))
1220 ns
= writer_find_ns(This
, prefix
, uri
);
1221 if (!ns
&& !is_empty_string(prefix
) && is_empty_string(uri
))
1222 return WR_E_NSPREFIXWITHEMPTYNSURI
;
1224 if (uri
&& !wcscmp(uri
, xmlnsuriW
))
1227 return WR_E_XMLNSPREFIXDECLARATION
;
1229 if (!is_empty_string(prefix
))
1230 return WR_E_XMLNSURIDECLARATION
;
1233 write_encoding_bom(This
);
1234 write_node_indent(This
);
1236 write_output_buffer_char(This
->output
, '<');
1238 write_output_qname(This
->output
, ns
->prefix
, ns
->prefix_len
, local_name
, local_len
);
1240 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1242 if (!ns
&& (prefix_len
|| !is_empty_string(uri
)))
1244 write_output_qname(This
->output
, L
" xmlns", 6, prefix
, prefix_len
);
1245 write_output_buffer_char(This
->output
, '=');
1246 write_output_buffer_quoted(This
->output
, uri
, -1);
1251 write_output_buffer_char(This
->output
, '>');
1252 write_output_buffer(This
->output
, value
, -1);
1253 write_output_buffer(This
->output
, L
"</", 2);
1254 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1255 write_output_buffer_char(This
->output
, '>');
1258 write_output_buffer(This
->output
, L
" />", 3);
1260 This
->state
= XmlWriterState_Content
;
1265 static HRESULT WINAPI
xmlwriter_WriteEndDocument(IXmlWriter
*iface
)
1267 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1269 TRACE("%p\n", This
);
1271 switch (This
->state
)
1273 case XmlWriterState_Initial
:
1274 return E_UNEXPECTED
;
1275 case XmlWriterState_Ready
:
1276 case XmlWriterState_DocClosed
:
1277 This
->state
= XmlWriterState_DocClosed
;
1278 return WR_E_INVALIDACTION
;
1279 case XmlWriterState_InvalidEncoding
:
1280 return MX_E_ENCODING
;
1285 /* empty element stack */
1286 while (IXmlWriter_WriteEndElement(iface
) == S_OK
)
1289 This
->state
= XmlWriterState_DocClosed
;
1293 static HRESULT WINAPI
xmlwriter_WriteEndElement(IXmlWriter
*iface
)
1295 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1296 struct element
*element
;
1298 TRACE("%p\n", This
);
1300 switch (This
->state
)
1302 case XmlWriterState_Initial
:
1303 return E_UNEXPECTED
;
1304 case XmlWriterState_Ready
:
1305 case XmlWriterState_DocClosed
:
1306 This
->state
= XmlWriterState_DocClosed
;
1307 return WR_E_INVALIDACTION
;
1308 case XmlWriterState_InvalidEncoding
:
1309 return MX_E_ENCODING
;
1314 element
= pop_element(This
);
1316 return WR_E_INVALIDACTION
;
1318 writer_dec_indent(This
);
1320 if (This
->starttagopen
)
1322 writer_output_ns(This
, element
);
1323 write_output_buffer(This
->output
, L
" />", 3);
1324 This
->starttagopen
= 0;
1328 /* Write full end tag. */
1329 write_node_indent(This
);
1330 write_output_buffer(This
->output
, L
"</", 2);
1331 write_output_buffer(This
->output
, element
->qname
, element
->len
);
1332 write_output_buffer_char(This
->output
, '>');
1334 writer_free_element(This
, element
);
1339 static HRESULT WINAPI
xmlwriter_WriteEntityRef(IXmlWriter
*iface
, LPCWSTR pwszName
)
1341 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1343 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
1345 switch (This
->state
)
1347 case XmlWriterState_Initial
:
1348 return E_UNEXPECTED
;
1349 case XmlWriterState_InvalidEncoding
:
1350 return MX_E_ENCODING
;
1351 case XmlWriterState_DocClosed
:
1352 return WR_E_INVALIDACTION
;
1360 static HRESULT WINAPI
xmlwriter_WriteFullEndElement(IXmlWriter
*iface
)
1362 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1363 struct element
*element
;
1365 TRACE("%p\n", This
);
1367 switch (This
->state
)
1369 case XmlWriterState_Initial
:
1370 return E_UNEXPECTED
;
1371 case XmlWriterState_Ready
:
1372 case XmlWriterState_DocClosed
:
1373 This
->state
= XmlWriterState_DocClosed
;
1374 return WR_E_INVALIDACTION
;
1375 case XmlWriterState_InvalidEncoding
:
1376 return MX_E_ENCODING
;
1377 case XmlWriterState_ElemStarted
:
1378 writer_close_starttag(This
);
1384 element
= pop_element(This
);
1386 return WR_E_INVALIDACTION
;
1388 writer_dec_indent(This
);
1390 /* don't force full end tag to the next line */
1391 if (This
->state
== XmlWriterState_ElemStarted
)
1393 This
->state
= XmlWriterState_Content
;
1397 write_node_indent(This
);
1399 /* write full end tag */
1400 write_output_buffer(This
->output
, L
"</", 2);
1401 write_output_buffer(This
->output
, element
->qname
, element
->len
);
1402 write_output_buffer_char(This
->output
, '>');
1404 writer_free_element(This
, element
);
1409 static HRESULT WINAPI
xmlwriter_WriteName(IXmlWriter
*iface
, LPCWSTR pwszName
)
1411 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1413 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
1415 switch (This
->state
)
1417 case XmlWriterState_Initial
:
1418 return E_UNEXPECTED
;
1419 case XmlWriterState_Ready
:
1420 case XmlWriterState_DocClosed
:
1421 This
->state
= XmlWriterState_DocClosed
;
1422 return WR_E_INVALIDACTION
;
1423 case XmlWriterState_InvalidEncoding
:
1424 return MX_E_ENCODING
;
1432 static HRESULT WINAPI
xmlwriter_WriteNmToken(IXmlWriter
*iface
, LPCWSTR pwszNmToken
)
1434 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1436 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszNmToken
));
1438 switch (This
->state
)
1440 case XmlWriterState_Initial
:
1441 return E_UNEXPECTED
;
1442 case XmlWriterState_Ready
:
1443 case XmlWriterState_DocClosed
:
1444 This
->state
= XmlWriterState_DocClosed
;
1445 return WR_E_INVALIDACTION
;
1446 case XmlWriterState_InvalidEncoding
:
1447 return MX_E_ENCODING
;
1455 static HRESULT WINAPI
xmlwriter_WriteNode(IXmlWriter
*iface
, IXmlReader
*pReader
,
1456 BOOL fWriteDefaultAttributes
)
1458 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1460 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
1465 static HRESULT WINAPI
xmlwriter_WriteNodeShallow(IXmlWriter
*iface
, IXmlReader
*pReader
,
1466 BOOL fWriteDefaultAttributes
)
1468 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1470 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
1475 static HRESULT WINAPI
xmlwriter_WriteProcessingInstruction(IXmlWriter
*iface
, LPCWSTR name
,
1478 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1480 TRACE("(%p)->(%s %s)\n", This
, wine_dbgstr_w(name
), wine_dbgstr_w(text
));
1482 switch (This
->state
)
1484 case XmlWriterState_Initial
:
1485 return E_UNEXPECTED
;
1486 case XmlWriterState_InvalidEncoding
:
1487 return MX_E_ENCODING
;
1488 case XmlWriterState_DocStarted
:
1489 if (!wcscmp(name
, L
"xml"))
1490 return WR_E_INVALIDACTION
;
1492 case XmlWriterState_ElemStarted
:
1493 case XmlWriterState_DocClosed
:
1494 return WR_E_INVALIDACTION
;
1499 write_encoding_bom(This
);
1500 write_node_indent(This
);
1501 write_output_buffer(This
->output
, L
"<?", 2);
1502 write_output_buffer(This
->output
, name
, -1);
1503 write_output_buffer_char(This
->output
, ' ');
1504 write_output_buffer(This
->output
, text
, -1);
1505 write_output_buffer(This
->output
, L
"?>", 2);
1507 if (!wcscmp(name
, L
"xml"))
1508 This
->state
= XmlWriterState_PIDocStarted
;
1513 static HRESULT WINAPI
xmlwriter_WriteQualifiedName(IXmlWriter
*iface
, LPCWSTR pwszLocalName
,
1514 LPCWSTR pwszNamespaceUri
)
1516 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1518 FIXME("%p %s %s\n", This
, wine_dbgstr_w(pwszLocalName
), wine_dbgstr_w(pwszNamespaceUri
));
1520 switch (This
->state
)
1522 case XmlWriterState_Initial
:
1523 return E_UNEXPECTED
;
1524 case XmlWriterState_InvalidEncoding
:
1525 return MX_E_ENCODING
;
1526 case XmlWriterState_DocClosed
:
1527 return WR_E_INVALIDACTION
;
1535 static HRESULT WINAPI
xmlwriter_WriteRaw(IXmlWriter
*iface
, LPCWSTR data
)
1537 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1539 TRACE("%p %s\n", This
, debugstr_w(data
));
1544 switch (This
->state
)
1546 case XmlWriterState_Initial
:
1547 return E_UNEXPECTED
;
1548 case XmlWriterState_Ready
:
1549 write_xmldecl(This
, XmlStandalone_Omit
);
1551 case XmlWriterState_DocStarted
:
1552 case XmlWriterState_PIDocStarted
:
1554 case XmlWriterState_InvalidEncoding
:
1555 return MX_E_ENCODING
;
1557 This
->state
= XmlWriterState_DocClosed
;
1558 return WR_E_INVALIDACTION
;
1561 write_output_buffer(This
->output
, data
, -1);
1565 static HRESULT WINAPI
xmlwriter_WriteRawChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
1567 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1569 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
1571 switch (This
->state
)
1573 case XmlWriterState_Initial
:
1574 return E_UNEXPECTED
;
1575 case XmlWriterState_InvalidEncoding
:
1576 return MX_E_ENCODING
;
1577 case XmlWriterState_DocClosed
:
1578 return WR_E_INVALIDACTION
;
1586 static HRESULT WINAPI
xmlwriter_WriteStartDocument(IXmlWriter
*iface
, XmlStandalone standalone
)
1588 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1590 TRACE("(%p)->(%d)\n", This
, standalone
);
1592 switch (This
->state
)
1594 case XmlWriterState_Initial
:
1595 return E_UNEXPECTED
;
1596 case XmlWriterState_PIDocStarted
:
1597 This
->state
= XmlWriterState_DocStarted
;
1599 case XmlWriterState_Ready
:
1601 case XmlWriterState_InvalidEncoding
:
1602 return MX_E_ENCODING
;
1604 This
->state
= XmlWriterState_DocClosed
;
1605 return WR_E_INVALIDACTION
;
1608 return write_xmldecl(This
, standalone
);
1611 static HRESULT WINAPI
xmlwriter_WriteStartElement(IXmlWriter
*iface
, LPCWSTR prefix
, LPCWSTR local_name
, LPCWSTR uri
)
1613 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1614 int prefix_len
, local_len
;
1615 struct element
*element
;
1619 TRACE("(%p)->(%s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
), wine_dbgstr_w(uri
));
1622 return E_INVALIDARG
;
1624 switch (This
->state
)
1626 case XmlWriterState_Initial
:
1627 return E_UNEXPECTED
;
1628 case XmlWriterState_InvalidEncoding
:
1629 return MX_E_ENCODING
;
1630 case XmlWriterState_DocClosed
:
1631 return WR_E_INVALIDACTION
;
1632 case XmlWriterState_ElemStarted
:
1633 writer_close_starttag(This
);
1639 /* Validate prefix and local name */
1640 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
1643 if (FAILED(hr
= is_valid_ncname(local_name
, &local_len
)))
1646 if (uri
&& !wcscmp(uri
, xmlnsuriW
))
1649 return WR_E_XMLNSPREFIXDECLARATION
;
1651 if (!is_empty_string(prefix
))
1652 return WR_E_XMLNSURIDECLARATION
;
1655 ns
= writer_find_ns(This
, prefix
, uri
);
1657 element
= alloc_element(This
, prefix
, local_name
);
1659 return E_OUTOFMEMORY
;
1661 write_encoding_bom(This
);
1662 write_node_indent(This
);
1664 This
->state
= XmlWriterState_ElemStarted
;
1665 This
->starttagopen
= 1;
1667 writer_push_element(This
, element
);
1670 writer_push_ns(This
, prefix
, prefix_len
, uri
);
1672 write_output_buffer_char(This
->output
, '<');
1674 write_output_qname(This
->output
, ns
->prefix
, ns
->prefix_len
, local_name
, local_len
);
1676 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1677 writer_inc_indent(This
);
1682 static void write_escaped_string(xmlwriter
*writer
, const WCHAR
*string
)
1689 write_output_buffer(writer
->output
, L
"<", 4);
1692 write_output_buffer(writer
->output
, L
"&", 5);
1695 write_output_buffer(writer
->output
, L
">", 4);
1698 write_output_buffer(writer
->output
, string
, 1);
1705 static HRESULT WINAPI
xmlwriter_WriteString(IXmlWriter
*iface
, const WCHAR
*string
)
1707 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1709 TRACE("%p %s\n", This
, debugstr_w(string
));
1714 switch (This
->state
)
1716 case XmlWriterState_Initial
:
1717 return E_UNEXPECTED
;
1718 case XmlWriterState_ElemStarted
:
1719 writer_close_starttag(This
);
1721 case XmlWriterState_Ready
:
1722 case XmlWriterState_DocClosed
:
1723 This
->state
= XmlWriterState_DocClosed
;
1724 return WR_E_INVALIDACTION
;
1725 case XmlWriterState_InvalidEncoding
:
1726 return MX_E_ENCODING
;
1732 write_escaped_string(This
, string
);
1736 static HRESULT WINAPI
xmlwriter_WriteSurrogateCharEntity(IXmlWriter
*iface
, WCHAR wchLow
, WCHAR wchHigh
)
1738 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1740 FIXME("%p %d %d\n", This
, wchLow
, wchHigh
);
1745 static HRESULT WINAPI
xmlwriter_WriteWhitespace(IXmlWriter
*iface
, LPCWSTR pwszWhitespace
)
1747 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1749 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszWhitespace
));
1754 static HRESULT WINAPI
xmlwriter_Flush(IXmlWriter
*iface
)
1756 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1758 TRACE("%p\n", This
);
1760 return writeroutput_flush_stream(This
->output
);
1763 static const struct IXmlWriterVtbl xmlwriter_vtbl
=
1765 xmlwriter_QueryInterface
,
1768 xmlwriter_SetOutput
,
1769 xmlwriter_GetProperty
,
1770 xmlwriter_SetProperty
,
1771 xmlwriter_WriteAttributes
,
1772 xmlwriter_WriteAttributeString
,
1773 xmlwriter_WriteCData
,
1774 xmlwriter_WriteCharEntity
,
1775 xmlwriter_WriteChars
,
1776 xmlwriter_WriteComment
,
1777 xmlwriter_WriteDocType
,
1778 xmlwriter_WriteElementString
,
1779 xmlwriter_WriteEndDocument
,
1780 xmlwriter_WriteEndElement
,
1781 xmlwriter_WriteEntityRef
,
1782 xmlwriter_WriteFullEndElement
,
1783 xmlwriter_WriteName
,
1784 xmlwriter_WriteNmToken
,
1785 xmlwriter_WriteNode
,
1786 xmlwriter_WriteNodeShallow
,
1787 xmlwriter_WriteProcessingInstruction
,
1788 xmlwriter_WriteQualifiedName
,
1790 xmlwriter_WriteRawChars
,
1791 xmlwriter_WriteStartDocument
,
1792 xmlwriter_WriteStartElement
,
1793 xmlwriter_WriteString
,
1794 xmlwriter_WriteSurrogateCharEntity
,
1795 xmlwriter_WriteWhitespace
,
1799 /** IXmlWriterOutput **/
1800 static HRESULT WINAPI
xmlwriteroutput_QueryInterface(IXmlWriterOutput
*iface
, REFIID riid
, void** ppvObject
)
1802 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1804 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1806 if (IsEqualGUID(riid
, &IID_IXmlWriterOutput
) ||
1807 IsEqualGUID(riid
, &IID_IUnknown
))
1813 WARN("interface %s not implemented\n", debugstr_guid(riid
));
1815 return E_NOINTERFACE
;
1818 IUnknown_AddRef(iface
);
1823 static ULONG WINAPI
xmlwriteroutput_AddRef(IXmlWriterOutput
*iface
)
1825 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1826 ULONG ref
= InterlockedIncrement(&This
->ref
);
1827 TRACE("(%p)->(%d)\n", This
, ref
);
1831 static ULONG WINAPI
xmlwriteroutput_Release(IXmlWriterOutput
*iface
)
1833 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1834 LONG ref
= InterlockedDecrement(&This
->ref
);
1836 TRACE("(%p)->(%d)\n", This
, ref
);
1840 IMalloc
*imalloc
= This
->imalloc
;
1841 if (This
->output
) IUnknown_Release(This
->output
);
1842 if (This
->stream
) ISequentialStream_Release(This
->stream
);
1843 free_output_buffer(This
);
1844 writeroutput_free(This
, This
->encoding_name
);
1845 writeroutput_free(This
, This
);
1846 if (imalloc
) IMalloc_Release(imalloc
);
1852 static const struct IUnknownVtbl xmlwriteroutputvtbl
=
1854 xmlwriteroutput_QueryInterface
,
1855 xmlwriteroutput_AddRef
,
1856 xmlwriteroutput_Release
1859 HRESULT WINAPI
CreateXmlWriter(REFIID riid
, void **obj
, IMalloc
*imalloc
)
1864 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
1867 writer
= IMalloc_Alloc(imalloc
, sizeof(*writer
));
1869 writer
= heap_alloc(sizeof(*writer
));
1871 return E_OUTOFMEMORY
;
1873 memset(writer
, 0, sizeof(*writer
));
1875 writer
->IXmlWriter_iface
.lpVtbl
= &xmlwriter_vtbl
;
1877 writer
->imalloc
= imalloc
;
1878 if (imalloc
) IMalloc_AddRef(imalloc
);
1880 writer
->conformance
= XmlConformanceLevel_Document
;
1881 writer
->state
= XmlWriterState_Initial
;
1882 list_init(&writer
->elements
);
1884 hr
= IXmlWriter_QueryInterface(&writer
->IXmlWriter_iface
, riid
, obj
);
1885 IXmlWriter_Release(&writer
->IXmlWriter_iface
);
1887 TRACE("returning iface %p, hr %#x\n", *obj
, hr
);
1892 static HRESULT
create_writer_output(IUnknown
*stream
, IMalloc
*imalloc
, xml_encoding encoding
,
1893 const WCHAR
*encoding_name
, xmlwriteroutput
**out
)
1895 xmlwriteroutput
*writeroutput
;
1901 writeroutput
= IMalloc_Alloc(imalloc
, sizeof(*writeroutput
));
1903 writeroutput
= heap_alloc(sizeof(*writeroutput
));
1905 return E_OUTOFMEMORY
;
1907 writeroutput
->IXmlWriterOutput_iface
.lpVtbl
= &xmlwriteroutputvtbl
;
1908 writeroutput
->ref
= 1;
1909 writeroutput
->imalloc
= imalloc
;
1911 IMalloc_AddRef(imalloc
);
1912 writeroutput
->encoding
= encoding
;
1913 writeroutput
->stream
= NULL
;
1914 hr
= init_output_buffer(writeroutput
);
1916 IUnknown_Release(&writeroutput
->IXmlWriterOutput_iface
);
1920 if (encoding_name
) {
1921 unsigned int size
= (lstrlenW(encoding_name
) + 1) * sizeof(WCHAR
);
1922 writeroutput
->encoding_name
= writeroutput_alloc(writeroutput
, size
);
1923 memcpy(writeroutput
->encoding_name
, encoding_name
, size
);
1926 writeroutput
->encoding_name
= NULL
;
1927 writeroutput
->written
= 0;
1929 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&writeroutput
->output
);
1931 *out
= writeroutput
;
1933 TRACE("Created writer output %p\n", *out
);
1938 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingName(IUnknown
*stream
, IMalloc
*imalloc
, const WCHAR
*encoding
,
1939 IXmlWriterOutput
**out
)
1941 xmlwriteroutput
*output
;
1942 xml_encoding xml_enc
;
1945 TRACE("%p %p %s %p\n", stream
, imalloc
, debugstr_w(encoding
), out
);
1947 if (!stream
|| !out
)
1948 return E_INVALIDARG
;
1952 xml_enc
= encoding
? parse_encoding_name(encoding
, -1) : XmlEncoding_UTF8
;
1953 if (SUCCEEDED(hr
= create_writer_output(stream
, imalloc
, xml_enc
, encoding
, &output
)))
1954 *out
= &output
->IXmlWriterOutput_iface
;
1959 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingCodePage(IUnknown
*stream
, IMalloc
*imalloc
, UINT codepage
,
1960 IXmlWriterOutput
**out
)
1962 xmlwriteroutput
*output
;
1963 xml_encoding xml_enc
;
1966 TRACE("%p %p %u %p\n", stream
, imalloc
, codepage
, out
);
1968 if (!stream
|| !out
)
1969 return E_INVALIDARG
;
1973 xml_enc
= get_encoding_from_codepage(codepage
);
1974 if (SUCCEEDED(hr
= create_writer_output(stream
, imalloc
, xml_enc
, NULL
, &output
)))
1975 *out
= &output
->IXmlWriterOutput_iface
;