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 %#lx.\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
*writer
= impl_from_IXmlWriter(iface
);
704 ULONG ref
= InterlockedIncrement(&writer
->ref
);
705 TRACE("%p, refcount %lu.\n", iface
, ref
);
709 static ULONG WINAPI
xmlwriter_Release(IXmlWriter
*iface
)
711 xmlwriter
*writer
= impl_from_IXmlWriter(iface
);
712 ULONG ref
= InterlockedDecrement(&writer
->ref
);
714 TRACE("%p, refcount %lu.\n", iface
, ref
);
718 IMalloc
*imalloc
= writer
->imalloc
;
720 writeroutput_flush_stream(writer
->output
);
722 IUnknown_Release(&writer
->output
->IXmlWriterOutput_iface
);
724 writer_free_element_stack(writer
);
726 writer_free(writer
, writer
);
727 if (imalloc
) IMalloc_Release(imalloc
);
733 /*** IXmlWriter methods ***/
734 static HRESULT WINAPI
xmlwriter_SetOutput(IXmlWriter
*iface
, IUnknown
*output
)
736 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
737 IXmlWriterOutput
*writeroutput
;
740 TRACE("(%p)->(%p)\n", This
, output
);
743 writeroutput_release_stream(This
->output
);
744 IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
746 This
->bomwritten
= 0;
748 This
->indent_level
= 0;
749 writer_free_element_stack(This
);
752 /* just reset current output */
754 This
->state
= XmlWriterState_Initial
;
758 /* now try IXmlWriterOutput, ISequentialStream, IStream */
759 hr
= IUnknown_QueryInterface(output
, &IID_IXmlWriterOutput
, (void**)&writeroutput
);
761 if (writeroutput
->lpVtbl
== &xmlwriteroutputvtbl
)
762 This
->output
= impl_from_IXmlWriterOutput(writeroutput
);
764 ERR("got external IXmlWriterOutput implementation: %p, vtbl=%p\n",
765 writeroutput
, writeroutput
->lpVtbl
);
766 IUnknown_Release(writeroutput
);
771 if (hr
!= S_OK
|| !writeroutput
) {
772 /* Create output for given stream. */
773 hr
= create_writer_output(output
, This
->imalloc
, XmlEncoding_UTF8
, NULL
, &This
->output
);
778 if (This
->output
->encoding
== XmlEncoding_Unknown
)
779 This
->state
= XmlWriterState_InvalidEncoding
;
781 This
->state
= XmlWriterState_Ready
;
782 return writeroutput_query_for_stream(This
->output
);
785 static HRESULT WINAPI
xmlwriter_GetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR
*value
)
787 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
789 TRACE("(%p)->(%s %p)\n", This
, debugstr_writer_prop(property
), value
);
791 if (!value
) return E_INVALIDARG
;
795 case XmlWriterProperty_Indent
:
796 *value
= This
->indent
;
798 case XmlWriterProperty_ByteOrderMark
:
801 case XmlWriterProperty_OmitXmlDeclaration
:
802 *value
= This
->omitxmldecl
;
804 case XmlWriterProperty_ConformanceLevel
:
805 *value
= This
->conformance
;
808 FIXME("Unimplemented property (%u)\n", property
);
815 static HRESULT WINAPI
xmlwriter_SetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR value
)
817 xmlwriter
*writer
= impl_from_IXmlWriter(iface
);
819 TRACE("%p, %s, %Id.\n", iface
, debugstr_writer_prop(property
), value
);
823 case XmlWriterProperty_Indent
:
824 writer
->indent
= !!value
;
826 case XmlWriterProperty_ByteOrderMark
:
827 writer
->bom
= !!value
;
829 case XmlWriterProperty_OmitXmlDeclaration
:
830 writer
->omitxmldecl
= !!value
;
833 FIXME("Unimplemented property (%u)\n", property
);
840 static HRESULT WINAPI
xmlwriter_WriteAttributes(IXmlWriter
*iface
, IXmlReader
*pReader
,
841 BOOL fWriteDefaultAttributes
)
843 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
845 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
850 static void write_output_attribute(xmlwriter
*writer
, const WCHAR
*prefix
, int prefix_len
,
851 const WCHAR
*local
, int local_len
, const WCHAR
*value
)
853 write_output_buffer_char(writer
->output
, ' ');
854 write_output_qname(writer
->output
, prefix
, prefix_len
, local
, local_len
);
855 write_output_buffer_char(writer
->output
, '=');
856 write_output_buffer_quoted(writer
->output
, value
, -1);
859 static BOOL
is_valid_xml_space_value(const WCHAR
*value
)
861 return value
&& (!wcscmp(value
, L
"preserve") || !wcscmp(value
, L
"default"));
864 static HRESULT WINAPI
xmlwriter_WriteAttributeString(IXmlWriter
*iface
, LPCWSTR prefix
,
865 LPCWSTR local
, LPCWSTR uri
, LPCWSTR value
)
867 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
868 BOOL is_xmlns_prefix
, is_xmlns_local
;
869 int prefix_len
, local_len
;
873 TRACE("%p %s %s %s %s\n", This
, debugstr_w(prefix
), debugstr_w(local
), debugstr_w(uri
), debugstr_w(value
));
877 case XmlWriterState_Initial
:
879 case XmlWriterState_Ready
:
880 case XmlWriterState_DocClosed
:
881 This
->state
= XmlWriterState_DocClosed
;
882 return WR_E_INVALIDACTION
;
883 case XmlWriterState_InvalidEncoding
:
884 return MX_E_ENCODING
;
890 is_xmlns_prefix
= prefix
&& !wcscmp(prefix
, L
"xmlns");
891 if (is_xmlns_prefix
&& is_empty_string(uri
) && is_empty_string(local
))
892 return WR_E_NSPREFIXDECLARED
;
897 /* Validate prefix and local name */
898 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
901 if (FAILED(hr
= is_valid_ncname(local
, &local_len
)))
904 is_xmlns_local
= !wcscmp(local
, L
"xmlns");
906 /* Trivial case, no prefix. */
907 if (prefix_len
== 0 && is_empty_string(uri
))
909 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
913 /* Predefined "xml" prefix. */
914 if (prefix_len
&& !wcscmp(prefix
, L
"xml"))
916 /* Valid "space" value is enforced. */
917 if (!wcscmp(local
, L
"space") && !is_valid_xml_space_value(value
))
918 return WR_E_INVALIDXMLSPACE
;
920 /* Redefinition is not allowed. */
921 if (!is_empty_string(uri
))
922 return WR_E_XMLPREFIXDECLARATION
;
924 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
929 if (is_xmlns_prefix
|| (prefix_len
== 0 && uri
&& !wcscmp(uri
, xmlnsuriW
)))
931 if (prefix_len
&& !is_empty_string(uri
))
932 return WR_E_XMLNSPREFIXDECLARATION
;
934 /* Look for exact match defined in current element, and write it out. */
935 if (!(ns
= writer_find_ns_current(This
, prefix
, value
)))
936 ns
= writer_push_ns(This
, local
, local_len
, value
);
939 write_output_attribute(This
, L
"xmlns", 5, local
, local_len
, value
);
944 /* Ignore prefix is URI wasn't specified. */
945 if (is_xmlns_local
&& is_empty_string(uri
))
947 write_output_attribute(This
, NULL
, 0, L
"xmlns", 5, value
);
951 if (!(ns
= writer_find_ns(This
, prefix
, uri
)))
953 if (is_empty_string(prefix
) && !is_empty_string(uri
))
955 FIXME("Prefix autogeneration is not implemented.\n");
958 if (!is_empty_string(uri
))
959 ns
= writer_push_ns(This
, prefix
, prefix_len
, uri
);
963 write_output_attribute(This
, ns
->prefix
, ns
->prefix_len
, local
, local_len
, value
);
965 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
970 static void write_cdata_section(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
972 write_output_buffer(output
, L
"<![CDATA[", 9);
974 write_output_buffer(output
, data
, len
);
975 write_output_buffer(output
, L
"]]>", 3);
978 static HRESULT WINAPI
xmlwriter_WriteCData(IXmlWriter
*iface
, LPCWSTR data
)
980 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
983 TRACE("%p %s\n", This
, debugstr_w(data
));
987 case XmlWriterState_Initial
:
989 case XmlWriterState_ElemStarted
:
990 writer_close_starttag(This
);
992 case XmlWriterState_Ready
:
993 case XmlWriterState_DocClosed
:
994 This
->state
= XmlWriterState_DocClosed
;
995 return WR_E_INVALIDACTION
;
996 case XmlWriterState_InvalidEncoding
:
997 return MX_E_ENCODING
;
1002 len
= data
? lstrlenW(data
) : 0;
1004 write_node_indent(This
);
1006 write_cdata_section(This
->output
, NULL
, 0);
1011 const WCHAR
*str
= wcsstr(data
, L
"]]>");
1014 write_cdata_section(This
->output
, data
, str
- data
);
1019 write_cdata_section(This
->output
, data
, len
);
1028 static HRESULT WINAPI
xmlwriter_WriteCharEntity(IXmlWriter
*iface
, WCHAR ch
)
1030 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1033 TRACE("%p %#x\n", This
, ch
);
1035 switch (This
->state
)
1037 case XmlWriterState_Initial
:
1038 return E_UNEXPECTED
;
1039 case XmlWriterState_InvalidEncoding
:
1040 return MX_E_ENCODING
;
1041 case XmlWriterState_ElemStarted
:
1042 writer_close_starttag(This
);
1044 case XmlWriterState_DocClosed
:
1045 return WR_E_INVALIDACTION
;
1050 swprintf(bufW
, ARRAY_SIZE(bufW
), L
"&#x%x;", ch
);
1051 write_output_buffer(This
->output
, bufW
, -1);
1056 static HRESULT WINAPI
xmlwriter_WriteChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
1058 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1060 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
1062 switch (This
->state
)
1064 case XmlWriterState_Initial
:
1065 return E_UNEXPECTED
;
1066 case XmlWriterState_InvalidEncoding
:
1067 return MX_E_ENCODING
;
1068 case XmlWriterState_DocClosed
:
1069 return WR_E_INVALIDACTION
;
1078 static HRESULT WINAPI
xmlwriter_WriteComment(IXmlWriter
*iface
, LPCWSTR comment
)
1080 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1082 TRACE("%p %s\n", This
, debugstr_w(comment
));
1084 switch (This
->state
)
1086 case XmlWriterState_Initial
:
1087 return E_UNEXPECTED
;
1088 case XmlWriterState_InvalidEncoding
:
1089 return MX_E_ENCODING
;
1090 case XmlWriterState_ElemStarted
:
1091 writer_close_starttag(This
);
1093 case XmlWriterState_DocClosed
:
1094 return WR_E_INVALIDACTION
;
1099 write_node_indent(This
);
1100 write_output_buffer(This
->output
, L
"<!--", 4);
1102 int len
= lstrlenW(comment
), i
;
1104 /* Make sure there's no two hyphen sequences in a string, space is used as a separator to produce compliant
1107 for (i
= 0; i
< len
; i
++) {
1108 write_output_buffer(This
->output
, comment
+ i
, 1);
1109 if (comment
[i
] == '-' && (i
+ 1 < len
) && comment
[i
+1] == '-')
1110 write_output_buffer_char(This
->output
, ' ');
1114 write_output_buffer(This
->output
, comment
, len
);
1116 if (len
&& comment
[len
-1] == '-')
1117 write_output_buffer_char(This
->output
, ' ');
1119 write_output_buffer(This
->output
, L
"-->", 3);
1124 static HRESULT WINAPI
xmlwriter_WriteDocType(IXmlWriter
*iface
, LPCWSTR name
, LPCWSTR pubid
,
1125 LPCWSTR sysid
, LPCWSTR subset
)
1127 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1128 unsigned int name_len
, pubid_len
;
1131 TRACE("(%p)->(%s %s %s %s)\n", This
, wine_dbgstr_w(name
), wine_dbgstr_w(pubid
), wine_dbgstr_w(sysid
),
1132 wine_dbgstr_w(subset
));
1134 switch (This
->state
)
1136 case XmlWriterState_Initial
:
1137 return E_UNEXPECTED
;
1138 case XmlWriterState_InvalidEncoding
:
1139 return MX_E_ENCODING
;
1140 case XmlWriterState_Content
:
1141 case XmlWriterState_DocClosed
:
1142 return WR_E_INVALIDACTION
;
1147 if (is_empty_string(name
))
1148 return E_INVALIDARG
;
1150 if (FAILED(hr
= is_valid_name(name
, &name_len
)))
1153 if (FAILED(hr
= is_valid_pubid(pubid
, &pubid_len
)))
1156 write_output_buffer(This
->output
, L
"<!DOCTYPE ", 10);
1157 write_output_buffer(This
->output
, name
, name_len
);
1161 write_output_buffer(This
->output
, L
" PUBLIC ", 8);
1162 write_output_buffer_quoted(This
->output
, pubid
, pubid_len
);
1163 write_output_buffer_char(This
->output
, ' ');
1164 write_output_buffer_quoted(This
->output
, sysid
, -1);
1168 write_output_buffer(This
->output
, L
" SYSTEM ", 8);
1169 write_output_buffer_quoted(This
->output
, sysid
, -1);
1174 write_output_buffer_char(This
->output
, ' ');
1175 write_output_buffer_char(This
->output
, '[');
1176 write_output_buffer(This
->output
, subset
, -1);
1177 write_output_buffer_char(This
->output
, ']');
1179 write_output_buffer_char(This
->output
, '>');
1181 This
->state
= XmlWriterState_Content
;
1186 static HRESULT WINAPI
xmlwriter_WriteElementString(IXmlWriter
*iface
, LPCWSTR prefix
,
1187 LPCWSTR local_name
, LPCWSTR uri
, LPCWSTR value
)
1189 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1190 int prefix_len
, local_len
;
1194 TRACE("(%p)->(%s %s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
),
1195 wine_dbgstr_w(uri
), wine_dbgstr_w(value
));
1197 switch (This
->state
)
1199 case XmlWriterState_Initial
:
1200 return E_UNEXPECTED
;
1201 case XmlWriterState_InvalidEncoding
:
1202 return MX_E_ENCODING
;
1203 case XmlWriterState_ElemStarted
:
1204 writer_close_starttag(This
);
1206 case XmlWriterState_DocClosed
:
1207 return WR_E_INVALIDACTION
;
1213 return E_INVALIDARG
;
1215 /* Validate prefix and local name */
1216 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
1219 if (FAILED(hr
= is_valid_ncname(local_name
, &local_len
)))
1222 ns
= writer_find_ns(This
, prefix
, uri
);
1223 if (!ns
&& !is_empty_string(prefix
) && is_empty_string(uri
))
1224 return WR_E_NSPREFIXWITHEMPTYNSURI
;
1226 if (uri
&& !wcscmp(uri
, xmlnsuriW
))
1229 return WR_E_XMLNSPREFIXDECLARATION
;
1231 if (!is_empty_string(prefix
))
1232 return WR_E_XMLNSURIDECLARATION
;
1235 write_encoding_bom(This
);
1236 write_node_indent(This
);
1238 write_output_buffer_char(This
->output
, '<');
1240 write_output_qname(This
->output
, ns
->prefix
, ns
->prefix_len
, local_name
, local_len
);
1242 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1244 if (!ns
&& (prefix_len
|| !is_empty_string(uri
)))
1246 write_output_qname(This
->output
, L
" xmlns", 6, prefix
, prefix_len
);
1247 write_output_buffer_char(This
->output
, '=');
1248 write_output_buffer_quoted(This
->output
, uri
, -1);
1253 write_output_buffer_char(This
->output
, '>');
1254 write_output_buffer(This
->output
, value
, -1);
1255 write_output_buffer(This
->output
, L
"</", 2);
1256 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1257 write_output_buffer_char(This
->output
, '>');
1260 write_output_buffer(This
->output
, L
" />", 3);
1262 This
->state
= XmlWriterState_Content
;
1267 static HRESULT WINAPI
xmlwriter_WriteEndDocument(IXmlWriter
*iface
)
1269 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1271 TRACE("%p\n", This
);
1273 switch (This
->state
)
1275 case XmlWriterState_Initial
:
1276 return E_UNEXPECTED
;
1277 case XmlWriterState_Ready
:
1278 case XmlWriterState_DocClosed
:
1279 This
->state
= XmlWriterState_DocClosed
;
1280 return WR_E_INVALIDACTION
;
1281 case XmlWriterState_InvalidEncoding
:
1282 return MX_E_ENCODING
;
1287 /* empty element stack */
1288 while (IXmlWriter_WriteEndElement(iface
) == S_OK
)
1291 This
->state
= XmlWriterState_DocClosed
;
1295 static HRESULT WINAPI
xmlwriter_WriteEndElement(IXmlWriter
*iface
)
1297 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1298 struct element
*element
;
1300 TRACE("%p\n", This
);
1302 switch (This
->state
)
1304 case XmlWriterState_Initial
:
1305 return E_UNEXPECTED
;
1306 case XmlWriterState_Ready
:
1307 case XmlWriterState_DocClosed
:
1308 This
->state
= XmlWriterState_DocClosed
;
1309 return WR_E_INVALIDACTION
;
1310 case XmlWriterState_InvalidEncoding
:
1311 return MX_E_ENCODING
;
1316 element
= pop_element(This
);
1318 return WR_E_INVALIDACTION
;
1320 writer_dec_indent(This
);
1322 if (This
->starttagopen
)
1324 writer_output_ns(This
, element
);
1325 write_output_buffer(This
->output
, L
" />", 3);
1326 This
->starttagopen
= 0;
1330 /* Write full end tag. */
1331 write_node_indent(This
);
1332 write_output_buffer(This
->output
, L
"</", 2);
1333 write_output_buffer(This
->output
, element
->qname
, element
->len
);
1334 write_output_buffer_char(This
->output
, '>');
1336 writer_free_element(This
, element
);
1341 static HRESULT WINAPI
xmlwriter_WriteEntityRef(IXmlWriter
*iface
, LPCWSTR pwszName
)
1343 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1345 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
1347 switch (This
->state
)
1349 case XmlWriterState_Initial
:
1350 return E_UNEXPECTED
;
1351 case XmlWriterState_InvalidEncoding
:
1352 return MX_E_ENCODING
;
1353 case XmlWriterState_DocClosed
:
1354 return WR_E_INVALIDACTION
;
1362 static HRESULT WINAPI
xmlwriter_WriteFullEndElement(IXmlWriter
*iface
)
1364 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1365 struct element
*element
;
1367 TRACE("%p\n", This
);
1369 switch (This
->state
)
1371 case XmlWriterState_Initial
:
1372 return E_UNEXPECTED
;
1373 case XmlWriterState_Ready
:
1374 case XmlWriterState_DocClosed
:
1375 This
->state
= XmlWriterState_DocClosed
;
1376 return WR_E_INVALIDACTION
;
1377 case XmlWriterState_InvalidEncoding
:
1378 return MX_E_ENCODING
;
1379 case XmlWriterState_ElemStarted
:
1380 writer_close_starttag(This
);
1386 element
= pop_element(This
);
1388 return WR_E_INVALIDACTION
;
1390 writer_dec_indent(This
);
1392 /* don't force full end tag to the next line */
1393 if (This
->state
== XmlWriterState_ElemStarted
)
1395 This
->state
= XmlWriterState_Content
;
1399 write_node_indent(This
);
1401 /* write full end tag */
1402 write_output_buffer(This
->output
, L
"</", 2);
1403 write_output_buffer(This
->output
, element
->qname
, element
->len
);
1404 write_output_buffer_char(This
->output
, '>');
1406 writer_free_element(This
, element
);
1411 static HRESULT WINAPI
xmlwriter_WriteName(IXmlWriter
*iface
, LPCWSTR pwszName
)
1413 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1415 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
1417 switch (This
->state
)
1419 case XmlWriterState_Initial
:
1420 return E_UNEXPECTED
;
1421 case XmlWriterState_Ready
:
1422 case XmlWriterState_DocClosed
:
1423 This
->state
= XmlWriterState_DocClosed
;
1424 return WR_E_INVALIDACTION
;
1425 case XmlWriterState_InvalidEncoding
:
1426 return MX_E_ENCODING
;
1434 static HRESULT WINAPI
xmlwriter_WriteNmToken(IXmlWriter
*iface
, LPCWSTR pwszNmToken
)
1436 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1438 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszNmToken
));
1440 switch (This
->state
)
1442 case XmlWriterState_Initial
:
1443 return E_UNEXPECTED
;
1444 case XmlWriterState_Ready
:
1445 case XmlWriterState_DocClosed
:
1446 This
->state
= XmlWriterState_DocClosed
;
1447 return WR_E_INVALIDACTION
;
1448 case XmlWriterState_InvalidEncoding
:
1449 return MX_E_ENCODING
;
1457 static HRESULT WINAPI
xmlwriter_WriteNode(IXmlWriter
*iface
, IXmlReader
*pReader
,
1458 BOOL fWriteDefaultAttributes
)
1460 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1462 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
1467 static HRESULT WINAPI
xmlwriter_WriteNodeShallow(IXmlWriter
*iface
, IXmlReader
*pReader
,
1468 BOOL fWriteDefaultAttributes
)
1470 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1472 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
1477 static HRESULT WINAPI
xmlwriter_WriteProcessingInstruction(IXmlWriter
*iface
, LPCWSTR name
,
1480 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1482 TRACE("(%p)->(%s %s)\n", This
, wine_dbgstr_w(name
), wine_dbgstr_w(text
));
1484 switch (This
->state
)
1486 case XmlWriterState_Initial
:
1487 return E_UNEXPECTED
;
1488 case XmlWriterState_InvalidEncoding
:
1489 return MX_E_ENCODING
;
1490 case XmlWriterState_DocStarted
:
1491 if (!wcscmp(name
, L
"xml"))
1492 return WR_E_INVALIDACTION
;
1494 case XmlWriterState_ElemStarted
:
1495 case XmlWriterState_DocClosed
:
1496 return WR_E_INVALIDACTION
;
1501 write_encoding_bom(This
);
1502 write_node_indent(This
);
1503 write_output_buffer(This
->output
, L
"<?", 2);
1504 write_output_buffer(This
->output
, name
, -1);
1505 write_output_buffer_char(This
->output
, ' ');
1506 write_output_buffer(This
->output
, text
, -1);
1507 write_output_buffer(This
->output
, L
"?>", 2);
1509 if (!wcscmp(name
, L
"xml"))
1510 This
->state
= XmlWriterState_PIDocStarted
;
1515 static HRESULT WINAPI
xmlwriter_WriteQualifiedName(IXmlWriter
*iface
, LPCWSTR pwszLocalName
,
1516 LPCWSTR pwszNamespaceUri
)
1518 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1520 FIXME("%p %s %s\n", This
, wine_dbgstr_w(pwszLocalName
), wine_dbgstr_w(pwszNamespaceUri
));
1522 switch (This
->state
)
1524 case XmlWriterState_Initial
:
1525 return E_UNEXPECTED
;
1526 case XmlWriterState_InvalidEncoding
:
1527 return MX_E_ENCODING
;
1528 case XmlWriterState_DocClosed
:
1529 return WR_E_INVALIDACTION
;
1537 static HRESULT WINAPI
xmlwriter_WriteRaw(IXmlWriter
*iface
, LPCWSTR data
)
1539 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1541 TRACE("%p %s\n", This
, debugstr_w(data
));
1546 switch (This
->state
)
1548 case XmlWriterState_Initial
:
1549 return E_UNEXPECTED
;
1550 case XmlWriterState_Ready
:
1551 write_xmldecl(This
, XmlStandalone_Omit
);
1553 case XmlWriterState_DocStarted
:
1554 case XmlWriterState_PIDocStarted
:
1556 case XmlWriterState_InvalidEncoding
:
1557 return MX_E_ENCODING
;
1559 This
->state
= XmlWriterState_DocClosed
;
1560 return WR_E_INVALIDACTION
;
1563 write_output_buffer(This
->output
, data
, -1);
1567 static HRESULT WINAPI
xmlwriter_WriteRawChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
1569 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1571 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
1573 switch (This
->state
)
1575 case XmlWriterState_Initial
:
1576 return E_UNEXPECTED
;
1577 case XmlWriterState_InvalidEncoding
:
1578 return MX_E_ENCODING
;
1579 case XmlWriterState_DocClosed
:
1580 return WR_E_INVALIDACTION
;
1588 static HRESULT WINAPI
xmlwriter_WriteStartDocument(IXmlWriter
*iface
, XmlStandalone standalone
)
1590 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1592 TRACE("(%p)->(%d)\n", This
, standalone
);
1594 switch (This
->state
)
1596 case XmlWriterState_Initial
:
1597 return E_UNEXPECTED
;
1598 case XmlWriterState_PIDocStarted
:
1599 This
->state
= XmlWriterState_DocStarted
;
1601 case XmlWriterState_Ready
:
1603 case XmlWriterState_InvalidEncoding
:
1604 return MX_E_ENCODING
;
1606 This
->state
= XmlWriterState_DocClosed
;
1607 return WR_E_INVALIDACTION
;
1610 return write_xmldecl(This
, standalone
);
1613 static HRESULT WINAPI
xmlwriter_WriteStartElement(IXmlWriter
*iface
, LPCWSTR prefix
, LPCWSTR local_name
, LPCWSTR uri
)
1615 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1616 int prefix_len
, local_len
;
1617 struct element
*element
;
1621 TRACE("(%p)->(%s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
), wine_dbgstr_w(uri
));
1624 return E_INVALIDARG
;
1626 switch (This
->state
)
1628 case XmlWriterState_Initial
:
1629 return E_UNEXPECTED
;
1630 case XmlWriterState_InvalidEncoding
:
1631 return MX_E_ENCODING
;
1632 case XmlWriterState_DocClosed
:
1633 return WR_E_INVALIDACTION
;
1634 case XmlWriterState_ElemStarted
:
1635 writer_close_starttag(This
);
1641 /* Validate prefix and local name */
1642 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
1645 if (FAILED(hr
= is_valid_ncname(local_name
, &local_len
)))
1648 if (uri
&& !wcscmp(uri
, xmlnsuriW
))
1651 return WR_E_XMLNSPREFIXDECLARATION
;
1653 if (!is_empty_string(prefix
))
1654 return WR_E_XMLNSURIDECLARATION
;
1657 ns
= writer_find_ns(This
, prefix
, uri
);
1659 element
= alloc_element(This
, prefix
, local_name
);
1661 return E_OUTOFMEMORY
;
1663 write_encoding_bom(This
);
1664 write_node_indent(This
);
1666 This
->state
= XmlWriterState_ElemStarted
;
1667 This
->starttagopen
= 1;
1669 writer_push_element(This
, element
);
1672 writer_push_ns(This
, prefix
, prefix_len
, uri
);
1674 write_output_buffer_char(This
->output
, '<');
1676 write_output_qname(This
->output
, ns
->prefix
, ns
->prefix_len
, local_name
, local_len
);
1678 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1679 writer_inc_indent(This
);
1684 static void write_escaped_string(xmlwriter
*writer
, const WCHAR
*string
)
1691 write_output_buffer(writer
->output
, L
"<", 4);
1694 write_output_buffer(writer
->output
, L
"&", 5);
1697 write_output_buffer(writer
->output
, L
">", 4);
1700 write_output_buffer(writer
->output
, string
, 1);
1707 static HRESULT WINAPI
xmlwriter_WriteString(IXmlWriter
*iface
, const WCHAR
*string
)
1709 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1711 TRACE("%p %s\n", This
, debugstr_w(string
));
1716 switch (This
->state
)
1718 case XmlWriterState_Initial
:
1719 return E_UNEXPECTED
;
1720 case XmlWriterState_ElemStarted
:
1721 writer_close_starttag(This
);
1723 case XmlWriterState_Ready
:
1724 case XmlWriterState_DocClosed
:
1725 This
->state
= XmlWriterState_DocClosed
;
1726 return WR_E_INVALIDACTION
;
1727 case XmlWriterState_InvalidEncoding
:
1728 return MX_E_ENCODING
;
1734 write_escaped_string(This
, string
);
1738 static HRESULT WINAPI
xmlwriter_WriteSurrogateCharEntity(IXmlWriter
*iface
, WCHAR wchLow
, WCHAR wchHigh
)
1740 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1742 FIXME("%p %d %d\n", This
, wchLow
, wchHigh
);
1747 static HRESULT WINAPI
xmlwriter_WriteWhitespace(IXmlWriter
*iface
, LPCWSTR pwszWhitespace
)
1749 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1751 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszWhitespace
));
1756 static HRESULT WINAPI
xmlwriter_Flush(IXmlWriter
*iface
)
1758 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1760 TRACE("%p\n", This
);
1762 return writeroutput_flush_stream(This
->output
);
1765 static const struct IXmlWriterVtbl xmlwriter_vtbl
=
1767 xmlwriter_QueryInterface
,
1770 xmlwriter_SetOutput
,
1771 xmlwriter_GetProperty
,
1772 xmlwriter_SetProperty
,
1773 xmlwriter_WriteAttributes
,
1774 xmlwriter_WriteAttributeString
,
1775 xmlwriter_WriteCData
,
1776 xmlwriter_WriteCharEntity
,
1777 xmlwriter_WriteChars
,
1778 xmlwriter_WriteComment
,
1779 xmlwriter_WriteDocType
,
1780 xmlwriter_WriteElementString
,
1781 xmlwriter_WriteEndDocument
,
1782 xmlwriter_WriteEndElement
,
1783 xmlwriter_WriteEntityRef
,
1784 xmlwriter_WriteFullEndElement
,
1785 xmlwriter_WriteName
,
1786 xmlwriter_WriteNmToken
,
1787 xmlwriter_WriteNode
,
1788 xmlwriter_WriteNodeShallow
,
1789 xmlwriter_WriteProcessingInstruction
,
1790 xmlwriter_WriteQualifiedName
,
1792 xmlwriter_WriteRawChars
,
1793 xmlwriter_WriteStartDocument
,
1794 xmlwriter_WriteStartElement
,
1795 xmlwriter_WriteString
,
1796 xmlwriter_WriteSurrogateCharEntity
,
1797 xmlwriter_WriteWhitespace
,
1801 /** IXmlWriterOutput **/
1802 static HRESULT WINAPI
xmlwriteroutput_QueryInterface(IXmlWriterOutput
*iface
, REFIID riid
, void** ppvObject
)
1804 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1806 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1808 if (IsEqualGUID(riid
, &IID_IXmlWriterOutput
) ||
1809 IsEqualGUID(riid
, &IID_IUnknown
))
1815 WARN("interface %s not implemented\n", debugstr_guid(riid
));
1817 return E_NOINTERFACE
;
1820 IUnknown_AddRef(iface
);
1825 static ULONG WINAPI
xmlwriteroutput_AddRef(IXmlWriterOutput
*iface
)
1827 xmlwriteroutput
*output
= impl_from_IXmlWriterOutput(iface
);
1828 ULONG ref
= InterlockedIncrement(&output
->ref
);
1829 TRACE("%p, refcount %ld.\n", iface
, ref
);
1833 static ULONG WINAPI
xmlwriteroutput_Release(IXmlWriterOutput
*iface
)
1835 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1836 LONG ref
= InterlockedDecrement(&This
->ref
);
1838 TRACE("%p, refcount %ld.\n", iface
, ref
);
1842 IMalloc
*imalloc
= This
->imalloc
;
1843 if (This
->output
) IUnknown_Release(This
->output
);
1844 if (This
->stream
) ISequentialStream_Release(This
->stream
);
1845 free_output_buffer(This
);
1846 writeroutput_free(This
, This
->encoding_name
);
1847 writeroutput_free(This
, This
);
1848 if (imalloc
) IMalloc_Release(imalloc
);
1854 static const struct IUnknownVtbl xmlwriteroutputvtbl
=
1856 xmlwriteroutput_QueryInterface
,
1857 xmlwriteroutput_AddRef
,
1858 xmlwriteroutput_Release
1861 HRESULT WINAPI
CreateXmlWriter(REFIID riid
, void **obj
, IMalloc
*imalloc
)
1866 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
1869 writer
= IMalloc_Alloc(imalloc
, sizeof(*writer
));
1871 writer
= heap_alloc(sizeof(*writer
));
1873 return E_OUTOFMEMORY
;
1875 memset(writer
, 0, sizeof(*writer
));
1877 writer
->IXmlWriter_iface
.lpVtbl
= &xmlwriter_vtbl
;
1879 writer
->imalloc
= imalloc
;
1880 if (imalloc
) IMalloc_AddRef(imalloc
);
1882 writer
->conformance
= XmlConformanceLevel_Document
;
1883 writer
->state
= XmlWriterState_Initial
;
1884 list_init(&writer
->elements
);
1886 hr
= IXmlWriter_QueryInterface(&writer
->IXmlWriter_iface
, riid
, obj
);
1887 IXmlWriter_Release(&writer
->IXmlWriter_iface
);
1889 TRACE("returning iface %p, hr %#lx.\n", *obj
, hr
);
1894 static HRESULT
create_writer_output(IUnknown
*stream
, IMalloc
*imalloc
, xml_encoding encoding
,
1895 const WCHAR
*encoding_name
, xmlwriteroutput
**out
)
1897 xmlwriteroutput
*writeroutput
;
1903 writeroutput
= IMalloc_Alloc(imalloc
, sizeof(*writeroutput
));
1905 writeroutput
= heap_alloc(sizeof(*writeroutput
));
1907 return E_OUTOFMEMORY
;
1909 writeroutput
->IXmlWriterOutput_iface
.lpVtbl
= &xmlwriteroutputvtbl
;
1910 writeroutput
->ref
= 1;
1911 writeroutput
->imalloc
= imalloc
;
1913 IMalloc_AddRef(imalloc
);
1914 writeroutput
->encoding
= encoding
;
1915 writeroutput
->stream
= NULL
;
1916 hr
= init_output_buffer(writeroutput
);
1918 IUnknown_Release(&writeroutput
->IXmlWriterOutput_iface
);
1922 if (encoding_name
) {
1923 unsigned int size
= (lstrlenW(encoding_name
) + 1) * sizeof(WCHAR
);
1924 writeroutput
->encoding_name
= writeroutput_alloc(writeroutput
, size
);
1925 memcpy(writeroutput
->encoding_name
, encoding_name
, size
);
1928 writeroutput
->encoding_name
= NULL
;
1929 writeroutput
->written
= 0;
1931 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&writeroutput
->output
);
1933 *out
= writeroutput
;
1935 TRACE("Created writer output %p\n", *out
);
1940 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingName(IUnknown
*stream
, IMalloc
*imalloc
, const WCHAR
*encoding
,
1941 IXmlWriterOutput
**out
)
1943 xmlwriteroutput
*output
;
1944 xml_encoding xml_enc
;
1947 TRACE("%p %p %s %p\n", stream
, imalloc
, debugstr_w(encoding
), out
);
1949 if (!stream
|| !out
)
1950 return E_INVALIDARG
;
1954 xml_enc
= encoding
? parse_encoding_name(encoding
, -1) : XmlEncoding_UTF8
;
1955 if (SUCCEEDED(hr
= create_writer_output(stream
, imalloc
, xml_enc
, encoding
, &output
)))
1956 *out
= &output
->IXmlWriterOutput_iface
;
1961 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingCodePage(IUnknown
*stream
, IMalloc
*imalloc
, UINT codepage
,
1962 IXmlWriterOutput
**out
)
1964 xmlwriteroutput
*output
;
1965 xml_encoding xml_enc
;
1968 TRACE("%p %p %u %p\n", stream
, imalloc
, codepage
, out
);
1970 if (!stream
|| !out
)
1971 return E_INVALIDARG
;
1975 xml_enc
= get_encoding_from_codepage(codepage
);
1976 if (SUCCEEDED(hr
= create_writer_output(stream
, imalloc
, xml_enc
, NULL
, &output
)))
1977 *out
= &output
->IXmlWriterOutput_iface
;