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"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(xmllite
);
39 /* not defined in public headers */
40 DEFINE_GUID(IID_IXmlWriterOutput
, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
42 static const WCHAR closeelementW
[] = {'<','/'};
43 static const WCHAR closetagW
[] = {' ','/','>'};
44 static const WCHAR closepiW
[] = {'?','>'};
45 static const WCHAR ltW
[] = {'<'};
46 static const WCHAR gtW
[] = {'>'};
47 static const WCHAR spaceW
[] = {' '};
48 static const WCHAR quoteW
[] = {'"'};
49 static const WCHAR eqW
[] = {'='};
50 static const WCHAR xmlnsW
[] = {' ','x','m','l','n','s'};
51 static const WCHAR xmlnsuriW
[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0};
56 unsigned int allocated
;
63 XmlWriterState_Initial
, /* output is not set yet */
64 XmlWriterState_Ready
, /* SetOutput() was called, ready to start */
65 XmlWriterState_InvalidEncoding
, /* SetOutput() was called, but output had invalid encoding */
66 XmlWriterState_PIDocStarted
, /* document was started with manually added 'xml' PI */
67 XmlWriterState_DocStarted
, /* document was started with WriteStartDocument() */
68 XmlWriterState_ElemStarted
, /* writing element */
69 XmlWriterState_Content
, /* content is accepted at this point */
70 XmlWriterState_DocClosed
/* WriteEndDocument was called */
75 IXmlWriterOutput IXmlWriterOutput_iface
;
78 ISequentialStream
*stream
;
80 xml_encoding encoding
;
81 WCHAR
*encoding_name
; /* exactly as specified on output creation */
82 struct output_buffer buffer
;
86 static const struct IUnknownVtbl xmlwriteroutputvtbl
;
92 unsigned int len
; /* qname length in chars */
103 struct element
*element
;
106 typedef struct _xmlwriter
108 IXmlWriter IXmlWriter_iface
;
111 xmlwriteroutput
*output
;
112 unsigned int indent_level
;
116 XmlConformanceLevel conformance
;
117 XmlWriterState state
;
118 struct list elements
;
119 DWORD bomwritten
: 1;
120 DWORD starttagopen
: 1;
124 static inline xmlwriter
*impl_from_IXmlWriter(IXmlWriter
*iface
)
126 return CONTAINING_RECORD(iface
, xmlwriter
, IXmlWriter_iface
);
129 static inline xmlwriteroutput
*impl_from_IXmlWriterOutput(IXmlWriterOutput
*iface
)
131 return CONTAINING_RECORD(iface
, xmlwriteroutput
, IXmlWriterOutput_iface
);
134 static const char *debugstr_writer_prop(XmlWriterProperty prop
)
136 static const char * const prop_names
[] =
141 "OmitXmlDeclaration",
145 if (prop
> _XmlWriterProperty_Last
)
146 return wine_dbg_sprintf("unknown property=%d", prop
);
148 return prop_names
[prop
];
151 static HRESULT
create_writer_output(IUnknown
*stream
, IMalloc
*imalloc
, xml_encoding encoding
,
152 const WCHAR
*encoding_name
, xmlwriteroutput
**out
);
154 /* writer output memory allocation functions */
155 static inline void *writeroutput_alloc(xmlwriteroutput
*output
, size_t len
)
157 return m_alloc(output
->imalloc
, len
);
160 static inline void writeroutput_free(xmlwriteroutput
*output
, void *mem
)
162 m_free(output
->imalloc
, mem
);
165 static inline void *writeroutput_realloc(xmlwriteroutput
*output
, void *mem
, size_t len
)
167 return m_realloc(output
->imalloc
, mem
, len
);
170 /* writer memory allocation functions */
171 static inline void *writer_alloc(const xmlwriter
*writer
, size_t len
)
173 return m_alloc(writer
->imalloc
, len
);
176 static inline void writer_free(const xmlwriter
*writer
, void *mem
)
178 m_free(writer
->imalloc
, mem
);
181 static struct element
*alloc_element(xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*local
)
186 ret
= writer_alloc(writer
, sizeof(*ret
));
187 if (!ret
) return ret
;
189 len
= prefix
? strlenW(prefix
) + 1 /* ':' */ : 0;
190 len
+= strlenW(local
);
192 ret
->qname
= writer_alloc(writer
, (len
+ 1)*sizeof(WCHAR
));
195 static const WCHAR colonW
[] = {':',0};
196 strcpyW(ret
->qname
, prefix
);
197 strcatW(ret
->qname
, colonW
);
201 strcatW(ret
->qname
, local
);
207 static void writer_free_element(xmlwriter
*writer
, struct element
*element
)
211 LIST_FOR_EACH_ENTRY_SAFE(ns
, ns2
, &element
->ns
, struct ns
, entry
)
213 list_remove(&ns
->entry
);
214 writer_free(writer
, ns
->prefix
);
215 writer_free(writer
, ns
->uri
);
216 writer_free(writer
, ns
);
219 writer_free(writer
, element
->qname
);
220 writer_free(writer
, element
);
223 static void writer_free_element_stack(xmlwriter
*writer
)
225 struct element
*element
, *element2
;
227 LIST_FOR_EACH_ENTRY_SAFE(element
, element2
, &writer
->elements
, struct element
, entry
)
229 list_remove(&element
->entry
);
230 writer_free_element(writer
, element
);
234 static void writer_push_element(xmlwriter
*writer
, struct element
*element
)
236 list_add_head(&writer
->elements
, &element
->entry
);
239 static struct element
*pop_element(xmlwriter
*writer
)
241 struct element
*element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
244 list_remove(&element
->entry
);
249 static WCHAR
*writer_strndupW(const xmlwriter
*writer
, const WCHAR
*str
, int len
)
260 size
= (len
+ 1) * sizeof(WCHAR
);
261 ret
= writer_alloc(writer
, size
);
262 memcpy(ret
, str
, size
);
266 static WCHAR
*writer_strdupW(const xmlwriter
*writer
, const WCHAR
*str
)
268 return writer_strndupW(writer
, str
, -1);
271 static struct ns
*writer_push_ns(xmlwriter
*writer
, const WCHAR
*prefix
, int prefix_len
, const WCHAR
*uri
)
273 struct element
*element
;
276 element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
280 if ((ns
= writer_alloc(writer
, sizeof(*ns
))))
282 ns
->prefix
= writer_strndupW(writer
, prefix
, prefix_len
);
283 ns
->prefix_len
= prefix_len
;
284 ns
->uri
= writer_strdupW(writer
, uri
);
286 ns
->element
= element
;
287 list_add_tail(&element
->ns
, &ns
->entry
);
293 static BOOL
is_empty_string(const WCHAR
*str
)
295 return !str
|| !*str
;
298 static struct ns
*writer_find_ns_current(const xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*uri
)
300 struct element
*element
;
303 if (is_empty_string(prefix
) || is_empty_string(uri
))
306 element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
308 LIST_FOR_EACH_ENTRY(ns
, &element
->ns
, struct ns
, entry
)
310 if (!strcmpW(uri
, ns
->uri
) && !strcmpW(prefix
, ns
->prefix
))
317 static struct ns
*writer_find_ns(const xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*uri
)
319 struct element
*element
;
322 if (is_empty_string(prefix
) && is_empty_string(uri
))
325 LIST_FOR_EACH_ENTRY(element
, &writer
->elements
, struct element
, entry
)
327 LIST_FOR_EACH_ENTRY(ns
, &element
->ns
, struct ns
, entry
)
331 if (!ns
->prefix
) continue;
332 if (!strcmpW(ns
->prefix
, prefix
))
335 else if (!strcmpW(uri
, ns
->uri
))
337 if (prefix
&& !*prefix
)
339 if (!prefix
|| !strcmpW(prefix
, ns
->prefix
))
348 static HRESULT
is_valid_ncname(const WCHAR
*str
, int *out
)
359 if (!is_ncnamechar(*str
))
360 return WC_E_NAMECHARACTER
;
369 static HRESULT
init_output_buffer(xmlwriteroutput
*output
)
371 struct output_buffer
*buffer
= &output
->buffer
;
372 const int initial_len
= 0x2000;
376 if (FAILED(hr
= get_code_page(output
->encoding
, &cp
)))
377 WARN("Failed to get code page for specified encoding.\n");
379 buffer
->data
= writeroutput_alloc(output
, initial_len
);
380 if (!buffer
->data
) return E_OUTOFMEMORY
;
382 memset(buffer
->data
, 0, 4);
383 buffer
->allocated
= initial_len
;
385 buffer
->codepage
= cp
;
390 static void free_output_buffer(xmlwriteroutput
*output
)
392 struct output_buffer
*buffer
= &output
->buffer
;
393 writeroutput_free(output
, buffer
->data
);
395 buffer
->allocated
= 0;
399 static HRESULT
grow_output_buffer(xmlwriteroutput
*output
, int length
)
401 struct output_buffer
*buffer
= &output
->buffer
;
402 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
403 if (buffer
->allocated
< buffer
->written
+ length
+ 4) {
404 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
405 char *ptr
= writeroutput_realloc(output
, buffer
->data
, grown_size
);
406 if (!ptr
) return E_OUTOFMEMORY
;
408 buffer
->allocated
= grown_size
;
414 static HRESULT
write_output_buffer(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
416 struct output_buffer
*buffer
= &output
->buffer
;
421 if (buffer
->codepage
== 1200) {
422 /* For UTF-16 encoding just copy. */
423 length
= len
== -1 ? strlenW(data
) : len
;
425 length
*= sizeof(WCHAR
);
427 hr
= grow_output_buffer(output
, length
);
428 if (FAILED(hr
)) return hr
;
429 ptr
= buffer
->data
+ buffer
->written
;
431 memcpy(ptr
, data
, length
);
432 buffer
->written
+= length
;
434 /* null termination */
439 length
= WideCharToMultiByte(buffer
->codepage
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
440 hr
= grow_output_buffer(output
, length
);
441 if (FAILED(hr
)) return hr
;
442 ptr
= buffer
->data
+ buffer
->written
;
443 length
= WideCharToMultiByte(buffer
->codepage
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
444 buffer
->written
+= len
== -1 ? length
-1 : length
;
446 output
->written
= length
!= 0;
451 static HRESULT
write_output_buffer_quoted(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
453 write_output_buffer(output
, quoteW
, ARRAY_SIZE(quoteW
));
454 if (!is_empty_string(data
))
455 write_output_buffer(output
, data
, len
);
456 write_output_buffer(output
, quoteW
, ARRAY_SIZE(quoteW
));
460 /* TODO: test if we need to validate char range */
461 static HRESULT
write_output_qname(xmlwriteroutput
*output
, const WCHAR
*prefix
, int prefix_len
,
462 const WCHAR
*local_name
, int local_len
)
464 static const WCHAR colW
[] = {':'};
466 assert(prefix_len
>= 0 && local_len
>= 0);
469 write_output_buffer(output
, prefix
, prefix_len
);
471 if (prefix_len
&& local_len
)
472 write_output_buffer(output
, colW
, ARRAY_SIZE(colW
));
474 write_output_buffer(output
, local_name
, local_len
);
479 static void writeroutput_release_stream(xmlwriteroutput
*writeroutput
)
481 if (writeroutput
->stream
) {
482 ISequentialStream_Release(writeroutput
->stream
);
483 writeroutput
->stream
= NULL
;
487 static inline HRESULT
writeroutput_query_for_stream(xmlwriteroutput
*writeroutput
)
491 writeroutput_release_stream(writeroutput
);
492 hr
= IUnknown_QueryInterface(writeroutput
->output
, &IID_IStream
, (void**)&writeroutput
->stream
);
494 hr
= IUnknown_QueryInterface(writeroutput
->output
, &IID_ISequentialStream
, (void**)&writeroutput
->stream
);
499 static HRESULT
writeroutput_flush_stream(xmlwriteroutput
*output
)
501 struct output_buffer
*buffer
;
502 ULONG written
, offset
= 0;
505 if (!output
|| !output
->stream
)
508 buffer
= &output
->buffer
;
510 /* It will loop forever until everything is written or an error occurred. */
513 hr
= ISequentialStream_Write(output
->stream
, buffer
->data
+ offset
, buffer
->written
, &written
);
515 WARN("write to stream failed (0x%08x)\n", hr
);
521 buffer
->written
-= written
;
522 } while (buffer
->written
> 0);
527 static HRESULT
write_encoding_bom(xmlwriter
*writer
)
529 if (!writer
->bom
|| writer
->bomwritten
) return S_OK
;
531 if (writer
->output
->encoding
== XmlEncoding_UTF16
) {
532 static const char utf16bom
[] = {0xff, 0xfe};
533 struct output_buffer
*buffer
= &writer
->output
->buffer
;
534 int len
= sizeof(utf16bom
);
537 hr
= grow_output_buffer(writer
->output
, len
);
538 if (FAILED(hr
)) return hr
;
539 memcpy(buffer
->data
+ buffer
->written
, utf16bom
, len
);
540 buffer
->written
+= len
;
543 writer
->bomwritten
= TRUE
;
547 static const WCHAR
*get_output_encoding_name(xmlwriteroutput
*output
)
549 if (output
->encoding_name
)
550 return output
->encoding_name
;
552 return get_encoding_name(output
->encoding
);
555 static HRESULT
write_xmldecl(xmlwriter
*writer
, XmlStandalone standalone
)
557 static const WCHAR versionW
[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"'};
558 static const WCHAR encodingW
[] = {' ','e','n','c','o','d','i','n','g','='};
560 write_encoding_bom(writer
);
561 writer
->state
= XmlWriterState_DocStarted
;
562 if (writer
->omitxmldecl
) return S_OK
;
565 write_output_buffer(writer
->output
, versionW
, ARRAY_SIZE(versionW
));
568 write_output_buffer(writer
->output
, encodingW
, ARRAY_SIZE(encodingW
));
569 write_output_buffer_quoted(writer
->output
, get_output_encoding_name(writer
->output
), -1);
572 if (standalone
== XmlStandalone_Omit
)
573 write_output_buffer(writer
->output
, closepiW
, ARRAY_SIZE(closepiW
));
575 static const WCHAR standaloneW
[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
576 static const WCHAR yesW
[] = {'y','e','s','\"','?','>'};
577 static const WCHAR noW
[] = {'n','o','\"','?','>'};
579 write_output_buffer(writer
->output
, standaloneW
, ARRAY_SIZE(standaloneW
));
580 if (standalone
== XmlStandalone_Yes
)
581 write_output_buffer(writer
->output
, yesW
, ARRAY_SIZE(yesW
));
583 write_output_buffer(writer
->output
, noW
, ARRAY_SIZE(noW
));
589 static void writer_output_ns(xmlwriter
*writer
, struct element
*element
)
593 LIST_FOR_EACH_ENTRY(ns
, &element
->ns
, struct ns
, entry
)
598 write_output_qname(writer
->output
, xmlnsW
, ARRAY_SIZE(xmlnsW
), ns
->prefix
, ns
->prefix_len
);
599 write_output_buffer(writer
->output
, eqW
, ARRAY_SIZE(eqW
));
600 write_output_buffer_quoted(writer
->output
, ns
->uri
, -1);
604 static HRESULT
writer_close_starttag(xmlwriter
*writer
)
608 if (!writer
->starttagopen
) return S_OK
;
610 writer_output_ns(writer
, LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
));
611 hr
= write_output_buffer(writer
->output
, gtW
, ARRAY_SIZE(gtW
));
612 writer
->starttagopen
= 0;
616 static void writer_inc_indent(xmlwriter
*writer
)
618 writer
->indent_level
++;
621 static void writer_dec_indent(xmlwriter
*writer
)
623 if (writer
->indent_level
)
624 writer
->indent_level
--;
627 static void write_node_indent(xmlwriter
*writer
)
629 static const WCHAR dblspaceW
[] = {' ',' '};
630 static const WCHAR crlfW
[] = {'\r','\n'};
631 unsigned int indent_level
= writer
->indent_level
;
633 if (!writer
->indent
|| writer
->textnode
)
635 writer
->textnode
= 0;
639 /* Do state check to prevent newline inserted after BOM. It is assumed that
640 state does not change between writing BOM and inserting indentation. */
641 if (writer
->output
->written
&& writer
->state
!= XmlWriterState_Ready
)
642 write_output_buffer(writer
->output
, crlfW
, ARRAY_SIZE(crlfW
));
643 while (indent_level
--)
644 write_output_buffer(writer
->output
, dblspaceW
, ARRAY_SIZE(dblspaceW
));
646 writer
->textnode
= 0;
649 static HRESULT WINAPI
xmlwriter_QueryInterface(IXmlWriter
*iface
, REFIID riid
, void **ppvObject
)
651 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
653 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
655 if (IsEqualGUID(riid
, &IID_IXmlWriter
) ||
656 IsEqualGUID(riid
, &IID_IUnknown
))
662 FIXME("interface %s is not supported\n", debugstr_guid(riid
));
664 return E_NOINTERFACE
;
667 IXmlWriter_AddRef(iface
);
672 static ULONG WINAPI
xmlwriter_AddRef(IXmlWriter
*iface
)
674 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
675 ULONG ref
= InterlockedIncrement(&This
->ref
);
676 TRACE("(%p)->(%u)\n", This
, ref
);
680 static ULONG WINAPI
xmlwriter_Release(IXmlWriter
*iface
)
682 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
683 ULONG ref
= InterlockedDecrement(&This
->ref
);
685 TRACE("(%p)->(%u)\n", This
, ref
);
688 IMalloc
*imalloc
= This
->imalloc
;
690 writeroutput_flush_stream(This
->output
);
691 if (This
->output
) IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
693 writer_free_element_stack(This
);
695 writer_free(This
, This
);
696 if (imalloc
) IMalloc_Release(imalloc
);
702 /*** IXmlWriter methods ***/
703 static HRESULT WINAPI
xmlwriter_SetOutput(IXmlWriter
*iface
, IUnknown
*output
)
705 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
706 IXmlWriterOutput
*writeroutput
;
709 TRACE("(%p)->(%p)\n", This
, output
);
712 writeroutput_release_stream(This
->output
);
713 IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
715 This
->bomwritten
= 0;
717 This
->indent_level
= 0;
718 writer_free_element_stack(This
);
721 /* just reset current output */
723 This
->state
= XmlWriterState_Initial
;
727 /* now try IXmlWriterOutput, ISequentialStream, IStream */
728 hr
= IUnknown_QueryInterface(output
, &IID_IXmlWriterOutput
, (void**)&writeroutput
);
730 if (writeroutput
->lpVtbl
== &xmlwriteroutputvtbl
)
731 This
->output
= impl_from_IXmlWriterOutput(writeroutput
);
733 ERR("got external IXmlWriterOutput implementation: %p, vtbl=%p\n",
734 writeroutput
, writeroutput
->lpVtbl
);
735 IUnknown_Release(writeroutput
);
740 if (hr
!= S_OK
|| !writeroutput
) {
741 /* Create output for given stream. */
742 hr
= create_writer_output(output
, This
->imalloc
, XmlEncoding_UTF8
, NULL
, &This
->output
);
747 if (This
->output
->encoding
== XmlEncoding_Unknown
)
748 This
->state
= XmlWriterState_InvalidEncoding
;
750 This
->state
= XmlWriterState_Ready
;
751 return writeroutput_query_for_stream(This
->output
);
754 static HRESULT WINAPI
xmlwriter_GetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR
*value
)
756 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
758 TRACE("(%p)->(%s %p)\n", This
, debugstr_writer_prop(property
), value
);
760 if (!value
) return E_INVALIDARG
;
764 case XmlWriterProperty_Indent
:
765 *value
= This
->indent
;
767 case XmlWriterProperty_ByteOrderMark
:
770 case XmlWriterProperty_OmitXmlDeclaration
:
771 *value
= This
->omitxmldecl
;
773 case XmlWriterProperty_ConformanceLevel
:
774 *value
= This
->conformance
;
777 FIXME("Unimplemented property (%u)\n", property
);
784 static HRESULT WINAPI
xmlwriter_SetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR value
)
786 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
788 TRACE("(%p)->(%s %lu)\n", This
, debugstr_writer_prop(property
), value
);
792 case XmlWriterProperty_Indent
:
793 This
->indent
= !!value
;
795 case XmlWriterProperty_ByteOrderMark
:
798 case XmlWriterProperty_OmitXmlDeclaration
:
799 This
->omitxmldecl
= !!value
;
802 FIXME("Unimplemented property (%u)\n", property
);
809 static HRESULT WINAPI
xmlwriter_WriteAttributes(IXmlWriter
*iface
, IXmlReader
*pReader
,
810 BOOL fWriteDefaultAttributes
)
812 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
814 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
819 static void write_output_attribute(xmlwriter
*writer
, const WCHAR
*prefix
, int prefix_len
,
820 const WCHAR
*local
, int local_len
, const WCHAR
*value
)
822 write_output_buffer(writer
->output
, spaceW
, ARRAY_SIZE(spaceW
));
823 write_output_qname(writer
->output
, prefix
, prefix_len
, local
, local_len
);
824 write_output_buffer(writer
->output
, eqW
, ARRAY_SIZE(eqW
));
825 write_output_buffer_quoted(writer
->output
, value
, -1);
828 static BOOL
is_valid_xml_space_value(const WCHAR
*value
)
830 static const WCHAR preserveW
[] = {'p','r','e','s','e','r','v','e',0};
831 static const WCHAR defaultW
[] = {'d','e','f','a','u','l','t',0};
836 return !strcmpW(value
, preserveW
) || !strcmpW(value
, defaultW
);
839 static HRESULT WINAPI
xmlwriter_WriteAttributeString(IXmlWriter
*iface
, LPCWSTR prefix
,
840 LPCWSTR local
, LPCWSTR uri
, LPCWSTR value
)
842 static const WCHAR spaceattrW
[] = {'s','p','a','c','e',0};
843 static const WCHAR xmlnsW
[] = {'x','m','l','n','s',0};
844 static const WCHAR xmlW
[] = {'x','m','l',0};
845 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
846 BOOL is_xmlns_prefix
, is_xmlns_local
;
847 int prefix_len
, local_len
;
851 TRACE("%p %s %s %s %s\n", This
, debugstr_w(prefix
), debugstr_w(local
), debugstr_w(uri
), debugstr_w(value
));
855 case XmlWriterState_Initial
:
857 case XmlWriterState_Ready
:
858 case XmlWriterState_DocClosed
:
859 This
->state
= XmlWriterState_DocClosed
;
860 return WR_E_INVALIDACTION
;
861 case XmlWriterState_InvalidEncoding
:
862 return MX_E_ENCODING
;
868 is_xmlns_prefix
= prefix
&& !strcmpW(prefix
, xmlnsW
);
869 if (is_xmlns_prefix
&& is_empty_string(uri
) && is_empty_string(local
))
870 return WR_E_NSPREFIXDECLARED
;
875 /* Validate prefix and local name */
876 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
879 if (FAILED(hr
= is_valid_ncname(local
, &local_len
)))
882 is_xmlns_local
= !strcmpW(local
, xmlnsW
);
884 /* Trivial case, no prefix. */
885 if (prefix_len
== 0 && is_empty_string(uri
))
887 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
891 /* Predefined "xml" prefix. */
892 if (prefix_len
&& !strcmpW(prefix
, xmlW
))
894 /* Valid "space" value is enforced. */
895 if (!strcmpW(local
, spaceattrW
) && !is_valid_xml_space_value(value
))
896 return WR_E_INVALIDXMLSPACE
;
898 /* Redefinition is not allowed. */
899 if (!is_empty_string(uri
))
900 return WR_E_XMLPREFIXDECLARATION
;
902 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
907 if (is_xmlns_prefix
|| (prefix_len
== 0 && uri
&& !strcmpW(uri
, xmlnsuriW
)))
909 if (prefix_len
&& !is_empty_string(uri
))
910 return WR_E_XMLNSPREFIXDECLARATION
;
912 /* Look for exact match defined in current element, and write it out. */
913 if (!(ns
= writer_find_ns_current(This
, prefix
, value
)))
914 ns
= writer_push_ns(This
, local
, local_len
, value
);
917 write_output_attribute(This
, xmlnsW
, ARRAY_SIZE(xmlnsW
) - 1, local
, local_len
, value
);
922 /* Ignore prefix is URI wasn't specified. */
923 if (is_xmlns_local
&& is_empty_string(uri
))
925 write_output_attribute(This
, NULL
, 0, xmlnsW
, ARRAY_SIZE(xmlnsW
) - 1, value
);
929 if (!(ns
= writer_find_ns(This
, prefix
, uri
)))
931 if (is_empty_string(prefix
) && !is_empty_string(uri
))
933 FIXME("Prefix autogeneration is not implemented.\n");
936 if (!is_empty_string(uri
))
937 ns
= writer_push_ns(This
, prefix
, prefix_len
, uri
);
941 write_output_attribute(This
, ns
->prefix
, ns
->prefix_len
, local
, local_len
, value
);
943 write_output_attribute(This
, prefix
, prefix_len
, local
, local_len
, value
);
948 static void write_cdata_section(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
950 static const WCHAR cdataopenW
[] = {'<','!','[','C','D','A','T','A','['};
951 static const WCHAR cdatacloseW
[] = {']',']','>'};
952 write_output_buffer(output
, cdataopenW
, ARRAY_SIZE(cdataopenW
));
954 write_output_buffer(output
, data
, len
);
955 write_output_buffer(output
, cdatacloseW
, ARRAY_SIZE(cdatacloseW
));
958 static HRESULT WINAPI
xmlwriter_WriteCData(IXmlWriter
*iface
, LPCWSTR data
)
960 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
963 TRACE("%p %s\n", This
, debugstr_w(data
));
967 case XmlWriterState_Initial
:
969 case XmlWriterState_ElemStarted
:
970 writer_close_starttag(This
);
972 case XmlWriterState_Ready
:
973 case XmlWriterState_DocClosed
:
974 This
->state
= XmlWriterState_DocClosed
;
975 return WR_E_INVALIDACTION
;
976 case XmlWriterState_InvalidEncoding
:
977 return MX_E_ENCODING
;
982 len
= data
? strlenW(data
) : 0;
984 write_node_indent(This
);
986 write_cdata_section(This
->output
, NULL
, 0);
988 static const WCHAR cdatacloseW
[] = {']',']','>',0};
990 const WCHAR
*str
= strstrW(data
, cdatacloseW
);
993 write_cdata_section(This
->output
, data
, str
- data
);
998 write_cdata_section(This
->output
, data
, len
);
1007 static HRESULT WINAPI
xmlwriter_WriteCharEntity(IXmlWriter
*iface
, WCHAR ch
)
1009 static const WCHAR fmtW
[] = {'&','#','x','%','x',';',0};
1010 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1013 TRACE("%p %#x\n", This
, ch
);
1015 switch (This
->state
)
1017 case XmlWriterState_Initial
:
1018 return E_UNEXPECTED
;
1019 case XmlWriterState_InvalidEncoding
:
1020 return MX_E_ENCODING
;
1021 case XmlWriterState_ElemStarted
:
1022 writer_close_starttag(This
);
1024 case XmlWriterState_DocClosed
:
1025 return WR_E_INVALIDACTION
;
1030 sprintfW(bufW
, fmtW
, ch
);
1031 write_output_buffer(This
->output
, bufW
, -1);
1036 static HRESULT WINAPI
xmlwriter_WriteChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
1038 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1040 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
1042 switch (This
->state
)
1044 case XmlWriterState_Initial
:
1045 return E_UNEXPECTED
;
1046 case XmlWriterState_InvalidEncoding
:
1047 return MX_E_ENCODING
;
1048 case XmlWriterState_DocClosed
:
1049 return WR_E_INVALIDACTION
;
1058 static HRESULT WINAPI
xmlwriter_WriteComment(IXmlWriter
*iface
, LPCWSTR comment
)
1060 static const WCHAR copenW
[] = {'<','!','-','-'};
1061 static const WCHAR ccloseW
[] = {'-','-','>'};
1062 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1064 TRACE("%p %s\n", This
, debugstr_w(comment
));
1066 switch (This
->state
)
1068 case XmlWriterState_Initial
:
1069 return E_UNEXPECTED
;
1070 case XmlWriterState_InvalidEncoding
:
1071 return MX_E_ENCODING
;
1072 case XmlWriterState_ElemStarted
:
1073 writer_close_starttag(This
);
1075 case XmlWriterState_DocClosed
:
1076 return WR_E_INVALIDACTION
;
1081 write_node_indent(This
);
1082 write_output_buffer(This
->output
, copenW
, ARRAY_SIZE(copenW
));
1084 int len
= strlenW(comment
), i
;
1086 /* Make sure there's no two hyphen sequences in a string, space is used as a separator to produce compliant
1089 for (i
= 0; i
< len
; i
++) {
1090 write_output_buffer(This
->output
, comment
+ i
, 1);
1091 if (comment
[i
] == '-' && (i
+ 1 < len
) && comment
[i
+1] == '-')
1092 write_output_buffer(This
->output
, spaceW
, ARRAY_SIZE(spaceW
));
1096 write_output_buffer(This
->output
, comment
, len
);
1098 if (len
&& comment
[len
-1] == '-')
1099 write_output_buffer(This
->output
, spaceW
, ARRAY_SIZE(spaceW
));
1101 write_output_buffer(This
->output
, ccloseW
, ARRAY_SIZE(ccloseW
));
1106 static HRESULT WINAPI
xmlwriter_WriteDocType(IXmlWriter
*iface
, LPCWSTR pwszName
, LPCWSTR pwszPublicId
,
1107 LPCWSTR pwszSystemId
, LPCWSTR pwszSubset
)
1109 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1111 FIXME("%p %s %s %s %s\n", This
, wine_dbgstr_w(pwszName
), wine_dbgstr_w(pwszPublicId
),
1112 wine_dbgstr_w(pwszSystemId
), wine_dbgstr_w(pwszSubset
));
1117 static HRESULT WINAPI
xmlwriter_WriteElementString(IXmlWriter
*iface
, LPCWSTR prefix
,
1118 LPCWSTR local_name
, LPCWSTR uri
, LPCWSTR value
)
1120 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1121 int prefix_len
, local_len
;
1125 TRACE("(%p)->(%s %s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
),
1126 wine_dbgstr_w(uri
), wine_dbgstr_w(value
));
1128 switch (This
->state
)
1130 case XmlWriterState_Initial
:
1131 return E_UNEXPECTED
;
1132 case XmlWriterState_InvalidEncoding
:
1133 return MX_E_ENCODING
;
1134 case XmlWriterState_ElemStarted
:
1135 writer_close_starttag(This
);
1137 case XmlWriterState_DocClosed
:
1138 return WR_E_INVALIDACTION
;
1144 return E_INVALIDARG
;
1146 /* Validate prefix and local name */
1147 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
1150 if (FAILED(hr
= is_valid_ncname(local_name
, &local_len
)))
1153 ns
= writer_find_ns(This
, prefix
, uri
);
1154 if (!ns
&& !is_empty_string(prefix
) && is_empty_string(uri
))
1155 return WR_E_NSPREFIXWITHEMPTYNSURI
;
1157 if (uri
&& !strcmpW(uri
, xmlnsuriW
))
1160 return WR_E_XMLNSPREFIXDECLARATION
;
1162 if (!is_empty_string(prefix
))
1163 return WR_E_XMLNSURIDECLARATION
;
1166 write_encoding_bom(This
);
1167 write_node_indent(This
);
1169 write_output_buffer(This
->output
, ltW
, ARRAY_SIZE(ltW
));
1171 write_output_qname(This
->output
, ns
->prefix
, ns
->prefix_len
, local_name
, local_len
);
1173 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1175 if (!ns
&& (prefix_len
|| !is_empty_string(uri
)))
1177 write_output_qname(This
->output
, xmlnsW
, ARRAY_SIZE(xmlnsW
), prefix
, prefix_len
);
1178 write_output_buffer(This
->output
, eqW
, ARRAY_SIZE(eqW
));
1179 write_output_buffer_quoted(This
->output
, uri
, -1);
1184 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
1185 write_output_buffer(This
->output
, value
, -1);
1186 write_output_buffer(This
->output
, closeelementW
, ARRAY_SIZE(closeelementW
));
1187 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1188 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
1191 write_output_buffer(This
->output
, closetagW
, ARRAY_SIZE(closetagW
));
1193 This
->state
= XmlWriterState_Content
;
1198 static HRESULT WINAPI
xmlwriter_WriteEndDocument(IXmlWriter
*iface
)
1200 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1202 TRACE("%p\n", This
);
1204 switch (This
->state
)
1206 case XmlWriterState_Initial
:
1207 return E_UNEXPECTED
;
1208 case XmlWriterState_Ready
:
1209 case XmlWriterState_DocClosed
:
1210 This
->state
= XmlWriterState_DocClosed
;
1211 return WR_E_INVALIDACTION
;
1212 case XmlWriterState_InvalidEncoding
:
1213 return MX_E_ENCODING
;
1218 /* empty element stack */
1219 while (IXmlWriter_WriteEndElement(iface
) == S_OK
)
1222 This
->state
= XmlWriterState_DocClosed
;
1226 static HRESULT WINAPI
xmlwriter_WriteEndElement(IXmlWriter
*iface
)
1228 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1229 struct element
*element
;
1231 TRACE("%p\n", This
);
1233 switch (This
->state
)
1235 case XmlWriterState_Initial
:
1236 return E_UNEXPECTED
;
1237 case XmlWriterState_Ready
:
1238 case XmlWriterState_DocClosed
:
1239 This
->state
= XmlWriterState_DocClosed
;
1240 return WR_E_INVALIDACTION
;
1241 case XmlWriterState_InvalidEncoding
:
1242 return MX_E_ENCODING
;
1247 element
= pop_element(This
);
1249 return WR_E_INVALIDACTION
;
1251 writer_dec_indent(This
);
1253 if (This
->starttagopen
)
1255 writer_output_ns(This
, element
);
1256 write_output_buffer(This
->output
, closetagW
, ARRAY_SIZE(closetagW
));
1257 This
->starttagopen
= 0;
1261 /* Write full end tag. */
1262 write_node_indent(This
);
1263 write_output_buffer(This
->output
, closeelementW
, ARRAY_SIZE(closeelementW
));
1264 write_output_buffer(This
->output
, element
->qname
, element
->len
);
1265 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
1267 writer_free_element(This
, element
);
1272 static HRESULT WINAPI
xmlwriter_WriteEntityRef(IXmlWriter
*iface
, LPCWSTR pwszName
)
1274 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1276 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
1278 switch (This
->state
)
1280 case XmlWriterState_Initial
:
1281 return E_UNEXPECTED
;
1282 case XmlWriterState_InvalidEncoding
:
1283 return MX_E_ENCODING
;
1284 case XmlWriterState_DocClosed
:
1285 return WR_E_INVALIDACTION
;
1293 static HRESULT WINAPI
xmlwriter_WriteFullEndElement(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
;
1310 case XmlWriterState_ElemStarted
:
1311 writer_close_starttag(This
);
1317 element
= pop_element(This
);
1319 return WR_E_INVALIDACTION
;
1321 writer_dec_indent(This
);
1323 /* don't force full end tag to the next line */
1324 if (This
->state
== XmlWriterState_ElemStarted
)
1326 This
->state
= XmlWriterState_Content
;
1330 write_node_indent(This
);
1332 /* write full end tag */
1333 write_output_buffer(This
->output
, closeelementW
, ARRAY_SIZE(closeelementW
));
1334 write_output_buffer(This
->output
, element
->qname
, element
->len
);
1335 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
1337 writer_free_element(This
, element
);
1342 static HRESULT WINAPI
xmlwriter_WriteName(IXmlWriter
*iface
, LPCWSTR pwszName
)
1344 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1346 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
1348 switch (This
->state
)
1350 case XmlWriterState_Initial
:
1351 return E_UNEXPECTED
;
1352 case XmlWriterState_Ready
:
1353 case XmlWriterState_DocClosed
:
1354 This
->state
= XmlWriterState_DocClosed
;
1355 return WR_E_INVALIDACTION
;
1356 case XmlWriterState_InvalidEncoding
:
1357 return MX_E_ENCODING
;
1365 static HRESULT WINAPI
xmlwriter_WriteNmToken(IXmlWriter
*iface
, LPCWSTR pwszNmToken
)
1367 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1369 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszNmToken
));
1371 switch (This
->state
)
1373 case XmlWriterState_Initial
:
1374 return E_UNEXPECTED
;
1375 case XmlWriterState_Ready
:
1376 case XmlWriterState_DocClosed
:
1377 This
->state
= XmlWriterState_DocClosed
;
1378 return WR_E_INVALIDACTION
;
1379 case XmlWriterState_InvalidEncoding
:
1380 return MX_E_ENCODING
;
1388 static HRESULT WINAPI
xmlwriter_WriteNode(IXmlWriter
*iface
, IXmlReader
*pReader
,
1389 BOOL fWriteDefaultAttributes
)
1391 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1393 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
1398 static HRESULT WINAPI
xmlwriter_WriteNodeShallow(IXmlWriter
*iface
, IXmlReader
*pReader
,
1399 BOOL fWriteDefaultAttributes
)
1401 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1403 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
1408 static HRESULT WINAPI
xmlwriter_WriteProcessingInstruction(IXmlWriter
*iface
, LPCWSTR name
,
1411 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1412 static const WCHAR xmlW
[] = {'x','m','l',0};
1413 static const WCHAR openpiW
[] = {'<','?'};
1415 TRACE("(%p)->(%s %s)\n", This
, wine_dbgstr_w(name
), wine_dbgstr_w(text
));
1417 switch (This
->state
)
1419 case XmlWriterState_Initial
:
1420 return E_UNEXPECTED
;
1421 case XmlWriterState_InvalidEncoding
:
1422 return MX_E_ENCODING
;
1423 case XmlWriterState_DocStarted
:
1424 if (!strcmpW(name
, xmlW
))
1425 return WR_E_INVALIDACTION
;
1427 case XmlWriterState_ElemStarted
:
1428 case XmlWriterState_DocClosed
:
1429 return WR_E_INVALIDACTION
;
1434 write_encoding_bom(This
);
1435 write_node_indent(This
);
1436 write_output_buffer(This
->output
, openpiW
, ARRAY_SIZE(openpiW
));
1437 write_output_buffer(This
->output
, name
, -1);
1438 write_output_buffer(This
->output
, spaceW
, ARRAY_SIZE(spaceW
));
1439 write_output_buffer(This
->output
, text
, -1);
1440 write_output_buffer(This
->output
, closepiW
, ARRAY_SIZE(closepiW
));
1442 if (!strcmpW(name
, xmlW
))
1443 This
->state
= XmlWriterState_PIDocStarted
;
1448 static HRESULT WINAPI
xmlwriter_WriteQualifiedName(IXmlWriter
*iface
, LPCWSTR pwszLocalName
,
1449 LPCWSTR pwszNamespaceUri
)
1451 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1453 FIXME("%p %s %s\n", This
, wine_dbgstr_w(pwszLocalName
), wine_dbgstr_w(pwszNamespaceUri
));
1455 switch (This
->state
)
1457 case XmlWriterState_Initial
:
1458 return E_UNEXPECTED
;
1459 case XmlWriterState_InvalidEncoding
:
1460 return MX_E_ENCODING
;
1461 case XmlWriterState_DocClosed
:
1462 return WR_E_INVALIDACTION
;
1470 static HRESULT WINAPI
xmlwriter_WriteRaw(IXmlWriter
*iface
, LPCWSTR data
)
1472 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1474 TRACE("%p %s\n", This
, debugstr_w(data
));
1479 switch (This
->state
)
1481 case XmlWriterState_Initial
:
1482 return E_UNEXPECTED
;
1483 case XmlWriterState_Ready
:
1484 write_xmldecl(This
, XmlStandalone_Omit
);
1486 case XmlWriterState_DocStarted
:
1487 case XmlWriterState_PIDocStarted
:
1489 case XmlWriterState_InvalidEncoding
:
1490 return MX_E_ENCODING
;
1492 This
->state
= XmlWriterState_DocClosed
;
1493 return WR_E_INVALIDACTION
;
1496 write_output_buffer(This
->output
, data
, -1);
1500 static HRESULT WINAPI
xmlwriter_WriteRawChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
1502 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1504 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
1506 switch (This
->state
)
1508 case XmlWriterState_Initial
:
1509 return E_UNEXPECTED
;
1510 case XmlWriterState_InvalidEncoding
:
1511 return MX_E_ENCODING
;
1512 case XmlWriterState_DocClosed
:
1513 return WR_E_INVALIDACTION
;
1521 static HRESULT WINAPI
xmlwriter_WriteStartDocument(IXmlWriter
*iface
, XmlStandalone standalone
)
1523 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1525 TRACE("(%p)->(%d)\n", This
, standalone
);
1527 switch (This
->state
)
1529 case XmlWriterState_Initial
:
1530 return E_UNEXPECTED
;
1531 case XmlWriterState_PIDocStarted
:
1532 This
->state
= XmlWriterState_DocStarted
;
1534 case XmlWriterState_Ready
:
1536 case XmlWriterState_InvalidEncoding
:
1537 return MX_E_ENCODING
;
1539 This
->state
= XmlWriterState_DocClosed
;
1540 return WR_E_INVALIDACTION
;
1543 return write_xmldecl(This
, standalone
);
1546 static HRESULT WINAPI
xmlwriter_WriteStartElement(IXmlWriter
*iface
, LPCWSTR prefix
, LPCWSTR local_name
, LPCWSTR uri
)
1548 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1549 int prefix_len
, local_len
;
1550 struct element
*element
;
1554 TRACE("(%p)->(%s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
), wine_dbgstr_w(uri
));
1557 return E_INVALIDARG
;
1559 switch (This
->state
)
1561 case XmlWriterState_Initial
:
1562 return E_UNEXPECTED
;
1563 case XmlWriterState_InvalidEncoding
:
1564 return MX_E_ENCODING
;
1565 case XmlWriterState_DocClosed
:
1566 return WR_E_INVALIDACTION
;
1567 case XmlWriterState_ElemStarted
:
1568 writer_close_starttag(This
);
1574 /* Validate prefix and local name */
1575 if (FAILED(hr
= is_valid_ncname(prefix
, &prefix_len
)))
1578 if (FAILED(hr
= is_valid_ncname(local_name
, &local_len
)))
1581 if (uri
&& !strcmpW(uri
, xmlnsuriW
))
1584 return WR_E_XMLNSPREFIXDECLARATION
;
1586 if (!is_empty_string(prefix
))
1587 return WR_E_XMLNSURIDECLARATION
;
1590 ns
= writer_find_ns(This
, prefix
, uri
);
1592 element
= alloc_element(This
, prefix
, local_name
);
1594 return E_OUTOFMEMORY
;
1596 write_encoding_bom(This
);
1597 write_node_indent(This
);
1599 This
->state
= XmlWriterState_ElemStarted
;
1600 This
->starttagopen
= 1;
1602 writer_push_element(This
, element
);
1605 writer_push_ns(This
, prefix
, prefix_len
, uri
);
1607 write_output_buffer(This
->output
, ltW
, ARRAY_SIZE(ltW
));
1609 write_output_qname(This
->output
, ns
->prefix
, ns
->prefix_len
, local_name
, local_len
);
1611 write_output_qname(This
->output
, prefix
, prefix_len
, local_name
, local_len
);
1612 writer_inc_indent(This
);
1617 static void write_escaped_string(xmlwriter
*writer
, const WCHAR
*string
)
1619 static const WCHAR ampW
[] = {'&','a','m','p',';'};
1620 static const WCHAR ltW
[] = {'&','l','t',';'};
1621 static const WCHAR gtW
[] = {'&','g','t',';'};
1628 write_output_buffer(writer
->output
, ltW
, ARRAY_SIZE(ltW
));
1631 write_output_buffer(writer
->output
, ampW
, ARRAY_SIZE(ampW
));
1634 write_output_buffer(writer
->output
, gtW
, ARRAY_SIZE(gtW
));
1637 write_output_buffer(writer
->output
, string
, 1);
1644 static HRESULT WINAPI
xmlwriter_WriteString(IXmlWriter
*iface
, const WCHAR
*string
)
1646 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1648 TRACE("%p %s\n", This
, debugstr_w(string
));
1653 switch (This
->state
)
1655 case XmlWriterState_Initial
:
1656 return E_UNEXPECTED
;
1657 case XmlWriterState_ElemStarted
:
1658 writer_close_starttag(This
);
1660 case XmlWriterState_Ready
:
1661 case XmlWriterState_DocClosed
:
1662 This
->state
= XmlWriterState_DocClosed
;
1663 return WR_E_INVALIDACTION
;
1664 case XmlWriterState_InvalidEncoding
:
1665 return MX_E_ENCODING
;
1671 write_escaped_string(This
, string
);
1675 static HRESULT WINAPI
xmlwriter_WriteSurrogateCharEntity(IXmlWriter
*iface
, WCHAR wchLow
, WCHAR wchHigh
)
1677 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1679 FIXME("%p %d %d\n", This
, wchLow
, wchHigh
);
1684 static HRESULT WINAPI
xmlwriter_WriteWhitespace(IXmlWriter
*iface
, LPCWSTR pwszWhitespace
)
1686 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1688 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszWhitespace
));
1693 static HRESULT WINAPI
xmlwriter_Flush(IXmlWriter
*iface
)
1695 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
1697 TRACE("%p\n", This
);
1699 return writeroutput_flush_stream(This
->output
);
1702 static const struct IXmlWriterVtbl xmlwriter_vtbl
=
1704 xmlwriter_QueryInterface
,
1707 xmlwriter_SetOutput
,
1708 xmlwriter_GetProperty
,
1709 xmlwriter_SetProperty
,
1710 xmlwriter_WriteAttributes
,
1711 xmlwriter_WriteAttributeString
,
1712 xmlwriter_WriteCData
,
1713 xmlwriter_WriteCharEntity
,
1714 xmlwriter_WriteChars
,
1715 xmlwriter_WriteComment
,
1716 xmlwriter_WriteDocType
,
1717 xmlwriter_WriteElementString
,
1718 xmlwriter_WriteEndDocument
,
1719 xmlwriter_WriteEndElement
,
1720 xmlwriter_WriteEntityRef
,
1721 xmlwriter_WriteFullEndElement
,
1722 xmlwriter_WriteName
,
1723 xmlwriter_WriteNmToken
,
1724 xmlwriter_WriteNode
,
1725 xmlwriter_WriteNodeShallow
,
1726 xmlwriter_WriteProcessingInstruction
,
1727 xmlwriter_WriteQualifiedName
,
1729 xmlwriter_WriteRawChars
,
1730 xmlwriter_WriteStartDocument
,
1731 xmlwriter_WriteStartElement
,
1732 xmlwriter_WriteString
,
1733 xmlwriter_WriteSurrogateCharEntity
,
1734 xmlwriter_WriteWhitespace
,
1738 /** IXmlWriterOutput **/
1739 static HRESULT WINAPI
xmlwriteroutput_QueryInterface(IXmlWriterOutput
*iface
, REFIID riid
, void** ppvObject
)
1741 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1743 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1745 if (IsEqualGUID(riid
, &IID_IXmlWriterOutput
) ||
1746 IsEqualGUID(riid
, &IID_IUnknown
))
1752 WARN("interface %s not implemented\n", debugstr_guid(riid
));
1754 return E_NOINTERFACE
;
1757 IUnknown_AddRef(iface
);
1762 static ULONG WINAPI
xmlwriteroutput_AddRef(IXmlWriterOutput
*iface
)
1764 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1765 ULONG ref
= InterlockedIncrement(&This
->ref
);
1766 TRACE("(%p)->(%d)\n", This
, ref
);
1770 static ULONG WINAPI
xmlwriteroutput_Release(IXmlWriterOutput
*iface
)
1772 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1773 LONG ref
= InterlockedDecrement(&This
->ref
);
1775 TRACE("(%p)->(%d)\n", This
, ref
);
1779 IMalloc
*imalloc
= This
->imalloc
;
1780 if (This
->output
) IUnknown_Release(This
->output
);
1781 if (This
->stream
) ISequentialStream_Release(This
->stream
);
1782 free_output_buffer(This
);
1783 writeroutput_free(This
, This
->encoding_name
);
1784 writeroutput_free(This
, This
);
1785 if (imalloc
) IMalloc_Release(imalloc
);
1791 static const struct IUnknownVtbl xmlwriteroutputvtbl
=
1793 xmlwriteroutput_QueryInterface
,
1794 xmlwriteroutput_AddRef
,
1795 xmlwriteroutput_Release
1798 HRESULT WINAPI
CreateXmlWriter(REFIID riid
, void **obj
, IMalloc
*imalloc
)
1803 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
1806 writer
= IMalloc_Alloc(imalloc
, sizeof(*writer
));
1808 writer
= heap_alloc(sizeof(*writer
));
1810 return E_OUTOFMEMORY
;
1812 memset(writer
, 0, sizeof(*writer
));
1814 writer
->IXmlWriter_iface
.lpVtbl
= &xmlwriter_vtbl
;
1816 writer
->imalloc
= imalloc
;
1817 if (imalloc
) IMalloc_AddRef(imalloc
);
1819 writer
->conformance
= XmlConformanceLevel_Document
;
1820 writer
->state
= XmlWriterState_Initial
;
1821 list_init(&writer
->elements
);
1823 hr
= IXmlWriter_QueryInterface(&writer
->IXmlWriter_iface
, riid
, obj
);
1824 IXmlWriter_Release(&writer
->IXmlWriter_iface
);
1826 TRACE("returning iface %p, hr %#x\n", *obj
, hr
);
1831 static HRESULT
create_writer_output(IUnknown
*stream
, IMalloc
*imalloc
, xml_encoding encoding
,
1832 const WCHAR
*encoding_name
, xmlwriteroutput
**out
)
1834 xmlwriteroutput
*writeroutput
;
1840 writeroutput
= IMalloc_Alloc(imalloc
, sizeof(*writeroutput
));
1842 writeroutput
= heap_alloc(sizeof(*writeroutput
));
1844 return E_OUTOFMEMORY
;
1846 writeroutput
->IXmlWriterOutput_iface
.lpVtbl
= &xmlwriteroutputvtbl
;
1847 writeroutput
->ref
= 1;
1848 writeroutput
->imalloc
= imalloc
;
1850 IMalloc_AddRef(imalloc
);
1851 writeroutput
->encoding
= encoding
;
1852 writeroutput
->stream
= NULL
;
1853 hr
= init_output_buffer(writeroutput
);
1855 IUnknown_Release(&writeroutput
->IXmlWriterOutput_iface
);
1859 if (encoding_name
) {
1860 unsigned int size
= (strlenW(encoding_name
) + 1) * sizeof(WCHAR
);
1861 writeroutput
->encoding_name
= writeroutput_alloc(writeroutput
, size
);
1862 memcpy(writeroutput
->encoding_name
, encoding_name
, size
);
1865 writeroutput
->encoding_name
= NULL
;
1866 writeroutput
->written
= 0;
1868 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&writeroutput
->output
);
1870 *out
= writeroutput
;
1872 TRACE("Created writer output %p\n", *out
);
1877 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingName(IUnknown
*stream
, IMalloc
*imalloc
, const WCHAR
*encoding
,
1878 IXmlWriterOutput
**out
)
1880 xmlwriteroutput
*output
;
1881 xml_encoding xml_enc
;
1884 TRACE("%p %p %s %p\n", stream
, imalloc
, debugstr_w(encoding
), out
);
1886 if (!stream
|| !out
)
1887 return E_INVALIDARG
;
1891 xml_enc
= encoding
? parse_encoding_name(encoding
, -1) : XmlEncoding_UTF8
;
1892 if (SUCCEEDED(hr
= create_writer_output(stream
, imalloc
, xml_enc
, encoding
, &output
)))
1893 *out
= &output
->IXmlWriterOutput_iface
;
1898 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingCodePage(IUnknown
*stream
, IMalloc
*imalloc
, UINT codepage
,
1899 IXmlWriterOutput
**out
)
1901 xmlwriteroutput
*output
;
1902 xml_encoding xml_enc
;
1905 TRACE("%p %p %u %p\n", stream
, imalloc
, codepage
, out
);
1907 if (!stream
|| !out
)
1908 return E_INVALIDARG
;
1912 xml_enc
= get_encoding_from_codepage(codepage
);
1913 if (SUCCEEDED(hr
= create_writer_output(stream
, imalloc
, xml_enc
, NULL
, &output
)))
1914 *out
= &output
->IXmlWriterOutput_iface
;