msxml3: Use a helper to get property values.
[wine/multimedia.git] / dlls / msxml3 / mxwriter.c
blobcc75d1dc4048303af4bb928902759d53ac6a4bbb
1 /*
2 * MXWriter implementation
4 * Copyright 2011 Nikolay Sivov for CodeWeavers
5 * Copyright 2011 Thomas Mullaly
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 #define COBJMACROS
23 #include "config.h"
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "ole2.h"
34 #include "msxml6.h"
36 #include "wine/debug.h"
38 #include "msxml_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
42 #ifdef HAVE_LIBXML2
44 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
45 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
47 static const char crlfA[] = "\r\n";
48 static const WCHAR emptyW[] = {0};
50 typedef enum
52 MXWriter_BOM = 0,
53 MXWriter_DisableEscaping,
54 MXWriter_Indent,
55 MXWriter_OmitXmlDecl,
56 MXWriter_Standalone,
57 MXWriter_LastProp
58 } MXWRITER_PROPS;
60 typedef struct _mxwriter
62 IMXWriter IMXWriter_iface;
63 ISAXContentHandler ISAXContentHandler_iface;
65 LONG ref;
66 MSXML_VERSION class_version;
68 VARIANT_BOOL props[MXWriter_LastProp];
69 BOOL prop_changed;
70 xmlCharEncoding encoding;
71 BSTR version;
73 /* contains a pending (or not closed yet) element name or NULL if
74 we don't have to close */
75 BSTR element;
77 IStream *dest;
78 ULONG dest_written;
80 xmlOutputBufferPtr buffer;
81 } mxwriter;
83 static HRESULT bstr_from_xmlCharEncoding(xmlCharEncoding enc, BSTR *encoding)
85 const char *encodingA;
87 if (enc != XML_CHAR_ENCODING_UTF16LE && enc != XML_CHAR_ENCODING_UTF8) {
88 FIXME("Unsupported xmlCharEncoding: %d\n", enc);
89 *encoding = NULL;
90 return E_NOTIMPL;
93 encodingA = xmlGetCharEncodingName(enc);
94 if (encodingA) {
95 DWORD len = MultiByteToWideChar(CP_ACP, 0, encodingA, -1, NULL, 0);
96 *encoding = SysAllocStringLen(NULL, len-1);
97 if(*encoding)
98 MultiByteToWideChar( CP_ACP, 0, encodingA, -1, *encoding, len);
99 } else
100 *encoding = SysAllocStringLen(NULL, 0);
102 return *encoding ? S_OK : E_OUTOFMEMORY;
105 /* Attempts to the write data from the mxwriter's buffer to
106 * the destination stream (if there is one).
108 static HRESULT write_data_to_stream(mxwriter *This)
110 HRESULT hres;
111 ULONG written = 0;
112 xmlBufferPtr buffer = NULL;
114 if (!This->dest)
115 return S_OK;
117 /* The xmlOutputBuffer doesn't copy its contents from its 'buffer' to the
118 * 'conv' buffer when UTF8 encoding is used.
120 if (This->encoding == XML_CHAR_ENCODING_UTF8)
121 buffer = This->buffer->buffer;
122 else
123 buffer = This->buffer->conv;
125 if (This->dest_written > buffer->use) {
126 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This->dest_written, buffer->use);
127 return E_FAIL;
128 } else if (This->dest_written == buffer->use && This->encoding != XML_CHAR_ENCODING_UTF8)
129 /* Windows seems to make an empty write call when the encoding is UTF-8 and
130 * all the data has been written to the stream. It doesn't seem make this call
131 * for any other encodings.
133 return S_OK;
135 /* Write the current content from the output buffer into 'dest'.
136 * TODO: Check what Windows does if the IStream doesn't write all of
137 * the data we give it at once.
139 hres = IStream_Write(This->dest, buffer->content+This->dest_written,
140 buffer->use-This->dest_written, &written);
141 if (FAILED(hres)) {
142 WARN("Failed to write data to IStream (%08x)\n", hres);
143 return hres;
146 This->dest_written += written;
147 return hres;
150 /* Newly added element start tag left unclosed cause for empty elements
151 we have to close it differently. */
152 static void close_element_starttag(const mxwriter *This)
154 if (!This->element) return;
155 xmlOutputBufferWriteString(This->buffer, ">");
158 static void set_element_name(mxwriter *This, const WCHAR *name, int len)
160 SysFreeString(This->element);
161 This->element = name ? SysAllocStringLen(name, len) : NULL;
164 static inline HRESULT flush_output_buffer(mxwriter *This)
166 close_element_starttag(This);
167 set_element_name(This, NULL, 0);
168 xmlOutputBufferFlush(This->buffer);
169 return write_data_to_stream(This);
172 /* Resets the mxwriter's output buffer by closing it, then creating a new
173 * output buffer using the given encoding.
175 static inline void reset_output_buffer(mxwriter *This)
177 xmlOutputBufferClose(This->buffer);
178 This->buffer = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This->encoding));
179 This->dest_written = 0;
182 static HRESULT writer_set_property(mxwriter *writer, MXWRITER_PROPS property, VARIANT_BOOL value)
184 writer->props[property] = value;
185 writer->prop_changed = TRUE;
186 return S_OK;
189 static HRESULT writer_get_property(const mxwriter *writer, MXWRITER_PROPS property, VARIANT_BOOL *value)
191 if (!value) return E_POINTER;
192 *value = writer->props[property];
193 return S_OK;
196 static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
198 return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
201 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
203 return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
206 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
208 mxwriter *This = impl_from_IMXWriter( iface );
210 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
212 if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
213 IsEqualGUID( riid, &IID_IDispatch ) ||
214 IsEqualGUID( riid, &IID_IUnknown ) )
216 *obj = &This->IMXWriter_iface;
218 else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
220 *obj = &This->ISAXContentHandler_iface;
222 else
224 ERR("interface %s not implemented\n", debugstr_guid(riid));
225 *obj = NULL;
226 return E_NOINTERFACE;
229 IMXWriter_AddRef(iface);
230 return S_OK;
233 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
235 mxwriter *This = impl_from_IMXWriter( iface );
236 LONG ref = InterlockedIncrement(&This->ref);
238 TRACE("(%p)->(%d)\n", This, ref);
240 return ref;
243 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
245 mxwriter *This = impl_from_IMXWriter( iface );
246 ULONG ref = InterlockedDecrement(&This->ref);
248 TRACE("(%p)->(%d)\n", This, ref);
250 if(!ref)
252 /* Windows flushes the buffer when the interface is destroyed. */
253 flush_output_buffer(This);
255 if (This->dest) IStream_Release(This->dest);
256 SysFreeString(This->version);
258 xmlOutputBufferClose(This->buffer);
259 SysFreeString(This->element);
260 heap_free(This);
263 return ref;
266 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
268 mxwriter *This = impl_from_IMXWriter( iface );
270 TRACE("(%p)->(%p)\n", This, pctinfo);
272 *pctinfo = 1;
274 return S_OK;
277 static HRESULT WINAPI mxwriter_GetTypeInfo(
278 IMXWriter *iface,
279 UINT iTInfo, LCID lcid,
280 ITypeInfo** ppTInfo )
282 mxwriter *This = impl_from_IMXWriter( iface );
284 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
286 return get_typeinfo(IMXWriter_tid, ppTInfo);
289 static HRESULT WINAPI mxwriter_GetIDsOfNames(
290 IMXWriter *iface,
291 REFIID riid, LPOLESTR* rgszNames,
292 UINT cNames, LCID lcid, DISPID* rgDispId )
294 mxwriter *This = impl_from_IMXWriter( iface );
295 ITypeInfo *typeinfo;
296 HRESULT hr;
298 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
299 lcid, rgDispId);
301 if(!rgszNames || cNames == 0 || !rgDispId)
302 return E_INVALIDARG;
304 hr = get_typeinfo(IMXWriter_tid, &typeinfo);
305 if(SUCCEEDED(hr))
307 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
308 ITypeInfo_Release(typeinfo);
311 return hr;
314 static HRESULT WINAPI mxwriter_Invoke(
315 IMXWriter *iface,
316 DISPID dispIdMember, REFIID riid, LCID lcid,
317 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
318 EXCEPINFO* pExcepInfo, UINT* puArgErr )
320 mxwriter *This = impl_from_IMXWriter( iface );
321 ITypeInfo *typeinfo;
322 HRESULT hr;
324 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
325 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
327 hr = get_typeinfo(IMXWriter_tid, &typeinfo);
328 if(SUCCEEDED(hr))
330 hr = ITypeInfo_Invoke(typeinfo, &This->IMXWriter_iface, dispIdMember, wFlags,
331 pDispParams, pVarResult, pExcepInfo, puArgErr);
332 ITypeInfo_Release(typeinfo);
335 return hr;
338 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
340 mxwriter *This = impl_from_IMXWriter( iface );
341 HRESULT hr;
343 TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
345 hr = flush_output_buffer(This);
346 if (FAILED(hr))
347 return hr;
349 switch (V_VT(&dest))
351 case VT_EMPTY:
353 if (This->dest) IStream_Release(This->dest);
354 This->dest = NULL;
356 /* We need to reset the output buffer to UTF-16, since the only way
357 * the content of the mxwriter can be accessed now is through a BSTR.
359 This->encoding = xmlParseCharEncoding("UTF-16");
360 reset_output_buffer(This);
361 break;
363 case VT_UNKNOWN:
365 IStream *stream;
367 hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
368 if (hr == S_OK)
370 /* Recreate the output buffer to make sure it's using the correct encoding. */
371 reset_output_buffer(This);
373 if (This->dest) IStream_Release(This->dest);
374 This->dest = stream;
375 break;
378 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
379 return E_NOTIMPL;
381 default:
382 FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
383 return E_NOTIMPL;
386 return S_OK;
389 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
391 mxwriter *This = impl_from_IMXWriter( iface );
393 TRACE("(%p)->(%p)\n", This, dest);
395 if (!This->dest)
397 HRESULT hr = flush_output_buffer(This);
398 if (FAILED(hr))
399 return hr;
401 /* TODO: Windows always seems to re-encode the XML to UTF-16 (this includes
402 * updating the XML decl so it says "UTF-16" instead of "UTF-8"). We don't
403 * support this yet...
405 if (This->encoding == XML_CHAR_ENCODING_UTF8) {
406 FIXME("XML re-encoding not supported yet\n");
407 return E_NOTIMPL;
410 V_VT(dest) = VT_BSTR;
411 V_BSTR(dest) = SysAllocStringLen((const WCHAR*)This->buffer->conv->content,
412 This->buffer->conv->use/sizeof(WCHAR));
414 return S_OK;
416 else
417 FIXME("not implemented when stream is set up\n");
419 return E_NOTIMPL;
422 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
424 mxwriter *This = impl_from_IMXWriter( iface );
426 TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
428 /* FIXME: filter all supported encodings */
429 if (!strcmpW(encoding, utf16W) || !strcmpW(encoding, utf8W))
431 HRESULT hr;
432 LPSTR enc;
434 hr = flush_output_buffer(This);
435 if (FAILED(hr))
436 return hr;
438 enc = heap_strdupWtoA(encoding);
439 if (!enc)
440 return E_OUTOFMEMORY;
442 This->encoding = xmlParseCharEncoding(enc);
443 heap_free(enc);
445 reset_output_buffer(This);
446 return S_OK;
448 else
450 FIXME("unsupported encoding %s\n", debugstr_w(encoding));
451 return E_INVALIDARG;
455 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
457 mxwriter *This = impl_from_IMXWriter( iface );
459 TRACE("(%p)->(%p)\n", This, encoding);
461 if (!encoding) return E_POINTER;
463 return bstr_from_xmlCharEncoding(This->encoding, encoding);
466 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
468 mxwriter *This = impl_from_IMXWriter( iface );
470 TRACE("(%p)->(%d)\n", This, value);
471 return writer_set_property(This, MXWriter_BOM, value);
474 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
476 mxwriter *This = impl_from_IMXWriter( iface );
478 TRACE("(%p)->(%p)\n", This, value);
479 return writer_get_property(This, MXWriter_BOM, value);
482 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
484 mxwriter *This = impl_from_IMXWriter( iface );
486 TRACE("(%p)->(%d)\n", This, value);
487 return writer_set_property(This, MXWriter_Indent, value);
490 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
492 mxwriter *This = impl_from_IMXWriter( iface );
494 TRACE("(%p)->(%p)\n", This, value);
495 return writer_get_property(This, MXWriter_Indent, value);
498 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
500 mxwriter *This = impl_from_IMXWriter( iface );
502 TRACE("(%p)->(%d)\n", This, value);
503 return writer_set_property(This, MXWriter_Standalone, value);
506 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
508 mxwriter *This = impl_from_IMXWriter( iface );
510 TRACE("(%p)->(%p)\n", This, value);
511 return writer_get_property(This, MXWriter_Standalone, value);
514 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
516 mxwriter *This = impl_from_IMXWriter( iface );
518 TRACE("(%p)->(%d)\n", This, value);
519 return writer_set_property(This, MXWriter_OmitXmlDecl, value);
522 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
524 mxwriter *This = impl_from_IMXWriter( iface );
526 TRACE("(%p)->(%p)\n", This, value);
527 return writer_get_property(This, MXWriter_OmitXmlDecl, value);
530 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
532 mxwriter *This = impl_from_IMXWriter( iface );
534 TRACE("(%p)->(%s)\n", This, debugstr_w(version));
536 if (!version) return E_INVALIDARG;
538 SysFreeString(This->version);
539 This->version = SysAllocString(version);
541 return S_OK;
544 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
546 mxwriter *This = impl_from_IMXWriter( iface );
548 TRACE("(%p)->(%p)\n", This, version);
550 if (!version) return E_POINTER;
552 return return_bstr(This->version, version);
555 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
557 mxwriter *This = impl_from_IMXWriter( iface );
559 TRACE("(%p)->(%d)\n", This, value);
560 return writer_set_property(This, MXWriter_DisableEscaping, value);
563 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
565 mxwriter *This = impl_from_IMXWriter( iface );
567 TRACE("(%p)->(%p)\n", This, value);
568 return writer_get_property(This, MXWriter_DisableEscaping, value);
571 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
573 mxwriter *This = impl_from_IMXWriter( iface );
574 TRACE("(%p)\n", This);
575 return flush_output_buffer(This);
578 static const struct IMXWriterVtbl mxwriter_vtbl =
580 mxwriter_QueryInterface,
581 mxwriter_AddRef,
582 mxwriter_Release,
583 mxwriter_GetTypeInfoCount,
584 mxwriter_GetTypeInfo,
585 mxwriter_GetIDsOfNames,
586 mxwriter_Invoke,
587 mxwriter_put_output,
588 mxwriter_get_output,
589 mxwriter_put_encoding,
590 mxwriter_get_encoding,
591 mxwriter_put_byteOrderMark,
592 mxwriter_get_byteOrderMark,
593 mxwriter_put_indent,
594 mxwriter_get_indent,
595 mxwriter_put_standalone,
596 mxwriter_get_standalone,
597 mxwriter_put_omitXMLDeclaration,
598 mxwriter_get_omitXMLDeclaration,
599 mxwriter_put_version,
600 mxwriter_get_version,
601 mxwriter_put_disableOutputEscaping,
602 mxwriter_get_disableOutputEscaping,
603 mxwriter_flush
606 /*** ISAXContentHandler ***/
607 static HRESULT WINAPI mxwriter_saxcontent_QueryInterface(
608 ISAXContentHandler *iface,
609 REFIID riid,
610 void **obj)
612 mxwriter *This = impl_from_ISAXContentHandler( iface );
613 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
616 static ULONG WINAPI mxwriter_saxcontent_AddRef(ISAXContentHandler *iface)
618 mxwriter *This = impl_from_ISAXContentHandler( iface );
619 return IMXWriter_AddRef(&This->IMXWriter_iface);
622 static ULONG WINAPI mxwriter_saxcontent_Release(ISAXContentHandler *iface)
624 mxwriter *This = impl_from_ISAXContentHandler( iface );
625 return IMXWriter_Release(&This->IMXWriter_iface);
628 static HRESULT WINAPI mxwriter_saxcontent_putDocumentLocator(
629 ISAXContentHandler *iface,
630 ISAXLocator *locator)
632 mxwriter *This = impl_from_ISAXContentHandler( iface );
633 FIXME("(%p)->(%p)\n", This, locator);
634 return E_NOTIMPL;
637 static HRESULT WINAPI mxwriter_saxcontent_startDocument(ISAXContentHandler *iface)
639 mxwriter *This = impl_from_ISAXContentHandler( iface );
640 xmlChar *s;
642 TRACE("(%p)\n", This);
644 /* If properties have been changed since the last "endDocument" call
645 * we need to reset the output buffer. If we don't the output buffer
646 * could end up with multiple XML documents in it, plus this seems to
647 * be how Windows works.
649 if (This->prop_changed) {
650 reset_output_buffer(This);
651 This->prop_changed = FALSE;
654 if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
656 /* version */
657 xmlOutputBufferWriteString(This->buffer, "<?xml version=\"");
658 s = xmlchar_from_wchar(This->version);
659 xmlOutputBufferWriteString(This->buffer, (char*)s);
660 heap_free(s);
661 xmlOutputBufferWriteString(This->buffer, "\"");
663 /* encoding */
664 xmlOutputBufferWriteString(This->buffer, " encoding=\"");
665 xmlOutputBufferWriteString(This->buffer, xmlGetCharEncodingName(This->encoding));
666 xmlOutputBufferWriteString(This->buffer, "\"");
668 /* standalone */
669 xmlOutputBufferWriteString(This->buffer, " standalone=\"");
670 if (This->props[MXWriter_Standalone] == VARIANT_TRUE)
671 xmlOutputBufferWriteString(This->buffer, "yes\"?>");
672 else
673 xmlOutputBufferWriteString(This->buffer, "no\"?>");
675 xmlOutputBufferWriteString(This->buffer, crlfA);
677 if (This->dest && This->encoding == XML_CHAR_ENCODING_UTF16LE) {
678 static const CHAR utf16BOM[] = {0xff,0xfe};
680 if (This->props[MXWriter_BOM] == VARIANT_TRUE)
681 /* Windows passes a NULL pointer as the pcbWritten parameter and
682 * ignores any error codes returned from this Write call.
684 IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
687 return S_OK;
690 static HRESULT WINAPI mxwriter_saxcontent_endDocument(ISAXContentHandler *iface)
692 mxwriter *This = impl_from_ISAXContentHandler( iface );
693 TRACE("(%p)\n", This);
694 This->prop_changed = FALSE;
695 return flush_output_buffer(This);
698 static HRESULT WINAPI mxwriter_saxcontent_startPrefixMapping(
699 ISAXContentHandler *iface,
700 const WCHAR *prefix,
701 int nprefix,
702 const WCHAR *uri,
703 int nuri)
705 mxwriter *This = impl_from_ISAXContentHandler( iface );
706 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
707 return E_NOTIMPL;
710 static HRESULT WINAPI mxwriter_saxcontent_endPrefixMapping(
711 ISAXContentHandler *iface,
712 const WCHAR *prefix,
713 int nprefix)
715 mxwriter *This = impl_from_ISAXContentHandler( iface );
716 FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
717 return E_NOTIMPL;
720 static HRESULT WINAPI mxwriter_saxcontent_startElement(
721 ISAXContentHandler *iface,
722 const WCHAR *namespaceUri,
723 int nnamespaceUri,
724 const WCHAR *local_name,
725 int nlocal_name,
726 const WCHAR *QName,
727 int nQName,
728 ISAXAttributes *attr)
730 mxwriter *This = impl_from_ISAXContentHandler( iface );
731 xmlChar *s;
733 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
734 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
736 if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
737 return E_INVALIDARG;
739 close_element_starttag(This);
740 set_element_name(This, QName ? QName : emptyW,
741 QName ? nQName : 0);
743 xmlOutputBufferWriteString(This->buffer, "<");
744 s = xmlchar_from_wcharn(QName, nQName);
745 xmlOutputBufferWriteString(This->buffer, (char*)s);
746 heap_free(s);
748 if (attr)
750 HRESULT hr;
751 INT length;
752 INT i;
754 hr = ISAXAttributes_getLength(attr, &length);
755 if (FAILED(hr)) return hr;
757 for (i = 0; i < length; i++)
759 const WCHAR *str;
760 INT len = 0;
762 hr = ISAXAttributes_getQName(attr, i, &str, &len);
763 if (FAILED(hr)) return hr;
765 /* space separator in front of every attribute */
766 xmlOutputBufferWriteString(This->buffer, " ");
768 s = xmlchar_from_wcharn(str, len);
769 xmlOutputBufferWriteString(This->buffer, (char*)s);
770 heap_free(s);
772 xmlOutputBufferWriteString(This->buffer, "=\"");
774 len = 0;
775 hr = ISAXAttributes_getValue(attr, i, &str, &len);
776 if (FAILED(hr)) return hr;
778 s = xmlchar_from_wcharn(str, len);
779 xmlOutputBufferWriteString(This->buffer, (char*)s);
780 heap_free(s);
782 xmlOutputBufferWriteString(This->buffer, "\"");
786 return S_OK;
789 static HRESULT WINAPI mxwriter_saxcontent_endElement(
790 ISAXContentHandler *iface,
791 const WCHAR *namespaceUri,
792 int nnamespaceUri,
793 const WCHAR * local_name,
794 int nlocal_name,
795 const WCHAR *QName,
796 int nQName)
798 mxwriter *This = impl_from_ISAXContentHandler( iface );
800 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(namespaceUri, nnamespaceUri), nnamespaceUri,
801 debugstr_wn(local_name, nlocal_name), nlocal_name, debugstr_wn(QName, nQName), nQName);
803 if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
804 return E_INVALIDARG;
806 if (This->element && QName && !strncmpW(This->element, QName, nQName))
808 xmlOutputBufferWriteString(This->buffer, "/>");
810 else
812 xmlChar *s = xmlchar_from_wcharn(QName, nQName);
814 xmlOutputBufferWriteString(This->buffer, "</");
815 xmlOutputBufferWriteString(This->buffer, (char*)s);
816 xmlOutputBufferWriteString(This->buffer, ">");
818 heap_free(s);
821 set_element_name(This, NULL, 0);
823 return S_OK;
826 static HRESULT WINAPI mxwriter_saxcontent_characters(
827 ISAXContentHandler *iface,
828 const WCHAR *chars,
829 int nchars)
831 mxwriter *This = impl_from_ISAXContentHandler( iface );
833 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
835 if (!chars) return E_INVALIDARG;
837 close_element_starttag(This);
838 set_element_name(This, NULL, 0);
840 if (nchars)
842 xmlChar *s = xmlchar_from_wcharn(chars, nchars);
843 xmlOutputBufferWriteString(This->buffer, (char*)s);
844 heap_free(s);
847 return S_OK;
850 static HRESULT WINAPI mxwriter_saxcontent_ignorableWhitespace(
851 ISAXContentHandler *iface,
852 const WCHAR *chars,
853 int nchars)
855 mxwriter *This = impl_from_ISAXContentHandler( iface );
856 FIXME("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
857 return E_NOTIMPL;
860 static HRESULT WINAPI mxwriter_saxcontent_processingInstruction(
861 ISAXContentHandler *iface,
862 const WCHAR *target,
863 int ntarget,
864 const WCHAR *data,
865 int ndata)
867 mxwriter *This = impl_from_ISAXContentHandler( iface );
868 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
869 return E_NOTIMPL;
872 static HRESULT WINAPI mxwriter_saxcontent_skippedEntity(
873 ISAXContentHandler *iface,
874 const WCHAR *name,
875 int nname)
877 mxwriter *This = impl_from_ISAXContentHandler( iface );
878 FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
879 return E_NOTIMPL;
882 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl =
884 mxwriter_saxcontent_QueryInterface,
885 mxwriter_saxcontent_AddRef,
886 mxwriter_saxcontent_Release,
887 mxwriter_saxcontent_putDocumentLocator,
888 mxwriter_saxcontent_startDocument,
889 mxwriter_saxcontent_endDocument,
890 mxwriter_saxcontent_startPrefixMapping,
891 mxwriter_saxcontent_endPrefixMapping,
892 mxwriter_saxcontent_startElement,
893 mxwriter_saxcontent_endElement,
894 mxwriter_saxcontent_characters,
895 mxwriter_saxcontent_ignorableWhitespace,
896 mxwriter_saxcontent_processingInstruction,
897 mxwriter_saxcontent_skippedEntity
900 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
902 static const WCHAR version10W[] = {'1','.','0',0};
903 mxwriter *This;
905 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
907 if (pUnkOuter) FIXME("support aggregation, outer\n");
909 This = heap_alloc( sizeof (*This) );
910 if(!This)
911 return E_OUTOFMEMORY;
913 This->IMXWriter_iface.lpVtbl = &mxwriter_vtbl;
914 This->ISAXContentHandler_iface.lpVtbl = &mxwriter_saxcontent_vtbl;
915 This->ref = 1;
916 This->class_version = version;
918 This->props[MXWriter_BOM] = VARIANT_TRUE;
919 This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
920 This->props[MXWriter_Indent] = VARIANT_FALSE;
921 This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
922 This->props[MXWriter_Standalone] = VARIANT_FALSE;
923 This->prop_changed = FALSE;
924 This->encoding = xmlParseCharEncoding("UTF-16");
925 This->version = SysAllocString(version10W);
927 This->element = NULL;
929 This->dest = NULL;
930 This->dest_written = 0;
932 This->buffer = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This->encoding));
934 *ppObj = &This->IMXWriter_iface;
936 TRACE("returning iface %p\n", *ppObj);
938 return S_OK;
941 #else
943 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **obj)
945 MESSAGE("This program tried to use a MXXMLWriter object, but\n"
946 "libxml2 support was not present at compile time.\n");
947 return E_NOTIMPL;
950 #endif /* HAVE_LIBXML2 */