msxml3: Use element name length passed to content handler.
[wine/testsucceed.git] / dlls / msxml3 / mxwriter.c
blobb08fd0b7ab724fbb2f74b320e8f3ae7a22d75e7a
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 inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
184 return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
187 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
189 return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
192 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
194 mxwriter *This = impl_from_IMXWriter( iface );
196 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
198 if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
199 IsEqualGUID( riid, &IID_IDispatch ) ||
200 IsEqualGUID( riid, &IID_IUnknown ) )
202 *obj = &This->IMXWriter_iface;
204 else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
206 *obj = &This->ISAXContentHandler_iface;
208 else
210 ERR("interface %s not implemented\n", debugstr_guid(riid));
211 *obj = NULL;
212 return E_NOINTERFACE;
215 IMXWriter_AddRef(iface);
216 return S_OK;
219 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
221 mxwriter *This = impl_from_IMXWriter( iface );
222 LONG ref = InterlockedIncrement(&This->ref);
224 TRACE("(%p)->(%d)\n", This, ref);
226 return ref;
229 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
231 mxwriter *This = impl_from_IMXWriter( iface );
232 ULONG ref = InterlockedDecrement(&This->ref);
234 TRACE("(%p)->(%d)\n", This, ref);
236 if(!ref)
238 /* Windows flushes the buffer when the interface is destroyed. */
239 flush_output_buffer(This);
241 if (This->dest) IStream_Release(This->dest);
242 SysFreeString(This->version);
244 xmlOutputBufferClose(This->buffer);
245 SysFreeString(This->element);
246 heap_free(This);
249 return ref;
252 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
254 mxwriter *This = impl_from_IMXWriter( iface );
256 TRACE("(%p)->(%p)\n", This, pctinfo);
258 *pctinfo = 1;
260 return S_OK;
263 static HRESULT WINAPI mxwriter_GetTypeInfo(
264 IMXWriter *iface,
265 UINT iTInfo, LCID lcid,
266 ITypeInfo** ppTInfo )
268 mxwriter *This = impl_from_IMXWriter( iface );
270 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
272 return get_typeinfo(IMXWriter_tid, ppTInfo);
275 static HRESULT WINAPI mxwriter_GetIDsOfNames(
276 IMXWriter *iface,
277 REFIID riid, LPOLESTR* rgszNames,
278 UINT cNames, LCID lcid, DISPID* rgDispId )
280 mxwriter *This = impl_from_IMXWriter( iface );
281 ITypeInfo *typeinfo;
282 HRESULT hr;
284 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
285 lcid, rgDispId);
287 if(!rgszNames || cNames == 0 || !rgDispId)
288 return E_INVALIDARG;
290 hr = get_typeinfo(IMXWriter_tid, &typeinfo);
291 if(SUCCEEDED(hr))
293 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
294 ITypeInfo_Release(typeinfo);
297 return hr;
300 static HRESULT WINAPI mxwriter_Invoke(
301 IMXWriter *iface,
302 DISPID dispIdMember, REFIID riid, LCID lcid,
303 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
304 EXCEPINFO* pExcepInfo, UINT* puArgErr )
306 mxwriter *This = impl_from_IMXWriter( iface );
307 ITypeInfo *typeinfo;
308 HRESULT hr;
310 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
311 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
313 hr = get_typeinfo(IMXWriter_tid, &typeinfo);
314 if(SUCCEEDED(hr))
316 hr = ITypeInfo_Invoke(typeinfo, &This->IMXWriter_iface, dispIdMember, wFlags,
317 pDispParams, pVarResult, pExcepInfo, puArgErr);
318 ITypeInfo_Release(typeinfo);
321 return hr;
324 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
326 mxwriter *This = impl_from_IMXWriter( iface );
327 HRESULT hr;
329 TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
331 hr = flush_output_buffer(This);
332 if (FAILED(hr))
333 return hr;
335 switch (V_VT(&dest))
337 case VT_EMPTY:
339 if (This->dest) IStream_Release(This->dest);
340 This->dest = NULL;
342 /* We need to reset the output buffer to UTF-16, since the only way
343 * the content of the mxwriter can be accessed now is through a BSTR.
345 This->encoding = xmlParseCharEncoding("UTF-16");
346 reset_output_buffer(This);
347 break;
349 case VT_UNKNOWN:
351 IStream *stream;
353 hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
354 if (hr == S_OK)
356 /* Recreate the output buffer to make sure it's using the correct encoding. */
357 reset_output_buffer(This);
359 if (This->dest) IStream_Release(This->dest);
360 This->dest = stream;
361 break;
364 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
365 return E_NOTIMPL;
367 default:
368 FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
369 return E_NOTIMPL;
372 return S_OK;
375 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
377 mxwriter *This = impl_from_IMXWriter( iface );
379 TRACE("(%p)->(%p)\n", This, dest);
381 if (!This->dest)
383 HRESULT hr = flush_output_buffer(This);
384 if (FAILED(hr))
385 return hr;
387 /* TODO: Windows always seems to re-encode the XML to UTF-16 (this includes
388 * updating the XML decl so it says "UTF-16" instead of "UTF-8"). We don't
389 * support this yet...
391 if (This->encoding == XML_CHAR_ENCODING_UTF8) {
392 FIXME("XML re-encoding not supported yet\n");
393 return E_NOTIMPL;
396 V_VT(dest) = VT_BSTR;
397 V_BSTR(dest) = SysAllocStringLen((const WCHAR*)This->buffer->conv->content,
398 This->buffer->conv->use/sizeof(WCHAR));
400 return S_OK;
402 else
403 FIXME("not implemented when stream is set up\n");
405 return E_NOTIMPL;
408 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
410 mxwriter *This = impl_from_IMXWriter( iface );
412 TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
414 /* FIXME: filter all supported encodings */
415 if (!strcmpW(encoding, utf16W) || !strcmpW(encoding, utf8W))
417 HRESULT hr;
418 LPSTR enc;
420 hr = flush_output_buffer(This);
421 if (FAILED(hr))
422 return hr;
424 enc = heap_strdupWtoA(encoding);
425 if (!enc)
426 return E_OUTOFMEMORY;
428 This->encoding = xmlParseCharEncoding(enc);
429 heap_free(enc);
431 reset_output_buffer(This);
432 return S_OK;
434 else
436 FIXME("unsupported encoding %s\n", debugstr_w(encoding));
437 return E_INVALIDARG;
441 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
443 mxwriter *This = impl_from_IMXWriter( iface );
445 TRACE("(%p)->(%p)\n", This, encoding);
447 if (!encoding) return E_POINTER;
449 return bstr_from_xmlCharEncoding(This->encoding, encoding);
452 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
454 mxwriter *This = impl_from_IMXWriter( iface );
456 TRACE("(%p)->(%d)\n", This, value);
457 This->props[MXWriter_BOM] = value;
458 This->prop_changed = TRUE;
460 return S_OK;
463 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
465 mxwriter *This = impl_from_IMXWriter( iface );
467 TRACE("(%p)->(%p)\n", This, value);
469 if (!value) return E_POINTER;
471 *value = This->props[MXWriter_BOM];
473 return S_OK;
476 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
478 mxwriter *This = impl_from_IMXWriter( iface );
480 TRACE("(%p)->(%d)\n", This, value);
481 This->props[MXWriter_Indent] = value;
482 This->prop_changed = TRUE;
484 return S_OK;
487 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
489 mxwriter *This = impl_from_IMXWriter( iface );
491 TRACE("(%p)->(%p)\n", This, value);
493 if (!value) return E_POINTER;
495 *value = This->props[MXWriter_Indent];
497 return S_OK;
500 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
502 mxwriter *This = impl_from_IMXWriter( iface );
504 TRACE("(%p)->(%d)\n", This, value);
505 This->props[MXWriter_Standalone] = value;
506 This->prop_changed = TRUE;
508 return S_OK;
511 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
513 mxwriter *This = impl_from_IMXWriter( iface );
515 TRACE("(%p)->(%p)\n", This, value);
517 if (!value) return E_POINTER;
519 *value = This->props[MXWriter_Standalone];
521 return S_OK;
524 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
526 mxwriter *This = impl_from_IMXWriter( iface );
528 TRACE("(%p)->(%d)\n", This, value);
529 This->props[MXWriter_OmitXmlDecl] = value;
530 This->prop_changed = TRUE;
532 return S_OK;
535 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
537 mxwriter *This = impl_from_IMXWriter( iface );
539 TRACE("(%p)->(%p)\n", This, value);
541 if (!value) return E_POINTER;
543 *value = This->props[MXWriter_OmitXmlDecl];
545 return S_OK;
548 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
550 mxwriter *This = impl_from_IMXWriter( iface );
552 TRACE("(%p)->(%s)\n", This, debugstr_w(version));
554 if (!version) return E_INVALIDARG;
556 SysFreeString(This->version);
557 This->version = SysAllocString(version);
559 return S_OK;
562 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
564 mxwriter *This = impl_from_IMXWriter( iface );
566 TRACE("(%p)->(%p)\n", This, version);
568 if (!version) return E_POINTER;
570 return return_bstr(This->version, version);
573 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
575 mxwriter *This = impl_from_IMXWriter( iface );
577 TRACE("(%p)->(%d)\n", This, value);
578 This->props[MXWriter_DisableEscaping] = value;
579 This->prop_changed = TRUE;
581 return S_OK;
584 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
586 mxwriter *This = impl_from_IMXWriter( iface );
588 TRACE("(%p)->(%p)\n", This, value);
590 if (!value) return E_POINTER;
592 *value = This->props[MXWriter_DisableEscaping];
594 return S_OK;
597 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
599 mxwriter *This = impl_from_IMXWriter( iface );
600 TRACE("(%p)\n", This);
601 return flush_output_buffer(This);
604 static const struct IMXWriterVtbl mxwriter_vtbl =
606 mxwriter_QueryInterface,
607 mxwriter_AddRef,
608 mxwriter_Release,
609 mxwriter_GetTypeInfoCount,
610 mxwriter_GetTypeInfo,
611 mxwriter_GetIDsOfNames,
612 mxwriter_Invoke,
613 mxwriter_put_output,
614 mxwriter_get_output,
615 mxwriter_put_encoding,
616 mxwriter_get_encoding,
617 mxwriter_put_byteOrderMark,
618 mxwriter_get_byteOrderMark,
619 mxwriter_put_indent,
620 mxwriter_get_indent,
621 mxwriter_put_standalone,
622 mxwriter_get_standalone,
623 mxwriter_put_omitXMLDeclaration,
624 mxwriter_get_omitXMLDeclaration,
625 mxwriter_put_version,
626 mxwriter_get_version,
627 mxwriter_put_disableOutputEscaping,
628 mxwriter_get_disableOutputEscaping,
629 mxwriter_flush
632 /*** ISAXContentHandler ***/
633 static HRESULT WINAPI mxwriter_saxcontent_QueryInterface(
634 ISAXContentHandler *iface,
635 REFIID riid,
636 void **obj)
638 mxwriter *This = impl_from_ISAXContentHandler( iface );
639 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
642 static ULONG WINAPI mxwriter_saxcontent_AddRef(ISAXContentHandler *iface)
644 mxwriter *This = impl_from_ISAXContentHandler( iface );
645 return IMXWriter_AddRef(&This->IMXWriter_iface);
648 static ULONG WINAPI mxwriter_saxcontent_Release(ISAXContentHandler *iface)
650 mxwriter *This = impl_from_ISAXContentHandler( iface );
651 return IMXWriter_Release(&This->IMXWriter_iface);
654 static HRESULT WINAPI mxwriter_saxcontent_putDocumentLocator(
655 ISAXContentHandler *iface,
656 ISAXLocator *locator)
658 mxwriter *This = impl_from_ISAXContentHandler( iface );
659 FIXME("(%p)->(%p)\n", This, locator);
660 return E_NOTIMPL;
663 static HRESULT WINAPI mxwriter_saxcontent_startDocument(ISAXContentHandler *iface)
665 mxwriter *This = impl_from_ISAXContentHandler( iface );
666 xmlChar *s;
668 TRACE("(%p)\n", This);
670 /* If properties have been changed since the last "endDocument" call
671 * we need to reset the output buffer. If we don't the output buffer
672 * could end up with multiple XML documents in it, plus this seems to
673 * be how Windows works.
675 if (This->prop_changed) {
676 reset_output_buffer(This);
677 This->prop_changed = FALSE;
680 if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
682 /* version */
683 xmlOutputBufferWriteString(This->buffer, "<?xml version=\"");
684 s = xmlchar_from_wchar(This->version);
685 xmlOutputBufferWriteString(This->buffer, (char*)s);
686 heap_free(s);
687 xmlOutputBufferWriteString(This->buffer, "\"");
689 /* encoding */
690 xmlOutputBufferWriteString(This->buffer, " encoding=\"");
691 xmlOutputBufferWriteString(This->buffer, xmlGetCharEncodingName(This->encoding));
692 xmlOutputBufferWriteString(This->buffer, "\"");
694 /* standalone */
695 xmlOutputBufferWriteString(This->buffer, " standalone=\"");
696 if (This->props[MXWriter_Standalone] == VARIANT_TRUE)
697 xmlOutputBufferWriteString(This->buffer, "yes\"?>");
698 else
699 xmlOutputBufferWriteString(This->buffer, "no\"?>");
701 xmlOutputBufferWriteString(This->buffer, crlfA);
703 if (This->dest && This->encoding == XML_CHAR_ENCODING_UTF16LE) {
704 static const CHAR utf16BOM[] = {0xff,0xfe};
706 if (This->props[MXWriter_BOM] == VARIANT_TRUE)
707 /* Windows passes a NULL pointer as the pcbWritten parameter and
708 * ignores any error codes returned from this Write call.
710 IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
713 return S_OK;
716 static HRESULT WINAPI mxwriter_saxcontent_endDocument(ISAXContentHandler *iface)
718 mxwriter *This = impl_from_ISAXContentHandler( iface );
719 TRACE("(%p)\n", This);
720 This->prop_changed = FALSE;
721 return flush_output_buffer(This);
724 static HRESULT WINAPI mxwriter_saxcontent_startPrefixMapping(
725 ISAXContentHandler *iface,
726 const WCHAR *prefix,
727 int nprefix,
728 const WCHAR *uri,
729 int nuri)
731 mxwriter *This = impl_from_ISAXContentHandler( iface );
732 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
733 return E_NOTIMPL;
736 static HRESULT WINAPI mxwriter_saxcontent_endPrefixMapping(
737 ISAXContentHandler *iface,
738 const WCHAR *prefix,
739 int nprefix)
741 mxwriter *This = impl_from_ISAXContentHandler( iface );
742 FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
743 return E_NOTIMPL;
746 static HRESULT WINAPI mxwriter_saxcontent_startElement(
747 ISAXContentHandler *iface,
748 const WCHAR *namespaceUri,
749 int nnamespaceUri,
750 const WCHAR *local_name,
751 int nlocal_name,
752 const WCHAR *QName,
753 int nQName,
754 ISAXAttributes *attr)
756 mxwriter *This = impl_from_ISAXContentHandler( iface );
757 xmlChar *s;
759 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
760 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
762 if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
763 return E_INVALIDARG;
765 close_element_starttag(This);
766 set_element_name(This, QName ? QName : emptyW,
767 QName ? nQName : 0);
769 xmlOutputBufferWriteString(This->buffer, "<");
770 s = xmlchar_from_wcharn(QName, nQName);
771 xmlOutputBufferWriteString(This->buffer, (char*)s);
772 heap_free(s);
774 if (attr)
776 HRESULT hr;
777 INT length;
778 INT i;
780 hr = ISAXAttributes_getLength(attr, &length);
781 if (FAILED(hr)) return hr;
783 for (i = 0; i < length; i++)
785 const WCHAR *str;
786 INT len = 0;
788 hr = ISAXAttributes_getQName(attr, i, &str, &len);
789 if (FAILED(hr)) return hr;
791 /* space separator in front of every attribute */
792 xmlOutputBufferWriteString(This->buffer, " ");
794 s = xmlchar_from_wcharn(str, len);
795 xmlOutputBufferWriteString(This->buffer, (char*)s);
796 heap_free(s);
798 xmlOutputBufferWriteString(This->buffer, "=\"");
800 len = 0;
801 hr = ISAXAttributes_getValue(attr, i, &str, &len);
802 if (FAILED(hr)) return hr;
804 s = xmlchar_from_wcharn(str, len);
805 xmlOutputBufferWriteString(This->buffer, (char*)s);
806 heap_free(s);
808 xmlOutputBufferWriteString(This->buffer, "\"");
812 return S_OK;
815 static HRESULT WINAPI mxwriter_saxcontent_endElement(
816 ISAXContentHandler *iface,
817 const WCHAR *namespaceUri,
818 int nnamespaceUri,
819 const WCHAR * local_name,
820 int nlocal_name,
821 const WCHAR *QName,
822 int nQName)
824 mxwriter *This = impl_from_ISAXContentHandler( iface );
825 xmlChar *s;
827 TRACE("(%p)->(%s %s %s)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
828 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName));
830 if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
831 return E_INVALIDARG;
833 s = xmlchar_from_wchar(QName);
835 if (This->element && QName && !strcmpW(This->element, QName))
837 xmlOutputBufferWriteString(This->buffer, "/>");
839 else
841 xmlOutputBufferWriteString(This->buffer, "</");
842 xmlOutputBufferWriteString(This->buffer, (char*)s);
843 xmlOutputBufferWriteString(This->buffer, ">");
846 heap_free(s);
847 set_element_name(This, NULL, 0);
849 return S_OK;
852 static HRESULT WINAPI mxwriter_saxcontent_characters(
853 ISAXContentHandler *iface,
854 const WCHAR *chars,
855 int nchars)
857 mxwriter *This = impl_from_ISAXContentHandler( iface );
859 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
861 if (!chars) return E_INVALIDARG;
863 close_element_starttag(This);
864 set_element_name(This, NULL, 0);
866 if (nchars)
868 xmlChar *s = xmlchar_from_wcharn(chars, nchars);
869 xmlOutputBufferWriteString(This->buffer, (char*)s);
870 heap_free(s);
873 return S_OK;
876 static HRESULT WINAPI mxwriter_saxcontent_ignorableWhitespace(
877 ISAXContentHandler *iface,
878 const WCHAR *chars,
879 int nchars)
881 mxwriter *This = impl_from_ISAXContentHandler( iface );
882 FIXME("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
883 return E_NOTIMPL;
886 static HRESULT WINAPI mxwriter_saxcontent_processingInstruction(
887 ISAXContentHandler *iface,
888 const WCHAR *target,
889 int ntarget,
890 const WCHAR *data,
891 int ndata)
893 mxwriter *This = impl_from_ISAXContentHandler( iface );
894 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
895 return E_NOTIMPL;
898 static HRESULT WINAPI mxwriter_saxcontent_skippedEntity(
899 ISAXContentHandler *iface,
900 const WCHAR *name,
901 int nname)
903 mxwriter *This = impl_from_ISAXContentHandler( iface );
904 FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
905 return E_NOTIMPL;
908 static const struct ISAXContentHandlerVtbl mxwriter_saxcontent_vtbl =
910 mxwriter_saxcontent_QueryInterface,
911 mxwriter_saxcontent_AddRef,
912 mxwriter_saxcontent_Release,
913 mxwriter_saxcontent_putDocumentLocator,
914 mxwriter_saxcontent_startDocument,
915 mxwriter_saxcontent_endDocument,
916 mxwriter_saxcontent_startPrefixMapping,
917 mxwriter_saxcontent_endPrefixMapping,
918 mxwriter_saxcontent_startElement,
919 mxwriter_saxcontent_endElement,
920 mxwriter_saxcontent_characters,
921 mxwriter_saxcontent_ignorableWhitespace,
922 mxwriter_saxcontent_processingInstruction,
923 mxwriter_saxcontent_skippedEntity
926 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
928 static const WCHAR version10W[] = {'1','.','0',0};
929 mxwriter *This;
931 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
933 if (pUnkOuter) FIXME("support aggregation, outer\n");
935 This = heap_alloc( sizeof (*This) );
936 if(!This)
937 return E_OUTOFMEMORY;
939 This->IMXWriter_iface.lpVtbl = &mxwriter_vtbl;
940 This->ISAXContentHandler_iface.lpVtbl = &mxwriter_saxcontent_vtbl;
941 This->ref = 1;
942 This->class_version = version;
944 This->props[MXWriter_BOM] = VARIANT_TRUE;
945 This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
946 This->props[MXWriter_Indent] = VARIANT_FALSE;
947 This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
948 This->props[MXWriter_Standalone] = VARIANT_FALSE;
949 This->prop_changed = FALSE;
950 This->encoding = xmlParseCharEncoding("UTF-16");
951 This->version = SysAllocString(version10W);
953 This->element = NULL;
955 This->dest = NULL;
956 This->dest_written = 0;
958 This->buffer = xmlAllocOutputBuffer(xmlGetCharEncodingHandler(This->encoding));
960 *ppObj = &This->IMXWriter_iface;
962 TRACE("returning iface %p\n", *ppObj);
964 return S_OK;
967 #else
969 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **obj)
971 MESSAGE("This program tried to use a MXXMLWriter object, but\n"
972 "libxml2 support was not present at compile time.\n");
973 return E_NOTIMPL;
976 #endif /* HAVE_LIBXML2 */