2 * IXmlWriter implementation
4 * Copyright 2011 Alistair Leslie-Hughes
5 * Copyright 2014 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
22 #include "xmllite_private.h"
24 #include <wine/list.h>
25 #include <wine/unicode.h>
27 /* not defined in public headers */
28 DEFINE_GUID(IID_IXmlWriterOutput
, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
30 #define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0]))
32 static const WCHAR closeelementW
[] = {'<','/'};
33 static const WCHAR closepiW
[] = {'?','>'};
34 static const WCHAR ltW
[] = {'<'};
35 static const WCHAR gtW
[] = {'>'};
40 unsigned int allocated
;
47 XmlWriterState_Initial
, /* output is not set yet */
48 XmlWriterState_Ready
, /* SetOutput() was called, ready to start */
49 XmlWriterState_PIDocStarted
, /* document was started with manually added 'xml' PI */
50 XmlWriterState_DocStarted
, /* document was started with WriteStartDocument() */
51 XmlWriterState_ElemStarted
, /* writing element */
52 XmlWriterState_Content
, /* content is accepted at this point */
53 XmlWriterState_DocClosed
/* WriteEndDocument was called */
58 IXmlWriterOutput IXmlWriterOutput_iface
;
61 ISequentialStream
*stream
;
63 xml_encoding encoding
;
64 struct output_buffer buffer
;
67 static const struct IUnknownVtbl xmlwriteroutputvtbl
;
73 unsigned int len
; /* qname length in chars */
76 typedef struct _xmlwriter
78 IXmlWriter IXmlWriter_iface
;
81 xmlwriteroutput
*output
;
85 XmlConformanceLevel conformance
;
92 static inline xmlwriter
*impl_from_IXmlWriter(IXmlWriter
*iface
)
94 return CONTAINING_RECORD(iface
, xmlwriter
, IXmlWriter_iface
);
97 static inline xmlwriteroutput
*impl_from_IXmlWriterOutput(IXmlWriterOutput
*iface
)
99 return CONTAINING_RECORD(iface
, xmlwriteroutput
, IXmlWriterOutput_iface
);
102 static const char *debugstr_writer_prop(XmlWriterProperty prop
)
104 static const char * const prop_names
[] =
109 "OmitXmlDeclaration",
113 if (prop
> _XmlWriterProperty_Last
)
114 return wine_dbg_sprintf("unknown property=%d", prop
);
116 return prop_names
[prop
];
119 /* writer output memory allocation functions */
120 static inline void *writeroutput_alloc(xmlwriteroutput
*output
, size_t len
)
122 return m_alloc(output
->imalloc
, len
);
125 static inline void writeroutput_free(xmlwriteroutput
*output
, void *mem
)
127 m_free(output
->imalloc
, mem
);
130 static inline void *writeroutput_realloc(xmlwriteroutput
*output
, void *mem
, size_t len
)
132 return m_realloc(output
->imalloc
, mem
, len
);
135 /* writer memory allocation functions */
136 static inline void *writer_alloc(xmlwriter
*writer
, size_t len
)
138 return m_alloc(writer
->imalloc
, len
);
141 static inline void writer_free(xmlwriter
*writer
, void *mem
)
143 m_free(writer
->imalloc
, mem
);
146 static struct element
*alloc_element(xmlwriter
*writer
, const WCHAR
*prefix
, const WCHAR
*local
)
151 ret
= writer_alloc(writer
, sizeof(*ret
));
152 if (!ret
) return ret
;
154 len
= prefix
? strlenW(prefix
) + 1 /* ':' */ : 0;
155 len
+= strlenW(local
);
157 ret
->qname
= writer_alloc(writer
, (len
+ 1)*sizeof(WCHAR
));
160 static const WCHAR colonW
[] = {':',0};
161 strcpyW(ret
->qname
, prefix
);
162 strcatW(ret
->qname
, colonW
);
166 strcatW(ret
->qname
, local
);
171 static void free_element(xmlwriter
*writer
, struct element
*element
)
173 writer_free(writer
, element
->qname
);
174 writer_free(writer
, element
);
177 static void push_element(xmlwriter
*writer
, struct element
*element
)
179 list_add_head(&writer
->elements
, &element
->entry
);
182 static struct element
*pop_element(xmlwriter
*writer
)
184 struct element
*element
= LIST_ENTRY(list_head(&writer
->elements
), struct element
, entry
);
187 list_remove(&element
->entry
);
192 static HRESULT
init_output_buffer(xmlwriteroutput
*output
)
194 struct output_buffer
*buffer
= &output
->buffer
;
195 const int initial_len
= 0x2000;
199 hr
= get_code_page(output
->encoding
, &cp
);
200 if (FAILED(hr
)) return hr
;
202 buffer
->data
= writeroutput_alloc(output
, initial_len
);
203 if (!buffer
->data
) return E_OUTOFMEMORY
;
205 memset(buffer
->data
, 0, 4);
206 buffer
->allocated
= initial_len
;
208 buffer
->codepage
= cp
;
213 static void free_output_buffer(xmlwriteroutput
*output
)
215 struct output_buffer
*buffer
= &output
->buffer
;
216 writeroutput_free(output
, buffer
->data
);
218 buffer
->allocated
= 0;
222 static HRESULT
grow_output_buffer(xmlwriteroutput
*output
, int length
)
224 struct output_buffer
*buffer
= &output
->buffer
;
225 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
226 if (buffer
->allocated
< buffer
->written
+ length
+ 4) {
227 int grown_size
= max(2*buffer
->allocated
, buffer
->allocated
+ length
);
228 char *ptr
= writeroutput_realloc(output
, buffer
->data
, grown_size
);
229 if (!ptr
) return E_OUTOFMEMORY
;
231 buffer
->allocated
= grown_size
;
237 static HRESULT
write_output_buffer(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
239 struct output_buffer
*buffer
= &output
->buffer
;
244 if (buffer
->codepage
!= ~0) {
245 length
= WideCharToMultiByte(buffer
->codepage
, 0, data
, len
, NULL
, 0, NULL
, NULL
);
246 hr
= grow_output_buffer(output
, length
);
247 if (FAILED(hr
)) return hr
;
248 ptr
= buffer
->data
+ buffer
->written
;
249 length
= WideCharToMultiByte(buffer
->codepage
, 0, data
, len
, ptr
, length
, NULL
, NULL
);
250 buffer
->written
+= len
== -1 ? length
-1 : length
;
253 /* WCHAR data just copied */
254 length
= len
== -1 ? strlenW(data
) : len
;
256 length
*= sizeof(WCHAR
);
258 hr
= grow_output_buffer(output
, length
);
259 if (FAILED(hr
)) return hr
;
260 ptr
= buffer
->data
+ buffer
->written
;
262 memcpy(ptr
, data
, length
);
263 buffer
->written
+= length
;
265 /* null termination */
273 static HRESULT
write_output_buffer_quoted(xmlwriteroutput
*output
, const WCHAR
*data
, int len
)
275 static const WCHAR quoteW
[] = {'"'};
276 write_output_buffer(output
, quoteW
, ARRAY_SIZE(quoteW
));
277 write_output_buffer(output
, data
, len
);
278 write_output_buffer(output
, quoteW
, ARRAY_SIZE(quoteW
));
282 /* TODO: test if we need to validate char range */
283 static HRESULT
write_output_qname(xmlwriteroutput
*output
, const WCHAR
*prefix
, const WCHAR
*local_name
)
286 static const WCHAR colW
[] = {':'};
287 write_output_buffer(output
, prefix
, -1);
288 write_output_buffer(output
, colW
, ARRAY_SIZE(colW
));
291 write_output_buffer(output
, local_name
, -1);
296 static void writeroutput_release_stream(xmlwriteroutput
*writeroutput
)
298 if (writeroutput
->stream
) {
299 ISequentialStream_Release(writeroutput
->stream
);
300 writeroutput
->stream
= NULL
;
304 static inline HRESULT
writeroutput_query_for_stream(xmlwriteroutput
*writeroutput
)
308 writeroutput_release_stream(writeroutput
);
309 hr
= IUnknown_QueryInterface(writeroutput
->output
, &IID_IStream
, (void**)&writeroutput
->stream
);
311 hr
= IUnknown_QueryInterface(writeroutput
->output
, &IID_ISequentialStream
, (void**)&writeroutput
->stream
);
316 static HRESULT
writeroutput_flush_stream(xmlwriteroutput
*output
)
318 struct output_buffer
*buffer
;
319 ULONG written
, offset
= 0;
322 if (!output
|| !output
->stream
)
325 buffer
= &output
->buffer
;
327 /* It will loop forever until everything is written or an error occurred. */
330 hr
= ISequentialStream_Write(output
->stream
, buffer
->data
+ offset
, buffer
->written
, &written
);
332 WARN("write to stream failed (0x%08x)\n", hr
);
338 buffer
->written
-= written
;
339 } while (buffer
->written
> 0);
344 static HRESULT
write_encoding_bom(xmlwriter
*writer
)
346 if (!writer
->bom
|| writer
->bomwritten
) return S_OK
;
348 if (writer
->output
->encoding
== XmlEncoding_UTF16
) {
349 static const char utf16bom
[] = {0xff, 0xfe};
350 struct output_buffer
*buffer
= &writer
->output
->buffer
;
351 int len
= sizeof(utf16bom
);
354 hr
= grow_output_buffer(writer
->output
, len
);
355 if (FAILED(hr
)) return hr
;
356 memcpy(buffer
->data
+ buffer
->written
, utf16bom
, len
);
357 buffer
->written
+= len
;
360 writer
->bomwritten
= TRUE
;
364 static HRESULT
writer_close_starttag(xmlwriter
*writer
)
368 if (!writer
->starttagopen
) return S_OK
;
369 hr
= write_output_buffer(writer
->output
, gtW
, ARRAY_SIZE(gtW
));
370 writer
->starttagopen
= FALSE
;
371 writer
->state
= XmlWriterState_Content
;
375 static HRESULT WINAPI
xmlwriter_QueryInterface(IXmlWriter
*iface
, REFIID riid
, void **ppvObject
)
377 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
379 TRACE("%p %s %p\n", This
, debugstr_guid(riid
), ppvObject
);
381 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
382 IsEqualGUID(riid
, &IID_IXmlWriter
))
387 IXmlWriter_AddRef(iface
);
392 static ULONG WINAPI
xmlwriter_AddRef(IXmlWriter
*iface
)
394 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
396 return InterlockedIncrement(&This
->ref
);
399 static ULONG WINAPI
xmlwriter_Release(IXmlWriter
*iface
)
401 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
406 ref
= InterlockedDecrement(&This
->ref
);
408 struct element
*element
, *element2
;
409 IMalloc
*imalloc
= This
->imalloc
;
411 IXmlWriter_Flush(iface
);
412 if (This
->output
) IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
415 LIST_FOR_EACH_ENTRY_SAFE(element
, element2
, &This
->elements
, struct element
, entry
) {
416 list_remove(&element
->entry
);
417 free_element(This
, element
);
420 writer_free(This
, This
);
421 if (imalloc
) IMalloc_Release(imalloc
);
427 /*** IXmlWriter methods ***/
428 static HRESULT WINAPI
xmlwriter_SetOutput(IXmlWriter
*iface
, IUnknown
*output
)
430 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
431 IXmlWriterOutput
*writeroutput
;
434 TRACE("(%p)->(%p)\n", This
, output
);
437 writeroutput_release_stream(This
->output
);
438 IUnknown_Release(&This
->output
->IXmlWriterOutput_iface
);
440 This
->bomwritten
= FALSE
;
443 /* just reset current output */
445 This
->state
= XmlWriterState_Initial
;
449 /* now try IXmlWriterOutput, ISequentialStream, IStream */
450 hr
= IUnknown_QueryInterface(output
, &IID_IXmlWriterOutput
, (void**)&writeroutput
);
452 if (writeroutput
->lpVtbl
== &xmlwriteroutputvtbl
)
453 This
->output
= impl_from_IXmlWriterOutput(writeroutput
);
455 ERR("got external IXmlWriterOutput implementation: %p, vtbl=%p\n",
456 writeroutput
, writeroutput
->lpVtbl
);
457 IUnknown_Release(writeroutput
);
463 if (hr
!= S_OK
|| !writeroutput
) {
464 /* create IXmlWriterOutput basing on supplied interface */
465 hr
= CreateXmlWriterOutputWithEncodingName(output
, This
->imalloc
, NULL
, &writeroutput
);
466 if (hr
!= S_OK
) return hr
;
467 This
->output
= impl_from_IXmlWriterOutput(writeroutput
);
470 This
->state
= XmlWriterState_Ready
;
471 return writeroutput_query_for_stream(This
->output
);
474 static HRESULT WINAPI
xmlwriter_GetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR
*value
)
476 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
478 TRACE("(%p)->(%s %p)\n", This
, debugstr_writer_prop(property
), value
);
480 if (!value
) return E_INVALIDARG
;
484 case XmlWriterProperty_Indent
:
485 *value
= This
->indent
;
487 case XmlWriterProperty_ByteOrderMark
:
490 case XmlWriterProperty_OmitXmlDeclaration
:
491 *value
= This
->omitxmldecl
;
493 case XmlWriterProperty_ConformanceLevel
:
494 *value
= This
->conformance
;
497 FIXME("Unimplemented property (%u)\n", property
);
504 static HRESULT WINAPI
xmlwriter_SetProperty(IXmlWriter
*iface
, UINT property
, LONG_PTR value
)
506 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
508 TRACE("(%p)->(%s %lu)\n", This
, debugstr_writer_prop(property
), value
);
512 case XmlWriterProperty_ByteOrderMark
:
515 case XmlWriterProperty_OmitXmlDeclaration
:
516 This
->omitxmldecl
= !!value
;
519 FIXME("Unimplemented property (%u)\n", property
);
526 static HRESULT WINAPI
xmlwriter_WriteAttributes(IXmlWriter
*iface
, IXmlReader
*pReader
,
527 BOOL fWriteDefaultAttributes
)
529 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
531 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
536 static HRESULT WINAPI
xmlwriter_WriteAttributeString(IXmlWriter
*iface
, LPCWSTR pwszPrefix
,
537 LPCWSTR pwszLocalName
, LPCWSTR pwszNamespaceUri
,
540 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
542 FIXME("%p %s %s %s %s\n", This
, wine_dbgstr_w(pwszPrefix
), wine_dbgstr_w(pwszLocalName
),
543 wine_dbgstr_w(pwszNamespaceUri
), wine_dbgstr_w(pwszValue
));
548 static HRESULT WINAPI
xmlwriter_WriteCData(IXmlWriter
*iface
, LPCWSTR pwszText
)
550 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
552 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszText
));
557 static HRESULT WINAPI
xmlwriter_WriteCharEntity(IXmlWriter
*iface
, WCHAR wch
)
562 static HRESULT WINAPI
xmlwriter_WriteChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
564 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
566 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
571 static HRESULT WINAPI
xmlwriter_WriteComment(IXmlWriter
*iface
, LPCWSTR pwszComment
)
576 static HRESULT WINAPI
xmlwriter_WriteDocType(IXmlWriter
*iface
, LPCWSTR pwszName
, LPCWSTR pwszPublicId
,
577 LPCWSTR pwszSystemId
, LPCWSTR pwszSubset
)
579 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
581 FIXME("%p %s %s %s %s\n", This
, wine_dbgstr_w(pwszName
), wine_dbgstr_w(pwszPublicId
),
582 wine_dbgstr_w(pwszSystemId
), wine_dbgstr_w(pwszSubset
));
587 static HRESULT WINAPI
xmlwriter_WriteElementString(IXmlWriter
*iface
, LPCWSTR prefix
,
588 LPCWSTR local_name
, LPCWSTR uri
, LPCWSTR value
)
590 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
592 TRACE("(%p)->(%s %s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
),
593 wine_dbgstr_w(uri
), wine_dbgstr_w(value
));
597 case XmlWriterState_Initial
:
599 case XmlWriterState_ElemStarted
:
600 writer_close_starttag(This
);
602 case XmlWriterState_DocClosed
:
603 return WR_E_INVALIDACTION
;
608 write_encoding_bom(This
);
609 write_output_buffer(This
->output
, ltW
, ARRAY_SIZE(ltW
));
610 write_output_qname(This
->output
, prefix
, local_name
);
611 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
614 write_output_buffer(This
->output
, value
, -1);
616 write_output_buffer(This
->output
, closeelementW
, ARRAY_SIZE(closeelementW
));
617 write_output_qname(This
->output
, prefix
, local_name
);
618 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
619 This
->state
= XmlWriterState_Content
;
624 static HRESULT WINAPI
xmlwriter_WriteEndDocument(IXmlWriter
*iface
)
626 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
633 case XmlWriterState_Initial
:
636 case XmlWriterState_Ready
:
637 case XmlWriterState_DocClosed
:
638 hr
= WR_E_INVALIDACTION
;
645 This
->state
= XmlWriterState_DocClosed
;
649 /* empty element stack */
650 while (IXmlWriter_WriteEndElement(iface
) == S_OK
)
653 This
->state
= XmlWriterState_DocClosed
;
657 static HRESULT WINAPI
xmlwriter_WriteEndElement(IXmlWriter
*iface
)
659 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
660 struct element
*element
;
664 element
= pop_element(This
);
666 return WR_E_INVALIDACTION
;
668 if (This
->starttagopen
) {
669 static WCHAR closetagW
[] = {' ','/','>'};
670 write_output_buffer(This
->output
, closetagW
, ARRAY_SIZE(closetagW
));
671 This
->starttagopen
= FALSE
;
674 /* write full end tag */
675 write_output_buffer(This
->output
, closeelementW
, ARRAY_SIZE(closeelementW
));
676 write_output_buffer(This
->output
, element
->qname
, element
->len
);
677 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
683 static HRESULT WINAPI
xmlwriter_WriteEntityRef(IXmlWriter
*iface
, LPCWSTR pwszName
)
685 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
687 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
692 static HRESULT WINAPI
xmlwriter_WriteFullEndElement(IXmlWriter
*iface
)
694 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
695 struct element
*element
;
699 element
= pop_element(This
);
701 return WR_E_INVALIDACTION
;
703 /* write full end tag */
704 write_output_buffer(This
->output
, closeelementW
, ARRAY_SIZE(closeelementW
));
705 write_output_buffer(This
->output
, element
->qname
, element
->len
);
706 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
707 This
->starttagopen
= FALSE
;
712 static HRESULT WINAPI
xmlwriter_WriteName(IXmlWriter
*iface
, LPCWSTR pwszName
)
714 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
716 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszName
));
721 static HRESULT WINAPI
xmlwriter_WriteNmToken(IXmlWriter
*iface
, LPCWSTR pwszNmToken
)
723 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
725 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszNmToken
));
730 static HRESULT WINAPI
xmlwriter_WriteNode(IXmlWriter
*iface
, IXmlReader
*pReader
,
731 BOOL fWriteDefaultAttributes
)
733 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
735 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
740 static HRESULT WINAPI
xmlwriter_WriteNodeShallow(IXmlWriter
*iface
, IXmlReader
*pReader
,
741 BOOL fWriteDefaultAttributes
)
743 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
745 FIXME("%p %p %d\n", This
, pReader
, fWriteDefaultAttributes
);
750 static HRESULT WINAPI
xmlwriter_WriteProcessingInstruction(IXmlWriter
*iface
, LPCWSTR name
,
753 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
754 static const WCHAR xmlW
[] = {'x','m','l',0};
755 static const WCHAR openpiW
[] = {'<','?'};
756 static const WCHAR spaceW
[] = {' '};
758 TRACE("(%p)->(%s %s)\n", This
, wine_dbgstr_w(name
), wine_dbgstr_w(text
));
762 case XmlWriterState_Initial
:
764 case XmlWriterState_DocStarted
:
765 if (!strcmpW(name
, xmlW
))
766 return WR_E_INVALIDACTION
;
768 case XmlWriterState_ElemStarted
:
769 case XmlWriterState_DocClosed
:
770 return WR_E_INVALIDACTION
;
775 write_encoding_bom(This
);
776 write_output_buffer(This
->output
, openpiW
, ARRAY_SIZE(openpiW
));
777 write_output_buffer(This
->output
, name
, -1);
778 write_output_buffer(This
->output
, spaceW
, ARRAY_SIZE(spaceW
));
779 write_output_buffer(This
->output
, text
, -1);
780 write_output_buffer(This
->output
, closepiW
, ARRAY_SIZE(closepiW
));
782 if (!strcmpW(name
, xmlW
))
783 This
->state
= XmlWriterState_PIDocStarted
;
788 static HRESULT WINAPI
xmlwriter_WriteQualifiedName(IXmlWriter
*iface
, LPCWSTR pwszLocalName
,
789 LPCWSTR pwszNamespaceUri
)
791 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
793 FIXME("%p %s %s\n", This
, wine_dbgstr_w(pwszLocalName
), wine_dbgstr_w(pwszNamespaceUri
));
798 static HRESULT WINAPI
xmlwriter_WriteRaw(IXmlWriter
*iface
, LPCWSTR pwszData
)
800 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
802 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszData
));
807 static HRESULT WINAPI
xmlwriter_WriteRawChars(IXmlWriter
*iface
, const WCHAR
*pwch
, UINT cwch
)
809 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
811 FIXME("%p %s %d\n", This
, wine_dbgstr_w(pwch
), cwch
);
816 static HRESULT WINAPI
xmlwriter_WriteStartDocument(IXmlWriter
*iface
, XmlStandalone standalone
)
818 static const WCHAR versionW
[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"'};
819 static const WCHAR encodingW
[] = {' ','e','n','c','o','d','i','n','g','='};
820 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
822 TRACE("(%p)->(%d)\n", This
, standalone
);
826 case XmlWriterState_Initial
:
828 case XmlWriterState_PIDocStarted
:
829 This
->state
= XmlWriterState_DocStarted
;
831 case XmlWriterState_DocStarted
:
832 case XmlWriterState_ElemStarted
:
833 case XmlWriterState_DocClosed
:
834 return WR_E_INVALIDACTION
;
839 write_encoding_bom(This
);
840 This
->state
= XmlWriterState_DocStarted
;
841 if (This
->omitxmldecl
) return S_OK
;
844 write_output_buffer(This
->output
, versionW
, ARRAY_SIZE(versionW
));
847 write_output_buffer(This
->output
, encodingW
, ARRAY_SIZE(encodingW
));
848 write_output_buffer_quoted(This
->output
, get_encoding_name(This
->output
->encoding
), -1);
851 if (standalone
== XmlStandalone_Omit
)
852 write_output_buffer(This
->output
, closepiW
, ARRAY_SIZE(closepiW
));
854 static const WCHAR standaloneW
[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
855 static const WCHAR yesW
[] = {'y','e','s','\"','?','>'};
856 static const WCHAR noW
[] = {'n','o','\"','?','>'};
858 write_output_buffer(This
->output
, standaloneW
, ARRAY_SIZE(standaloneW
));
859 if (standalone
== XmlStandalone_Yes
)
860 write_output_buffer(This
->output
, yesW
, ARRAY_SIZE(yesW
));
862 write_output_buffer(This
->output
, noW
, ARRAY_SIZE(noW
));
868 static HRESULT WINAPI
xmlwriter_WriteStartElement(IXmlWriter
*iface
, LPCWSTR prefix
, LPCWSTR local_name
, LPCWSTR uri
)
870 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
871 struct element
*element
;
873 TRACE("(%p)->(%s %s %s)\n", This
, wine_dbgstr_w(prefix
), wine_dbgstr_w(local_name
), wine_dbgstr_w(uri
));
877 case XmlWriterState_Initial
:
879 case XmlWriterState_DocClosed
:
880 return WR_E_INVALIDACTION
;
888 /* close pending element */
889 if (This
->starttagopen
)
890 write_output_buffer(This
->output
, gtW
, ARRAY_SIZE(gtW
));
892 element
= alloc_element(This
, prefix
, local_name
);
894 return E_OUTOFMEMORY
;
896 write_encoding_bom(This
);
897 This
->state
= XmlWriterState_ElemStarted
;
898 This
->starttagopen
= TRUE
;
900 push_element(This
, element
);
902 write_output_buffer(This
->output
, ltW
, ARRAY_SIZE(ltW
));
903 write_output_qname(This
->output
, prefix
, local_name
);
908 static HRESULT WINAPI
xmlwriter_WriteString(IXmlWriter
*iface
, LPCWSTR pwszText
)
910 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
912 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszText
));
917 static HRESULT WINAPI
xmlwriter_WriteSurrogateCharEntity(IXmlWriter
*iface
, WCHAR wchLow
, WCHAR wchHigh
)
919 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
921 FIXME("%p %d %d\n", This
, wchLow
, wchHigh
);
926 static HRESULT WINAPI
xmlwriter_WriteWhitespace(IXmlWriter
*iface
, LPCWSTR pwszWhitespace
)
928 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
930 FIXME("%p %s\n", This
, wine_dbgstr_w(pwszWhitespace
));
935 static HRESULT WINAPI
xmlwriter_Flush(IXmlWriter
*iface
)
937 xmlwriter
*This
= impl_from_IXmlWriter(iface
);
941 return writeroutput_flush_stream(This
->output
);
944 static const struct IXmlWriterVtbl xmlwriter_vtbl
=
946 xmlwriter_QueryInterface
,
950 xmlwriter_GetProperty
,
951 xmlwriter_SetProperty
,
952 xmlwriter_WriteAttributes
,
953 xmlwriter_WriteAttributeString
,
954 xmlwriter_WriteCData
,
955 xmlwriter_WriteCharEntity
,
956 xmlwriter_WriteChars
,
957 xmlwriter_WriteComment
,
958 xmlwriter_WriteDocType
,
959 xmlwriter_WriteElementString
,
960 xmlwriter_WriteEndDocument
,
961 xmlwriter_WriteEndElement
,
962 xmlwriter_WriteEntityRef
,
963 xmlwriter_WriteFullEndElement
,
965 xmlwriter_WriteNmToken
,
967 xmlwriter_WriteNodeShallow
,
968 xmlwriter_WriteProcessingInstruction
,
969 xmlwriter_WriteQualifiedName
,
971 xmlwriter_WriteRawChars
,
972 xmlwriter_WriteStartDocument
,
973 xmlwriter_WriteStartElement
,
974 xmlwriter_WriteString
,
975 xmlwriter_WriteSurrogateCharEntity
,
976 xmlwriter_WriteWhitespace
,
980 /** IXmlWriterOutput **/
981 static HRESULT WINAPI
xmlwriteroutput_QueryInterface(IXmlWriterOutput
*iface
, REFIID riid
, void** ppvObject
)
983 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
985 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
987 if (IsEqualGUID(riid
, &IID_IXmlWriterOutput
) ||
988 IsEqualGUID(riid
, &IID_IUnknown
))
994 WARN("interface %s not implemented\n", debugstr_guid(riid
));
996 return E_NOINTERFACE
;
999 IUnknown_AddRef(iface
);
1004 static ULONG WINAPI
xmlwriteroutput_AddRef(IXmlWriterOutput
*iface
)
1006 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1007 ULONG ref
= InterlockedIncrement(&This
->ref
);
1008 TRACE("(%p)->(%d)\n", This
, ref
);
1012 static ULONG WINAPI
xmlwriteroutput_Release(IXmlWriterOutput
*iface
)
1014 xmlwriteroutput
*This
= impl_from_IXmlWriterOutput(iface
);
1015 LONG ref
= InterlockedDecrement(&This
->ref
);
1017 TRACE("(%p)->(%d)\n", This
, ref
);
1021 IMalloc
*imalloc
= This
->imalloc
;
1022 if (This
->output
) IUnknown_Release(This
->output
);
1023 if (This
->stream
) ISequentialStream_Release(This
->stream
);
1024 free_output_buffer(This
);
1025 writeroutput_free(This
, This
);
1026 if (imalloc
) IMalloc_Release(imalloc
);
1032 static const struct IUnknownVtbl xmlwriteroutputvtbl
=
1034 xmlwriteroutput_QueryInterface
,
1035 xmlwriteroutput_AddRef
,
1036 xmlwriteroutput_Release
1039 HRESULT WINAPI
CreateXmlWriter(REFIID riid
, void **obj
, IMalloc
*imalloc
)
1043 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid
), obj
, imalloc
);
1045 if (!IsEqualGUID(riid
, &IID_IXmlWriter
))
1047 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid
));
1052 writer
= IMalloc_Alloc(imalloc
, sizeof(*writer
));
1054 writer
= heap_alloc(sizeof(*writer
));
1055 if(!writer
) return E_OUTOFMEMORY
;
1057 writer
->IXmlWriter_iface
.lpVtbl
= &xmlwriter_vtbl
;
1059 writer
->imalloc
= imalloc
;
1060 if (imalloc
) IMalloc_AddRef(imalloc
);
1061 writer
->output
= NULL
;
1062 writer
->indent
= FALSE
;
1064 writer
->omitxmldecl
= FALSE
;
1065 writer
->conformance
= XmlConformanceLevel_Document
;
1066 writer
->state
= XmlWriterState_Initial
;
1067 writer
->bomwritten
= FALSE
;
1068 writer
->starttagopen
= FALSE
;
1069 list_init(&writer
->elements
);
1071 *obj
= &writer
->IXmlWriter_iface
;
1073 TRACE("returning iface %p\n", *obj
);
1078 static HRESULT
create_writer(IUnknown
*stream
, IMalloc
*imalloc
, xml_encoding encoding
,
1079 IXmlWriterOutput
**output
)
1081 xmlwriteroutput
*writeroutput
;
1087 writeroutput
= IMalloc_Alloc(imalloc
, sizeof(*writeroutput
));
1089 writeroutput
= heap_alloc(sizeof(*writeroutput
));
1090 if(!writeroutput
) return E_OUTOFMEMORY
;
1092 writeroutput
->IXmlWriterOutput_iface
.lpVtbl
= &xmlwriteroutputvtbl
;
1093 writeroutput
->ref
= 1;
1094 writeroutput
->imalloc
= imalloc
;
1095 if (imalloc
) IMalloc_AddRef(imalloc
);
1096 writeroutput
->encoding
= encoding
;
1097 writeroutput
->stream
= NULL
;
1098 hr
= init_output_buffer(writeroutput
);
1100 IUnknown_Release(&writeroutput
->IXmlWriterOutput_iface
);
1104 IUnknown_QueryInterface(stream
, &IID_IUnknown
, (void**)&writeroutput
->output
);
1106 *output
= &writeroutput
->IXmlWriterOutput_iface
;
1108 TRACE("returning iface %p\n", *output
);
1113 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingName(IUnknown
*stream
,
1116 IXmlWriterOutput
**output
)
1118 static const WCHAR utf8W
[] = {'U','T','F','-','8',0};
1119 xml_encoding xml_enc
;
1121 TRACE("%p %p %s %p\n", stream
, imalloc
, debugstr_w(encoding
), output
);
1123 if (!stream
|| !output
) return E_INVALIDARG
;
1125 xml_enc
= parse_encoding_name(encoding
? encoding
: utf8W
, -1);
1126 return create_writer(stream
, imalloc
, xml_enc
, output
);
1129 HRESULT WINAPI
CreateXmlWriterOutputWithEncodingCodePage(IUnknown
*stream
,
1132 IXmlWriterOutput
**output
)
1134 xml_encoding xml_enc
;
1136 TRACE("%p %p %u %p\n", stream
, imalloc
, codepage
, output
);
1138 if (!stream
|| !output
) return E_INVALIDARG
;
1140 xml_enc
= get_encoding_from_codepage(codepage
);
1141 return create_writer(stream
, imalloc
, xml_enc
, output
);