xmllite/writer: Initial support for starting a document.
[wine.git] / dlls / xmllite / writer.c
blob745da797ea925702ff4b141bde41b76659fe329e
1 /*
2 * IXmlWriter implementation
4 * Copyright 2011 Alistair Leslie-Hughes
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
26 #include "xmllite.h"
27 #include "xmllite_private.h"
28 #include "initguid.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(xmllite);
35 /* not defined in public headers */
36 DEFINE_GUID(IID_IXmlWriterOutput, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
38 static const WCHAR closepiW[] = {'?','>'};
40 struct output_buffer
42 char *data;
43 unsigned int allocated;
44 unsigned int written;
45 UINT codepage;
48 typedef enum
50 XmlWriterState_Initial, /* output is not set yet */
51 XmlWriterState_Ready, /* SetOutput() was called, ready to start */
52 XmlWriterState_PIDocStarted, /* document was started with manually added 'xml' PI */
53 XmlWriterState_DocStarted /* document was started with WriteStartDocument() */
54 } XmlWriterState;
56 typedef struct
58 IXmlWriterOutput IXmlWriterOutput_iface;
59 LONG ref;
60 IUnknown *output;
61 ISequentialStream *stream;
62 IMalloc *imalloc;
63 xml_encoding encoding;
64 struct output_buffer buffer;
65 } xmlwriteroutput;
67 static const struct IUnknownVtbl xmlwriteroutputvtbl;
69 typedef struct _xmlwriter
71 IXmlWriter IXmlWriter_iface;
72 LONG ref;
73 IMalloc *imalloc;
74 xmlwriteroutput *output;
75 BOOL indent;
76 BOOL bom;
77 BOOL omitxmldecl;
78 XmlConformanceLevel conformance;
79 XmlWriterState state;
80 } xmlwriter;
82 static inline xmlwriter *impl_from_IXmlWriter(IXmlWriter *iface)
84 return CONTAINING_RECORD(iface, xmlwriter, IXmlWriter_iface);
87 static inline xmlwriteroutput *impl_from_IXmlWriterOutput(IXmlWriterOutput *iface)
89 return CONTAINING_RECORD(iface, xmlwriteroutput, IXmlWriterOutput_iface);
92 static const char *debugstr_writer_prop(XmlWriterProperty prop)
94 static const char * const prop_names[] =
96 "MultiLanguage",
97 "Indent",
98 "ByteOrderMark",
99 "OmitXmlDeclaration",
100 "ConformanceLevel"
103 if (prop > _XmlWriterProperty_Last)
104 return wine_dbg_sprintf("unknown property=%d", prop);
106 return prop_names[prop];
109 /* writer output memory allocation functions */
110 static inline void *writeroutput_alloc(xmlwriteroutput *output, size_t len)
112 return m_alloc(output->imalloc, len);
115 static inline void writeroutput_free(xmlwriteroutput *output, void *mem)
117 m_free(output->imalloc, mem);
120 static inline void *writeroutput_realloc(xmlwriteroutput *output, void *mem, size_t len)
122 return m_realloc(output->imalloc, mem, len);
125 /* writer memory allocation functions */
126 static inline void *writer_alloc(xmlwriter *writer, size_t len)
128 return m_alloc(writer->imalloc, len);
131 static inline void writer_free(xmlwriter *writer, void *mem)
133 m_free(writer->imalloc, mem);
136 static HRESULT init_output_buffer(xmlwriteroutput *output)
138 struct output_buffer *buffer = &output->buffer;
139 const int initial_len = 0x2000;
140 HRESULT hr;
141 UINT cp;
143 hr = get_code_page(output->encoding, &cp);
144 if (FAILED(hr)) return hr;
146 buffer->data = writeroutput_alloc(output, initial_len);
147 if (!buffer->data) return E_OUTOFMEMORY;
149 memset(buffer->data, 0, 4);
150 buffer->allocated = initial_len;
151 buffer->written = 0;
152 buffer->codepage = cp;
154 return S_OK;
157 static void free_output_buffer(xmlwriteroutput *output)
159 struct output_buffer *buffer = &output->buffer;
160 writeroutput_free(output, buffer->data);
161 buffer->data = NULL;
162 buffer->allocated = 0;
163 buffer->written = 0;
166 static HRESULT grow_output_buffer(xmlwriteroutput *output, int length)
168 struct output_buffer *buffer = &output->buffer;
169 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
170 if (buffer->allocated < buffer->written + length + 4) {
171 int grown_size = max(2*buffer->allocated, buffer->allocated + length);
172 char *ptr = writeroutput_realloc(output, buffer->data, grown_size);
173 if (!ptr) return E_OUTOFMEMORY;
174 buffer->data = ptr;
175 buffer->allocated = grown_size;
178 return S_OK;
181 static HRESULT write_output_buffer(xmlwriteroutput *output, const WCHAR *data, int len)
183 struct output_buffer *buffer = &output->buffer;
184 int length;
185 HRESULT hr;
186 char *ptr;
188 if (buffer->codepage != ~0) {
189 length = WideCharToMultiByte(buffer->codepage, 0, data, len, NULL, 0, NULL, NULL);
190 hr = grow_output_buffer(output, length);
191 if (FAILED(hr)) return hr;
192 ptr = buffer->data + buffer->written;
193 length = WideCharToMultiByte(buffer->codepage, 0, data, len, ptr, length, NULL, NULL);
194 buffer->written += len == -1 ? length-1 : length;
196 else {
197 /* WCHAR data just copied */
198 length = len == -1 ? strlenW(data) : len;
199 if (length) {
200 length *= sizeof(WCHAR);
202 hr = grow_output_buffer(output, length);
203 if (FAILED(hr)) return hr;
204 ptr = buffer->data + buffer->written;
206 memcpy(ptr, data, length);
207 buffer->written += length;
208 ptr += length;
209 /* null termination */
210 *(WCHAR*)ptr = 0;
214 return S_OK;
217 static HRESULT write_output_buffer_quoted(xmlwriteroutput *output, const WCHAR *data, int len)
219 static const WCHAR quotW[] = {'"'};
220 write_output_buffer(output, quotW, 1);
221 write_output_buffer(output, data, len);
222 write_output_buffer(output, quotW, 1);
223 return S_OK;
226 static void writeroutput_release_stream(xmlwriteroutput *writeroutput)
228 if (writeroutput->stream) {
229 ISequentialStream_Release(writeroutput->stream);
230 writeroutput->stream = NULL;
234 static inline HRESULT writeroutput_query_for_stream(xmlwriteroutput *writeroutput)
236 HRESULT hr;
238 writeroutput_release_stream(writeroutput);
239 hr = IUnknown_QueryInterface(writeroutput->output, &IID_IStream, (void**)&writeroutput->stream);
240 if (hr != S_OK)
241 hr = IUnknown_QueryInterface(writeroutput->output, &IID_ISequentialStream, (void**)&writeroutput->stream);
243 return hr;
246 static HRESULT WINAPI xmlwriter_QueryInterface(IXmlWriter *iface, REFIID riid, void **ppvObject)
248 xmlwriter *This = impl_from_IXmlWriter(iface);
250 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
252 if (IsEqualGUID(riid, &IID_IUnknown) ||
253 IsEqualGUID(riid, &IID_IXmlWriter))
255 *ppvObject = iface;
258 IXmlWriter_AddRef(iface);
260 return S_OK;
263 static ULONG WINAPI xmlwriter_AddRef(IXmlWriter *iface)
265 xmlwriter *This = impl_from_IXmlWriter(iface);
266 TRACE("%p\n", This);
267 return InterlockedIncrement(&This->ref);
270 static ULONG WINAPI xmlwriter_Release(IXmlWriter *iface)
272 xmlwriter *This = impl_from_IXmlWriter(iface);
273 LONG ref;
275 TRACE("%p\n", This);
277 ref = InterlockedDecrement(&This->ref);
278 if (ref == 0) {
279 IMalloc *imalloc = This->imalloc;
280 if (This->output) IUnknown_Release(&This->output->IXmlWriterOutput_iface);
281 writer_free(This, This);
282 if (imalloc) IMalloc_Release(imalloc);
285 return ref;
288 /*** IXmlWriter methods ***/
289 static HRESULT WINAPI xmlwriter_SetOutput(IXmlWriter *iface, IUnknown *output)
291 xmlwriter *This = impl_from_IXmlWriter(iface);
292 IXmlWriterOutput *writeroutput;
293 HRESULT hr;
295 TRACE("(%p)->(%p)\n", This, output);
297 if (This->output) {
298 writeroutput_release_stream(This->output);
299 IUnknown_Release(&This->output->IXmlWriterOutput_iface);
300 This->output = NULL;
303 /* just reset current output */
304 if (!output) {
305 This->state = XmlWriterState_Initial;
306 return S_OK;
309 /* now try IXmlWriterOutput, ISequentialStream, IStream */
310 hr = IUnknown_QueryInterface(output, &IID_IXmlWriterOutput, (void**)&writeroutput);
311 if (hr == S_OK) {
312 if (writeroutput->lpVtbl == &xmlwriteroutputvtbl)
313 This->output = impl_from_IXmlWriterOutput(writeroutput);
314 else {
315 ERR("got external IXmlWriterOutput implementation: %p, vtbl=%p\n",
316 writeroutput, writeroutput->lpVtbl);
317 IUnknown_Release(writeroutput);
318 return E_FAIL;
323 if (hr != S_OK || !writeroutput) {
324 /* create IXmlWriterOutput basing on supplied interface */
325 hr = CreateXmlWriterOutputWithEncodingName(output, This->imalloc, NULL, &writeroutput);
326 if (hr != S_OK) return hr;
327 This->output = impl_from_IXmlWriterOutput(writeroutput);
330 This->state = XmlWriterState_Ready;
331 return writeroutput_query_for_stream(This->output);
334 static HRESULT WINAPI xmlwriter_GetProperty(IXmlWriter *iface, UINT property, LONG_PTR *value)
336 xmlwriter *This = impl_from_IXmlWriter(iface);
338 TRACE("(%p)->(%s %p)\n", This, debugstr_writer_prop(property), value);
340 if (!value) return E_INVALIDARG;
342 switch (property)
344 case XmlWriterProperty_Indent:
345 *value = This->indent;
346 break;
347 case XmlWriterProperty_ByteOrderMark:
348 *value = This->bom;
349 break;
350 case XmlWriterProperty_OmitXmlDeclaration:
351 *value = This->omitxmldecl;
352 break;
353 case XmlWriterProperty_ConformanceLevel:
354 *value = This->conformance;
355 break;
356 default:
357 FIXME("Unimplemented property (%u)\n", property);
358 return E_NOTIMPL;
361 return S_OK;
364 static HRESULT WINAPI xmlwriter_SetProperty(IXmlWriter *iface, UINT nProperty, LONG_PTR pValue)
366 xmlwriter *This = impl_from_IXmlWriter(iface);
368 FIXME("%p %u %lu\n", This, nProperty, pValue);
370 return E_NOTIMPL;
373 static HRESULT WINAPI xmlwriter_WriteAttributes(IXmlWriter *iface, IXmlReader *pReader,
374 BOOL fWriteDefaultAttributes)
376 xmlwriter *This = impl_from_IXmlWriter(iface);
378 FIXME("%p %p %d\n", This, pReader, fWriteDefaultAttributes);
380 return E_NOTIMPL;
383 static HRESULT WINAPI xmlwriter_WriteAttributeString(IXmlWriter *iface, LPCWSTR pwszPrefix,
384 LPCWSTR pwszLocalName, LPCWSTR pwszNamespaceUri,
385 LPCWSTR pwszValue)
387 xmlwriter *This = impl_from_IXmlWriter(iface);
389 FIXME("%p %s %s %s %s\n", This, wine_dbgstr_w(pwszPrefix), wine_dbgstr_w(pwszLocalName),
390 wine_dbgstr_w(pwszNamespaceUri), wine_dbgstr_w(pwszValue));
392 return E_NOTIMPL;
395 static HRESULT WINAPI xmlwriter_WriteCData(IXmlWriter *iface, LPCWSTR pwszText)
397 xmlwriter *This = impl_from_IXmlWriter(iface);
399 FIXME("%p %s\n", This, wine_dbgstr_w(pwszText));
401 return E_NOTIMPL;
404 static HRESULT WINAPI xmlwriter_WriteCharEntity(IXmlWriter *iface, WCHAR wch)
406 return E_NOTIMPL;
409 static HRESULT WINAPI xmlwriter_WriteChars(IXmlWriter *iface, const WCHAR *pwch, UINT cwch)
411 xmlwriter *This = impl_from_IXmlWriter(iface);
413 FIXME("%p %s %d\n", This, wine_dbgstr_w(pwch), cwch);
415 return E_NOTIMPL;
418 static HRESULT WINAPI xmlwriter_WriteComment(IXmlWriter *iface, LPCWSTR pwszComment)
420 return E_NOTIMPL;
423 static HRESULT WINAPI xmlwriter_WriteDocType(IXmlWriter *iface, LPCWSTR pwszName, LPCWSTR pwszPublicId,
424 LPCWSTR pwszSystemId, LPCWSTR pwszSubset)
426 xmlwriter *This = impl_from_IXmlWriter(iface);
428 FIXME("%p %s %s %s %s\n", This, wine_dbgstr_w(pwszName), wine_dbgstr_w(pwszPublicId),
429 wine_dbgstr_w(pwszSystemId), wine_dbgstr_w(pwszSubset));
431 return E_NOTIMPL;
434 static HRESULT WINAPI xmlwriter_WriteElementString(IXmlWriter *iface, LPCWSTR pwszPrefix,
435 LPCWSTR pwszLocalName, LPCWSTR pwszNamespaceUri,
436 LPCWSTR pwszValue)
438 xmlwriter *This = impl_from_IXmlWriter(iface);
440 FIXME("%p %s %s %s %s\n", This, wine_dbgstr_w(pwszPrefix), wine_dbgstr_w(pwszLocalName),
441 wine_dbgstr_w(pwszNamespaceUri), wine_dbgstr_w(pwszValue));
443 return E_NOTIMPL;
446 static HRESULT WINAPI xmlwriter_WriteEndDocument(IXmlWriter *iface)
448 xmlwriter *This = impl_from_IXmlWriter(iface);
450 FIXME("%p\n", This);
452 return E_NOTIMPL;
455 static HRESULT WINAPI xmlwriter_WriteEndElement(IXmlWriter *iface)
457 xmlwriter *This = impl_from_IXmlWriter(iface);
459 FIXME("%p\n", This);
461 return E_NOTIMPL;
464 static HRESULT WINAPI xmlwriter_WriteEntityRef(IXmlWriter *iface, LPCWSTR pwszName)
466 xmlwriter *This = impl_from_IXmlWriter(iface);
468 FIXME("%p %s\n", This, wine_dbgstr_w(pwszName));
470 return E_NOTIMPL;
473 static HRESULT WINAPI xmlwriter_WriteFullEndElement(IXmlWriter *iface)
475 xmlwriter *This = impl_from_IXmlWriter(iface);
477 FIXME("%p\n", This);
479 return E_NOTIMPL;
482 static HRESULT WINAPI xmlwriter_WriteName(IXmlWriter *iface, LPCWSTR pwszName)
484 xmlwriter *This = impl_from_IXmlWriter(iface);
486 FIXME("%p %s\n", This, wine_dbgstr_w(pwszName));
488 return E_NOTIMPL;
491 static HRESULT WINAPI xmlwriter_WriteNmToken(IXmlWriter *iface, LPCWSTR pwszNmToken)
493 xmlwriter *This = impl_from_IXmlWriter(iface);
495 FIXME("%p %s\n", This, wine_dbgstr_w(pwszNmToken));
497 return E_NOTIMPL;
500 static HRESULT WINAPI xmlwriter_WriteNode(IXmlWriter *iface, IXmlReader *pReader,
501 BOOL fWriteDefaultAttributes)
503 xmlwriter *This = impl_from_IXmlWriter(iface);
505 FIXME("%p %p %d\n", This, pReader, fWriteDefaultAttributes);
507 return E_NOTIMPL;
510 static HRESULT WINAPI xmlwriter_WriteNodeShallow(IXmlWriter *iface, IXmlReader *pReader,
511 BOOL fWriteDefaultAttributes)
513 xmlwriter *This = impl_from_IXmlWriter(iface);
515 FIXME("%p %p %d\n", This, pReader, fWriteDefaultAttributes);
517 return E_NOTIMPL;
520 static HRESULT WINAPI xmlwriter_WriteProcessingInstruction(IXmlWriter *iface, LPCWSTR name,
521 LPCWSTR text)
523 xmlwriter *This = impl_from_IXmlWriter(iface);
524 static const WCHAR xmlW[] = {'x','m','l',0};
525 static const WCHAR openpiW[] = {'<','?'};
526 static const WCHAR spaceW[] = {' '};
528 TRACE("(%p)->(%s %s)\n", This, wine_dbgstr_w(name), wine_dbgstr_w(text));
530 if (This->state == XmlWriterState_Initial)
531 return E_UNEXPECTED;
533 if (This->state == XmlWriterState_DocStarted && !strcmpW(name, xmlW))
534 return WR_E_INVALIDACTION;
536 write_output_buffer(This->output, openpiW, sizeof(openpiW)/sizeof(WCHAR));
537 write_output_buffer(This->output, name, -1);
538 write_output_buffer(This->output, spaceW, 1);
539 write_output_buffer(This->output, text, -1);
540 write_output_buffer(This->output, closepiW, sizeof(closepiW)/sizeof(WCHAR));
542 if (!strcmpW(name, xmlW))
543 This->state = XmlWriterState_PIDocStarted;
545 return S_OK;
548 static HRESULT WINAPI xmlwriter_WriteQualifiedName(IXmlWriter *iface, LPCWSTR pwszLocalName,
549 LPCWSTR pwszNamespaceUri)
551 xmlwriter *This = impl_from_IXmlWriter(iface);
553 FIXME("%p %s %s\n", This, wine_dbgstr_w(pwszLocalName), wine_dbgstr_w(pwszNamespaceUri));
555 return E_NOTIMPL;
558 static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR pwszData)
560 xmlwriter *This = impl_from_IXmlWriter(iface);
562 FIXME("%p %s\n", This, wine_dbgstr_w(pwszData));
564 return E_NOTIMPL;
567 static HRESULT WINAPI xmlwriter_WriteRawChars(IXmlWriter *iface, const WCHAR *pwch, UINT cwch)
569 xmlwriter *This = impl_from_IXmlWriter(iface);
571 FIXME("%p %s %d\n", This, wine_dbgstr_w(pwch), cwch);
573 return E_NOTIMPL;
576 static HRESULT WINAPI xmlwriter_WriteStartDocument(IXmlWriter *iface, XmlStandalone standalone)
578 static const WCHAR versionW[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"'};
579 static const WCHAR encodingW[] = {' ','e','n','c','o','d','i','n','g','='};
580 xmlwriter *This = impl_from_IXmlWriter(iface);
582 TRACE("(%p)->(%d)\n", This, standalone);
584 switch (This->state)
586 case XmlWriterState_Initial:
587 return E_UNEXPECTED;
588 case XmlWriterState_PIDocStarted:
589 This->state = XmlWriterState_DocStarted;
590 return S_OK;
591 case XmlWriterState_DocStarted:
592 return WR_E_INVALIDACTION;
593 default:
597 /* version */
598 write_output_buffer(This->output, versionW, sizeof(versionW)/sizeof(WCHAR));
600 /* encoding */
601 write_output_buffer(This->output, encodingW, sizeof(encodingW)/sizeof(WCHAR));
602 write_output_buffer_quoted(This->output, get_encoding_name(This->output->encoding), -1);
604 /* standalone */
605 if (standalone == XmlStandalone_Omit)
606 write_output_buffer(This->output, closepiW, sizeof(closepiW)/sizeof(WCHAR));
607 else {
608 static const WCHAR standaloneW[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
609 static const WCHAR yesW[] = {'y','e','s','\"','?','>'};
610 static const WCHAR noW[] = {'n','o','\"','?','>'};
612 write_output_buffer(This->output, standaloneW, sizeof(standaloneW)/sizeof(WCHAR));
613 if (standalone == XmlStandalone_Yes)
614 write_output_buffer(This->output, yesW, sizeof(yesW)/sizeof(WCHAR));
615 else
616 write_output_buffer(This->output, noW, sizeof(noW)/sizeof(WCHAR));
619 This->state = XmlWriterState_DocStarted;
620 return S_OK;
623 static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pwszPrefix,
624 LPCWSTR pwszLocalName, LPCWSTR pwszNamespaceUri)
626 xmlwriter *This = impl_from_IXmlWriter(iface);
628 FIXME("%p %s %s %s\n", This, wine_dbgstr_w(pwszPrefix), wine_dbgstr_w(pwszLocalName),
629 wine_dbgstr_w(pwszNamespaceUri));
631 return E_NOTIMPL;
634 static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, LPCWSTR pwszText)
636 xmlwriter *This = impl_from_IXmlWriter(iface);
638 FIXME("%p %s\n", This, wine_dbgstr_w(pwszText));
640 return E_NOTIMPL;
643 static HRESULT WINAPI xmlwriter_WriteSurrogateCharEntity(IXmlWriter *iface, WCHAR wchLow, WCHAR wchHigh)
645 xmlwriter *This = impl_from_IXmlWriter(iface);
647 FIXME("%p %d %d\n", This, wchLow, wchHigh);
649 return E_NOTIMPL;
652 static HRESULT WINAPI xmlwriter_WriteWhitespace(IXmlWriter *iface, LPCWSTR pwszWhitespace)
654 xmlwriter *This = impl_from_IXmlWriter(iface);
656 FIXME("%p %s\n", This, wine_dbgstr_w(pwszWhitespace));
658 return E_NOTIMPL;
661 static HRESULT WINAPI xmlwriter_Flush(IXmlWriter *iface)
663 xmlwriter *This = impl_from_IXmlWriter(iface);
665 FIXME("%p\n", This);
667 return E_NOTIMPL;
670 static const struct IXmlWriterVtbl xmlwriter_vtbl =
672 xmlwriter_QueryInterface,
673 xmlwriter_AddRef,
674 xmlwriter_Release,
675 xmlwriter_SetOutput,
676 xmlwriter_GetProperty,
677 xmlwriter_SetProperty,
678 xmlwriter_WriteAttributes,
679 xmlwriter_WriteAttributeString,
680 xmlwriter_WriteCData,
681 xmlwriter_WriteCharEntity,
682 xmlwriter_WriteChars,
683 xmlwriter_WriteComment,
684 xmlwriter_WriteDocType,
685 xmlwriter_WriteElementString,
686 xmlwriter_WriteEndDocument,
687 xmlwriter_WriteEndElement,
688 xmlwriter_WriteEntityRef,
689 xmlwriter_WriteFullEndElement,
690 xmlwriter_WriteName,
691 xmlwriter_WriteNmToken,
692 xmlwriter_WriteNode,
693 xmlwriter_WriteNodeShallow,
694 xmlwriter_WriteProcessingInstruction,
695 xmlwriter_WriteQualifiedName,
696 xmlwriter_WriteRaw,
697 xmlwriter_WriteRawChars,
698 xmlwriter_WriteStartDocument,
699 xmlwriter_WriteStartElement,
700 xmlwriter_WriteString,
701 xmlwriter_WriteSurrogateCharEntity,
702 xmlwriter_WriteWhitespace,
703 xmlwriter_Flush
706 /** IXmlWriterOutput **/
707 static HRESULT WINAPI xmlwriteroutput_QueryInterface(IXmlWriterOutput *iface, REFIID riid, void** ppvObject)
709 xmlwriteroutput *This = impl_from_IXmlWriterOutput(iface);
711 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
713 if (IsEqualGUID(riid, &IID_IXmlWriterOutput) ||
714 IsEqualGUID(riid, &IID_IUnknown))
716 *ppvObject = iface;
718 else
720 WARN("interface %s not implemented\n", debugstr_guid(riid));
721 *ppvObject = NULL;
722 return E_NOINTERFACE;
725 IUnknown_AddRef(iface);
727 return S_OK;
730 static ULONG WINAPI xmlwriteroutput_AddRef(IXmlWriterOutput *iface)
732 xmlwriteroutput *This = impl_from_IXmlWriterOutput(iface);
733 ULONG ref = InterlockedIncrement(&This->ref);
734 TRACE("(%p)->(%d)\n", This, ref);
735 return ref;
738 static ULONG WINAPI xmlwriteroutput_Release(IXmlWriterOutput *iface)
740 xmlwriteroutput *This = impl_from_IXmlWriterOutput(iface);
741 LONG ref = InterlockedDecrement(&This->ref);
743 TRACE("(%p)->(%d)\n", This, ref);
745 if (ref == 0)
747 IMalloc *imalloc = This->imalloc;
748 if (This->output) IUnknown_Release(This->output);
749 if (This->stream) ISequentialStream_Release(This->stream);
750 free_output_buffer(This);
751 writeroutput_free(This, This);
752 if (imalloc) IMalloc_Release(imalloc);
755 return ref;
758 static const struct IUnknownVtbl xmlwriteroutputvtbl =
760 xmlwriteroutput_QueryInterface,
761 xmlwriteroutput_AddRef,
762 xmlwriteroutput_Release
765 HRESULT WINAPI CreateXmlWriter(REFIID riid, void **obj, IMalloc *imalloc)
767 xmlwriter *writer;
769 TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
771 if (!IsEqualGUID(riid, &IID_IXmlWriter))
773 ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
774 return E_FAIL;
777 if (imalloc)
778 writer = IMalloc_Alloc(imalloc, sizeof(*writer));
779 else
780 writer = heap_alloc(sizeof(*writer));
781 if(!writer) return E_OUTOFMEMORY;
783 writer->IXmlWriter_iface.lpVtbl = &xmlwriter_vtbl;
784 writer->ref = 1;
785 writer->imalloc = imalloc;
786 if (imalloc) IMalloc_AddRef(imalloc);
787 writer->output = NULL;
788 writer->indent = FALSE;
789 writer->bom = TRUE;
790 writer->omitxmldecl = FALSE;
791 writer->conformance = XmlConformanceLevel_Document;
792 writer->state = XmlWriterState_Initial;
794 *obj = &writer->IXmlWriter_iface;
796 TRACE("returning iface %p\n", *obj);
798 return S_OK;
801 HRESULT WINAPI CreateXmlWriterOutputWithEncodingName(IUnknown *stream,
802 IMalloc *imalloc,
803 LPCWSTR encoding,
804 IXmlWriterOutput **output)
806 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
807 xmlwriteroutput *writeroutput;
808 HRESULT hr;
810 TRACE("%p %p %s %p\n", stream, imalloc, debugstr_w(encoding), output);
812 if (!stream || !output) return E_INVALIDARG;
814 *output = NULL;
816 if (imalloc)
817 writeroutput = IMalloc_Alloc(imalloc, sizeof(*writeroutput));
818 else
819 writeroutput = heap_alloc(sizeof(*writeroutput));
820 if(!writeroutput) return E_OUTOFMEMORY;
822 writeroutput->IXmlWriterOutput_iface.lpVtbl = &xmlwriteroutputvtbl;
823 writeroutput->ref = 1;
824 writeroutput->imalloc = imalloc;
825 if (imalloc) IMalloc_AddRef(imalloc);
826 writeroutput->encoding = parse_encoding_name(encoding ? encoding : utf8W, -1);
827 writeroutput->stream = NULL;
828 hr = init_output_buffer(writeroutput);
829 if (FAILED(hr)) {
830 IUnknown_Release(&writeroutput->IXmlWriterOutput_iface);
831 return hr;
834 IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&writeroutput->output);
836 *output = &writeroutput->IXmlWriterOutput_iface;
838 TRACE("returning iface %p\n", *output);
840 return S_OK;