dmloader: Don't claim partial success when loading fails.
[wine] / dlls / msxml3 / mxwriter.c
1 /*
2  *    MXWriter implementation
3  *
4  * Copyright 2011-2012 Nikolay Sivov for CodeWeavers
5  * Copyright 2011 Thomas Mullaly
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #define COBJMACROS
23 #include "config.h"
24
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 #endif
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "ole2.h"
33
34 #include "msxml6.h"
35
36 #include "wine/debug.h"
37
38 #include "msxml_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
41
42 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
43 static const WCHAR emptyW[] = {0};
44 static const WCHAR spaceW[] = {' '};
45 static const WCHAR quotW[]  = {'\"'};
46
47 typedef enum
48 {
49     XmlEncoding_UTF8,
50     XmlEncoding_UTF16,
51     XmlEncoding_Unknown
52 } xml_encoding;
53
54 typedef enum
55 {
56     OutputBuffer_Native  = 0x001,
57     OutputBuffer_Encoded = 0x010,
58     OutputBuffer_Both    = 0x100
59 } output_mode;
60
61 typedef enum
62 {
63     MXWriter_BOM = 0,
64     MXWriter_DisableEscaping,
65     MXWriter_Indent,
66     MXWriter_OmitXmlDecl,
67     MXWriter_Standalone,
68     MXWriter_LastProp
69 } mxwriter_prop;
70
71 typedef enum
72 {
73     EscapeValue,
74     EscapeText
75 } escape_mode;
76
77 typedef struct
78 {
79     char *data;
80     unsigned int allocated;
81     unsigned int written;
82 } encoded_buffer;
83
84 typedef struct
85 {
86     encoded_buffer utf16;
87     encoded_buffer encoded;
88     UINT code_page;
89 } output_buffer;
90
91 typedef struct
92 {
93     DispatchEx dispex;
94     IMXWriter IMXWriter_iface;
95     ISAXContentHandler ISAXContentHandler_iface;
96     ISAXLexicalHandler ISAXLexicalHandler_iface;
97     ISAXDeclHandler    ISAXDeclHandler_iface;
98
99     LONG ref;
100     MSXML_VERSION class_version;
101
102     VARIANT_BOOL props[MXWriter_LastProp];
103     BOOL prop_changed;
104     BOOL cdata;
105
106     BSTR version;
107
108     BSTR encoding; /* exact property value */
109     xml_encoding xml_enc;
110
111     /* contains a pending (or not closed yet) element name or NULL if
112        we don't have to close */
113     BSTR element;
114
115     IStream *dest;
116     ULONG dest_written;
117
118     output_buffer *buffer;
119 } mxwriter;
120
121 typedef struct
122 {
123     BSTR qname;
124     BSTR local;
125     BSTR uri;
126     BSTR type;
127     BSTR value;
128 } mxattribute;
129
130 typedef struct
131 {
132     DispatchEx dispex;
133     IMXAttributes IMXAttributes_iface;
134     ISAXAttributes ISAXAttributes_iface;
135     IVBSAXAttributes IVBSAXAttributes_iface;
136     LONG ref;
137
138     MSXML_VERSION class_version;
139
140     mxattribute *attr;
141     int length;
142     int allocated;
143 } mxattributes;
144
145 static inline mxattributes *impl_from_IMXAttributes( IMXAttributes *iface )
146 {
147     return CONTAINING_RECORD(iface, mxattributes, IMXAttributes_iface);
148 }
149
150 static inline mxattributes *impl_from_ISAXAttributes( ISAXAttributes *iface )
151 {
152     return CONTAINING_RECORD(iface, mxattributes, ISAXAttributes_iface);
153 }
154
155 static inline mxattributes *impl_from_IVBSAXAttributes( IVBSAXAttributes *iface )
156 {
157     return CONTAINING_RECORD(iface, mxattributes, IVBSAXAttributes_iface);
158 }
159
160 static HRESULT mxattributes_grow(mxattributes *This)
161 {
162     if (This->length < This->allocated) return S_OK;
163
164     This->allocated *= 2;
165     This->attr = heap_realloc(This->attr, This->allocated*sizeof(mxattribute));
166
167     return This->attr ? S_OK : E_OUTOFMEMORY;
168 }
169
170 static xml_encoding parse_encoding_name(const WCHAR *encoding)
171 {
172     static const WCHAR utf8W[]  = {'U','T','F','-','8',0};
173     if (!strcmpiW(encoding, utf8W))  return XmlEncoding_UTF8;
174     if (!strcmpiW(encoding, utf16W)) return XmlEncoding_UTF16;
175     return XmlEncoding_Unknown;
176 }
177
178 static HRESULT init_encoded_buffer(encoded_buffer *buffer)
179 {
180     const int initial_len = 0x2000;
181     buffer->data = heap_alloc(initial_len);
182     if (!buffer->data) return E_OUTOFMEMORY;
183
184     memset(buffer->data, 0, 4);
185     buffer->allocated = initial_len;
186     buffer->written = 0;
187
188     return S_OK;
189 }
190
191 static void free_encoded_buffer(encoded_buffer *buffer)
192 {
193     heap_free(buffer->data);
194 }
195
196 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
197 {
198     switch (encoding)
199     {
200     case XmlEncoding_UTF8:
201         *cp = CP_UTF8;
202         break;
203     case XmlEncoding_UTF16:
204         *cp = ~0;
205         break;
206     default:
207         FIXME("unsupported encoding %d\n", encoding);
208         return E_NOTIMPL;
209     }
210
211     return S_OK;
212 }
213
214 static HRESULT alloc_output_buffer(xml_encoding encoding, output_buffer **buffer)
215 {
216     output_buffer *ret;
217     HRESULT hr;
218
219     ret = heap_alloc(sizeof(*ret));
220     if (!ret) return E_OUTOFMEMORY;
221
222     hr = get_code_page(encoding, &ret->code_page);
223     if (hr != S_OK) {
224         heap_free(ret);
225         return hr;
226     }
227
228     hr = init_encoded_buffer(&ret->utf16);
229     if (hr != S_OK) {
230         heap_free(ret);
231         return hr;
232     }
233
234     if (ret->code_page == CP_UTF8) {
235         hr = init_encoded_buffer(&ret->encoded);
236         if (hr != S_OK) {
237             free_encoded_buffer(&ret->utf16);
238             heap_free(ret);
239             return hr;
240         }
241     }
242     else
243         memset(&ret->encoded, 0, sizeof(ret->encoded));
244
245     *buffer = ret;
246
247     return S_OK;
248 }
249
250 static void free_output_buffer(output_buffer *buffer)
251 {
252     free_encoded_buffer(&buffer->encoded);
253     free_encoded_buffer(&buffer->utf16);
254     heap_free(buffer);
255 }
256
257 static void grow_buffer(encoded_buffer *buffer, int length)
258 {
259     /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
260     if (buffer->allocated < buffer->written + length + 4)
261     {
262         int grown_size = max(2*buffer->allocated, buffer->allocated + length);
263         buffer->data = heap_realloc(buffer->data, grown_size);
264         buffer->allocated = grown_size;
265     }
266 }
267
268 static HRESULT write_output_buffer_mode(output_buffer *buffer, output_mode mode, const WCHAR *data, int len)
269 {
270     int length;
271     char *ptr;
272
273     if (mode & (OutputBuffer_Encoded | OutputBuffer_Both)) {
274         if (buffer->code_page == CP_UTF8)
275         {
276             length = WideCharToMultiByte(buffer->code_page, 0, data, len, NULL, 0, NULL, NULL);
277             grow_buffer(&buffer->encoded, length);
278             ptr = buffer->encoded.data + buffer->encoded.written;
279             length = WideCharToMultiByte(buffer->code_page, 0, data, len, ptr, length, NULL, NULL);
280             buffer->encoded.written += len == -1 ? length-1 : length;
281         }
282     }
283
284     if (mode & (OutputBuffer_Native | OutputBuffer_Both)) {
285         /* WCHAR data just copied */
286         length = len == -1 ? strlenW(data) : len;
287         if (length)
288         {
289             length *= sizeof(WCHAR);
290
291             grow_buffer(&buffer->utf16, length);
292             ptr = buffer->utf16.data + buffer->utf16.written;
293
294             memcpy(ptr, data, length);
295             buffer->utf16.written += length;
296             ptr += length;
297             /* null termination */
298             memset(ptr, 0, sizeof(WCHAR));
299         }
300     }
301
302     return S_OK;
303 }
304
305 static HRESULT write_output_buffer(output_buffer *buffer, const WCHAR *data, int len)
306 {
307     return write_output_buffer_mode(buffer, OutputBuffer_Both, data, len);
308 }
309
310 static HRESULT write_output_buffer_quoted(output_buffer *buffer, const WCHAR *data, int len)
311 {
312     write_output_buffer(buffer, quotW, 1);
313     write_output_buffer(buffer, data, len);
314     write_output_buffer(buffer, quotW, 1);
315
316     return S_OK;
317 }
318
319 /* frees buffer data, reallocates with a default lengths */
320 static void close_output_buffer(mxwriter *This)
321 {
322     heap_free(This->buffer->utf16.data);
323     heap_free(This->buffer->encoded.data);
324     init_encoded_buffer(&This->buffer->utf16);
325     init_encoded_buffer(&This->buffer->encoded);
326     get_code_page(This->xml_enc, &This->buffer->code_page);
327 }
328
329 /* escapes special characters like:
330    '<' -> "&lt;"
331    '&' -> "&amp;"
332    '"' -> "&quot;"
333    '>' -> "&gt;"
334 */
335 static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len)
336 {
337     static const WCHAR ltW[]    = {'&','l','t',';'};
338     static const WCHAR ampW[]   = {'&','a','m','p',';'};
339     static const WCHAR equotW[] = {'&','q','u','o','t',';'};
340     static const WCHAR gtW[]    = {'&','g','t',';'};
341
342     const int default_alloc = 100;
343     const int grow_thresh = 10;
344     int p = *len, conv_len;
345     WCHAR *ptr, *ret;
346
347     /* default buffer size to something if length is unknown */
348     conv_len = *len == -1 ? default_alloc : max(2**len, default_alloc);
349     ptr = ret = heap_alloc(conv_len*sizeof(WCHAR));
350
351     while (*str && p)
352     {
353         if (ptr - ret > conv_len - grow_thresh)
354         {
355             int written = ptr - ret;
356             conv_len *= 2;
357             ptr = ret = heap_realloc(ret, conv_len*sizeof(WCHAR));
358             ptr += written;
359         }
360
361         switch (*str)
362         {
363         case '<':
364             memcpy(ptr, ltW, sizeof(ltW));
365             ptr += sizeof(ltW)/sizeof(WCHAR);
366             break;
367         case '&':
368             memcpy(ptr, ampW, sizeof(ampW));
369             ptr += sizeof(ampW)/sizeof(WCHAR);
370             break;
371         case '>':
372             memcpy(ptr, gtW, sizeof(gtW));
373             ptr += sizeof(gtW)/sizeof(WCHAR);
374             break;
375         case '"':
376             if (mode == EscapeValue)
377             {
378                 memcpy(ptr, equotW, sizeof(equotW));
379                 ptr += sizeof(equotW)/sizeof(WCHAR);
380                 break;
381             }
382             /* fallthrough for text mode */
383         default:
384             *ptr++ = *str;
385             break;
386         }
387
388         str++;
389         if (*len != -1) p--;
390     }
391
392     if (*len != -1) *len = ptr-ret;
393     *++ptr = 0;
394
395     return ret;
396 }
397
398 static void write_prolog_buffer(const mxwriter *This)
399 {
400     static const WCHAR versionW[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','='};
401     static const WCHAR encodingW[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
402     static const WCHAR standaloneW[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
403     static const WCHAR yesW[] = {'y','e','s','\"','?','>'};
404     static const WCHAR noW[] = {'n','o','\"','?','>'};
405     static const WCHAR crlfW[] = {'\r','\n'};
406
407     /* version */
408     write_output_buffer(This->buffer, versionW, sizeof(versionW)/sizeof(WCHAR));
409     write_output_buffer_quoted(This->buffer, This->version, -1);
410
411     /* encoding */
412     write_output_buffer(This->buffer, encodingW, sizeof(encodingW)/sizeof(WCHAR));
413
414     /* always write UTF-16 to WCHAR buffer */
415     write_output_buffer_mode(This->buffer, OutputBuffer_Native, utf16W, sizeof(utf16W)/sizeof(WCHAR) - 1);
416     write_output_buffer_mode(This->buffer, OutputBuffer_Encoded, This->encoding, -1);
417     write_output_buffer(This->buffer, quotW, 1);
418
419     /* standalone */
420     write_output_buffer(This->buffer, standaloneW, sizeof(standaloneW)/sizeof(WCHAR));
421     if (This->props[MXWriter_Standalone] == VARIANT_TRUE)
422         write_output_buffer(This->buffer, yesW, sizeof(yesW)/sizeof(WCHAR));
423     else
424         write_output_buffer(This->buffer, noW, sizeof(noW)/sizeof(WCHAR));
425
426     write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR));
427 }
428
429 /* Attempts to the write data from the mxwriter's buffer to
430  * the destination stream (if there is one).
431  */
432 static HRESULT write_data_to_stream(mxwriter *This)
433 {
434     encoded_buffer *buffer;
435     ULONG written = 0;
436     HRESULT hr;
437
438     if (!This->dest)
439         return S_OK;
440
441     if (This->xml_enc != XmlEncoding_UTF16)
442         buffer = &This->buffer->encoded;
443     else
444         buffer = &This->buffer->utf16;
445
446     if (This->dest_written > buffer->written) {
447         ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This->dest_written, buffer->written);
448         return E_FAIL;
449     } else if (This->dest_written == buffer->written && This->xml_enc != XmlEncoding_UTF8)
450         /* Windows seems to make an empty write call when the encoding is UTF-8 and
451          * all the data has been written to the stream. It doesn't seem make this call
452          * for any other encodings.
453          */
454         return S_OK;
455
456     /* Write the current content from the output buffer into 'dest'.
457      * TODO: Check what Windows does if the IStream doesn't write all of
458      *       the data we give it at once.
459      */
460     hr = IStream_Write(This->dest, buffer->data+This->dest_written,
461                          buffer->written-This->dest_written, &written);
462     if (FAILED(hr)) {
463         WARN("Failed to write data to IStream (0x%08x)\n", hr);
464         return hr;
465     }
466
467     This->dest_written += written;
468     return hr;
469 }
470
471 /* Newly added element start tag left unclosed cause for empty elements
472    we have to close it differently. */
473 static void close_element_starttag(const mxwriter *This)
474 {
475     static const WCHAR gtW[] = {'>'};
476     if (!This->element) return;
477     write_output_buffer(This->buffer, gtW, 1);
478 }
479
480 static void set_element_name(mxwriter *This, const WCHAR *name, int len)
481 {
482     SysFreeString(This->element);
483     This->element = name ? SysAllocStringLen(name, len) : NULL;
484 }
485
486 static inline HRESULT flush_output_buffer(mxwriter *This)
487 {
488     close_element_starttag(This);
489     set_element_name(This, NULL, 0);
490     This->cdata = FALSE;
491     return write_data_to_stream(This);
492 }
493
494 /* Resets the mxwriter's output buffer by closing it, then creating a new
495  * output buffer using the given encoding.
496  */
497 static inline void reset_output_buffer(mxwriter *This)
498 {
499     close_output_buffer(This);
500     This->dest_written = 0;
501 }
502
503 static HRESULT writer_set_property(mxwriter *writer, mxwriter_prop property, VARIANT_BOOL value)
504 {
505     writer->props[property] = value;
506     writer->prop_changed = TRUE;
507     return S_OK;
508 }
509
510 static HRESULT writer_get_property(const mxwriter *writer, mxwriter_prop property, VARIANT_BOOL *value)
511 {
512     if (!value) return E_POINTER;
513     *value = writer->props[property];
514     return S_OK;
515 }
516
517 static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
518 {
519     return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
520 }
521
522 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
523 {
524     return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
525 }
526
527 static inline mxwriter *impl_from_ISAXLexicalHandler(ISAXLexicalHandler *iface)
528 {
529     return CONTAINING_RECORD(iface, mxwriter, ISAXLexicalHandler_iface);
530 }
531
532 static inline mxwriter *impl_from_ISAXDeclHandler(ISAXDeclHandler *iface)
533 {
534     return CONTAINING_RECORD(iface, mxwriter, ISAXDeclHandler_iface);
535 }
536
537 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
538 {
539     mxwriter *This = impl_from_IMXWriter( iface );
540
541     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
542
543     *obj = NULL;
544
545     if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
546          IsEqualGUID( riid, &IID_IDispatch ) ||
547          IsEqualGUID( riid, &IID_IUnknown ) )
548     {
549         *obj = &This->IMXWriter_iface;
550     }
551     else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
552     {
553         *obj = &This->ISAXContentHandler_iface;
554     }
555     else if ( IsEqualGUID( riid, &IID_ISAXLexicalHandler ) )
556     {
557         *obj = &This->ISAXLexicalHandler_iface;
558     }
559     else if ( IsEqualGUID( riid, &IID_ISAXDeclHandler ) )
560     {
561         *obj = &This->ISAXDeclHandler_iface;
562     }
563     else if (dispex_query_interface(&This->dispex, riid, obj))
564     {
565         return *obj ? S_OK : E_NOINTERFACE;
566     }
567     else
568     {
569         ERR("interface %s not implemented\n", debugstr_guid(riid));
570         *obj = NULL;
571         return E_NOINTERFACE;
572     }
573
574     IMXWriter_AddRef(iface);
575     return S_OK;
576 }
577
578 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
579 {
580     mxwriter *This = impl_from_IMXWriter( iface );
581     LONG ref = InterlockedIncrement(&This->ref);
582
583     TRACE("(%p)->(%d)\n", This, ref);
584
585     return ref;
586 }
587
588 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
589 {
590     mxwriter *This = impl_from_IMXWriter( iface );
591     ULONG ref = InterlockedDecrement(&This->ref);
592
593     TRACE("(%p)->(%d)\n", This, ref);
594
595     if(!ref)
596     {
597         /* Windows flushes the buffer when the interface is destroyed. */
598         flush_output_buffer(This);
599         free_output_buffer(This->buffer);
600
601         if (This->dest) IStream_Release(This->dest);
602         SysFreeString(This->version);
603         SysFreeString(This->encoding);
604
605         SysFreeString(This->element);
606         release_dispex(&This->dispex);
607         heap_free(This);
608     }
609
610     return ref;
611 }
612
613 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
614 {
615     mxwriter *This = impl_from_IMXWriter( iface );
616     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
617 }
618
619 static HRESULT WINAPI mxwriter_GetTypeInfo(
620     IMXWriter *iface,
621     UINT iTInfo, LCID lcid,
622     ITypeInfo** ppTInfo )
623 {
624     mxwriter *This = impl_from_IMXWriter( iface );
625     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
626         iTInfo, lcid, ppTInfo);
627 }
628
629 static HRESULT WINAPI mxwriter_GetIDsOfNames(
630     IMXWriter *iface,
631     REFIID riid, LPOLESTR* rgszNames,
632     UINT cNames, LCID lcid, DISPID* rgDispId )
633 {
634     mxwriter *This = impl_from_IMXWriter( iface );
635     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
636         riid, rgszNames, cNames, lcid, rgDispId);
637 }
638
639 static HRESULT WINAPI mxwriter_Invoke(
640     IMXWriter *iface,
641     DISPID dispIdMember, REFIID riid, LCID lcid,
642     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
643     EXCEPINFO* pExcepInfo, UINT* puArgErr )
644 {
645     mxwriter *This = impl_from_IMXWriter( iface );
646     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
647         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
648 }
649
650 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
651 {
652     mxwriter *This = impl_from_IMXWriter( iface );
653     HRESULT hr;
654
655     TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
656
657     hr = flush_output_buffer(This);
658     if (FAILED(hr))
659         return hr;
660
661     switch (V_VT(&dest))
662     {
663     case VT_EMPTY:
664     {
665         if (This->dest) IStream_Release(This->dest);
666         This->dest = NULL;
667         reset_output_buffer(This);
668         break;
669     }
670     case VT_UNKNOWN:
671     {
672         IStream *stream;
673
674         hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
675         if (hr == S_OK)
676         {
677             /* Recreate the output buffer to make sure it's using the correct encoding. */
678             reset_output_buffer(This);
679
680             if (This->dest) IStream_Release(This->dest);
681             This->dest = stream;
682             break;
683         }
684
685         FIXME("unhandled interface type for VT_UNKNOWN destination\n");
686         return E_NOTIMPL;
687     }
688     default:
689         FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
690         return E_NOTIMPL;
691     }
692
693     return S_OK;
694 }
695
696 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
697 {
698     mxwriter *This = impl_from_IMXWriter( iface );
699
700     TRACE("(%p)->(%p)\n", This, dest);
701
702     if (!This->dest)
703     {
704         HRESULT hr = flush_output_buffer(This);
705         if (FAILED(hr))
706             return hr;
707
708         V_VT(dest)   = VT_BSTR;
709         V_BSTR(dest) = SysAllocString((WCHAR*)This->buffer->utf16.data);
710
711         return S_OK;
712     }
713     else
714         FIXME("not implemented when stream is set up\n");
715
716     return E_NOTIMPL;
717 }
718
719 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
720 {
721     mxwriter *This = impl_from_IMXWriter( iface );
722     xml_encoding enc;
723     HRESULT hr;
724
725     TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
726
727     enc = parse_encoding_name(encoding);
728     if (enc == XmlEncoding_Unknown)
729     {
730         FIXME("unsupported encoding %s\n", debugstr_w(encoding));
731         return E_INVALIDARG;
732     }
733
734     hr = flush_output_buffer(This);
735     if (FAILED(hr))
736         return hr;
737
738     SysReAllocString(&This->encoding, encoding);
739     This->xml_enc = enc;
740
741     TRACE("got encoding %d\n", This->xml_enc);
742     reset_output_buffer(This);
743     return S_OK;
744 }
745
746 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
747 {
748     mxwriter *This = impl_from_IMXWriter( iface );
749
750     TRACE("(%p)->(%p)\n", This, encoding);
751
752     if (!encoding) return E_POINTER;
753
754     *encoding = SysAllocString(This->encoding);
755     if (!*encoding) return E_OUTOFMEMORY;
756
757     return S_OK;
758 }
759
760 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
761 {
762     mxwriter *This = impl_from_IMXWriter( iface );
763
764     TRACE("(%p)->(%d)\n", This, value);
765     return writer_set_property(This, MXWriter_BOM, value);
766 }
767
768 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
769 {
770     mxwriter *This = impl_from_IMXWriter( iface );
771
772     TRACE("(%p)->(%p)\n", This, value);
773     return writer_get_property(This, MXWriter_BOM, value);
774 }
775
776 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
777 {
778     mxwriter *This = impl_from_IMXWriter( iface );
779
780     TRACE("(%p)->(%d)\n", This, value);
781     return writer_set_property(This, MXWriter_Indent, value);
782 }
783
784 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
785 {
786     mxwriter *This = impl_from_IMXWriter( iface );
787
788     TRACE("(%p)->(%p)\n", This, value);
789     return writer_get_property(This, MXWriter_Indent, value);
790 }
791
792 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
793 {
794     mxwriter *This = impl_from_IMXWriter( iface );
795
796     TRACE("(%p)->(%d)\n", This, value);
797     return writer_set_property(This, MXWriter_Standalone, value);
798 }
799
800 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
801 {
802     mxwriter *This = impl_from_IMXWriter( iface );
803
804     TRACE("(%p)->(%p)\n", This, value);
805     return writer_get_property(This, MXWriter_Standalone, value);
806 }
807
808 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
809 {
810     mxwriter *This = impl_from_IMXWriter( iface );
811
812     TRACE("(%p)->(%d)\n", This, value);
813     return writer_set_property(This, MXWriter_OmitXmlDecl, value);
814 }
815
816 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
817 {
818     mxwriter *This = impl_from_IMXWriter( iface );
819
820     TRACE("(%p)->(%p)\n", This, value);
821     return writer_get_property(This, MXWriter_OmitXmlDecl, value);
822 }
823
824 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
825 {
826     mxwriter *This = impl_from_IMXWriter( iface );
827
828     TRACE("(%p)->(%s)\n", This, debugstr_w(version));
829
830     if (!version) return E_INVALIDARG;
831
832     SysFreeString(This->version);
833     This->version = SysAllocString(version);
834
835     return S_OK;
836 }
837
838 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
839 {
840     mxwriter *This = impl_from_IMXWriter( iface );
841
842     TRACE("(%p)->(%p)\n", This, version);
843
844     if (!version) return E_POINTER;
845
846     return return_bstr(This->version, version);
847 }
848
849 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
850 {
851     mxwriter *This = impl_from_IMXWriter( iface );
852
853     TRACE("(%p)->(%d)\n", This, value);
854     return writer_set_property(This, MXWriter_DisableEscaping, value);
855 }
856
857 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
858 {
859     mxwriter *This = impl_from_IMXWriter( iface );
860
861     TRACE("(%p)->(%p)\n", This, value);
862     return writer_get_property(This, MXWriter_DisableEscaping, value);
863 }
864
865 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
866 {
867     mxwriter *This = impl_from_IMXWriter( iface );
868     TRACE("(%p)\n", This);
869     return flush_output_buffer(This);
870 }
871
872 static const struct IMXWriterVtbl MXWriterVtbl =
873 {
874     mxwriter_QueryInterface,
875     mxwriter_AddRef,
876     mxwriter_Release,
877     mxwriter_GetTypeInfoCount,
878     mxwriter_GetTypeInfo,
879     mxwriter_GetIDsOfNames,
880     mxwriter_Invoke,
881     mxwriter_put_output,
882     mxwriter_get_output,
883     mxwriter_put_encoding,
884     mxwriter_get_encoding,
885     mxwriter_put_byteOrderMark,
886     mxwriter_get_byteOrderMark,
887     mxwriter_put_indent,
888     mxwriter_get_indent,
889     mxwriter_put_standalone,
890     mxwriter_get_standalone,
891     mxwriter_put_omitXMLDeclaration,
892     mxwriter_get_omitXMLDeclaration,
893     mxwriter_put_version,
894     mxwriter_get_version,
895     mxwriter_put_disableOutputEscaping,
896     mxwriter_get_disableOutputEscaping,
897     mxwriter_flush
898 };
899
900 /*** ISAXContentHandler ***/
901 static HRESULT WINAPI SAXContentHandler_QueryInterface(
902     ISAXContentHandler *iface,
903     REFIID riid,
904     void **obj)
905 {
906     mxwriter *This = impl_from_ISAXContentHandler( iface );
907     return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
908 }
909
910 static ULONG WINAPI SAXContentHandler_AddRef(ISAXContentHandler *iface)
911 {
912     mxwriter *This = impl_from_ISAXContentHandler( iface );
913     return IMXWriter_AddRef(&This->IMXWriter_iface);
914 }
915
916 static ULONG WINAPI SAXContentHandler_Release(ISAXContentHandler *iface)
917 {
918     mxwriter *This = impl_from_ISAXContentHandler( iface );
919     return IMXWriter_Release(&This->IMXWriter_iface);
920 }
921
922 static HRESULT WINAPI SAXContentHandler_putDocumentLocator(
923     ISAXContentHandler *iface,
924     ISAXLocator *locator)
925 {
926     mxwriter *This = impl_from_ISAXContentHandler( iface );
927     FIXME("(%p)->(%p)\n", This, locator);
928     return E_NOTIMPL;
929 }
930
931 static HRESULT WINAPI SAXContentHandler_startDocument(ISAXContentHandler *iface)
932 {
933     mxwriter *This = impl_from_ISAXContentHandler( iface );
934
935     TRACE("(%p)\n", This);
936
937     /* If properties have been changed since the last "endDocument" call
938      * we need to reset the output buffer. If we don't the output buffer
939      * could end up with multiple XML documents in it, plus this seems to
940      * be how Windows works.
941      */
942     if (This->prop_changed) {
943         reset_output_buffer(This);
944         This->prop_changed = FALSE;
945     }
946
947     if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
948
949     write_prolog_buffer(This);
950
951     if (This->dest && This->xml_enc == XmlEncoding_UTF16) {
952         static const char utf16BOM[] = {0xff,0xfe};
953
954         if (This->props[MXWriter_BOM] == VARIANT_TRUE)
955             /* Windows passes a NULL pointer as the pcbWritten parameter and
956              * ignores any error codes returned from this Write call.
957              */
958             IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
959     }
960
961     return S_OK;
962 }
963
964 static HRESULT WINAPI SAXContentHandler_endDocument(ISAXContentHandler *iface)
965 {
966     mxwriter *This = impl_from_ISAXContentHandler( iface );
967     TRACE("(%p)\n", This);
968     This->prop_changed = FALSE;
969     return flush_output_buffer(This);
970 }
971
972 static HRESULT WINAPI SAXContentHandler_startPrefixMapping(
973     ISAXContentHandler *iface,
974     const WCHAR *prefix,
975     int nprefix,
976     const WCHAR *uri,
977     int nuri)
978 {
979     mxwriter *This = impl_from_ISAXContentHandler( iface );
980     FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
981     return E_NOTIMPL;
982 }
983
984 static HRESULT WINAPI SAXContentHandler_endPrefixMapping(
985     ISAXContentHandler *iface,
986     const WCHAR *prefix,
987     int nprefix)
988 {
989     mxwriter *This = impl_from_ISAXContentHandler( iface );
990     FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
991     return E_NOTIMPL;
992 }
993
994 static HRESULT WINAPI SAXContentHandler_startElement(
995     ISAXContentHandler *iface,
996     const WCHAR *namespaceUri,
997     int nnamespaceUri,
998     const WCHAR *local_name,
999     int nlocal_name,
1000     const WCHAR *QName,
1001     int nQName,
1002     ISAXAttributes *attr)
1003 {
1004     mxwriter *This = impl_from_ISAXContentHandler( iface );
1005     static const WCHAR ltW[] = {'<'};
1006
1007     TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
1008         debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
1009
1010     if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
1011         return E_INVALIDARG;
1012
1013     close_element_starttag(This);
1014     set_element_name(This, QName ? QName  : emptyW,
1015                            QName ? nQName : 0);
1016
1017     write_output_buffer(This->buffer, ltW, 1);
1018     write_output_buffer(This->buffer, QName, nQName);
1019
1020     if (attr)
1021     {
1022         HRESULT hr;
1023         INT length;
1024         INT i;
1025
1026         hr = ISAXAttributes_getLength(attr, &length);
1027         if (FAILED(hr)) return hr;
1028
1029         for (i = 0; i < length; i++)
1030         {
1031             static const WCHAR eqW[] = {'='};
1032             const WCHAR *str;
1033             WCHAR *escaped;
1034             INT len = 0;
1035
1036             hr = ISAXAttributes_getQName(attr, i, &str, &len);
1037             if (FAILED(hr)) return hr;
1038
1039             /* space separator in front of every attribute */
1040             write_output_buffer(This->buffer, spaceW, 1);
1041             write_output_buffer(This->buffer, str, len);
1042
1043             write_output_buffer(This->buffer, eqW, 1);
1044
1045             len = 0;
1046             hr = ISAXAttributes_getValue(attr, i, &str, &len);
1047             if (FAILED(hr)) return hr;
1048
1049             escaped = get_escaped_string(str, EscapeValue, &len);
1050             write_output_buffer_quoted(This->buffer, escaped, len);
1051             heap_free(escaped);
1052         }
1053     }
1054
1055     return S_OK;
1056 }
1057
1058 static HRESULT WINAPI SAXContentHandler_endElement(
1059     ISAXContentHandler *iface,
1060     const WCHAR *namespaceUri,
1061     int nnamespaceUri,
1062     const WCHAR * local_name,
1063     int nlocal_name,
1064     const WCHAR *QName,
1065     int nQName)
1066 {
1067     mxwriter *This = impl_from_ISAXContentHandler( iface );
1068
1069     TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(namespaceUri, nnamespaceUri), nnamespaceUri,
1070         debugstr_wn(local_name, nlocal_name), nlocal_name, debugstr_wn(QName, nQName), nQName);
1071
1072     if ((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6)
1073         return E_INVALIDARG;
1074
1075     if (This->element && QName && !strncmpW(This->element, QName, nQName))
1076     {
1077         static const WCHAR closeW[] = {'/','>'};
1078
1079         write_output_buffer(This->buffer, closeW, 2);
1080     }
1081     else
1082     {
1083         static const WCHAR closetagW[] = {'<','/'};
1084         static const WCHAR gtW[] = {'>'};
1085
1086         write_output_buffer(This->buffer, closetagW, 2);
1087         write_output_buffer(This->buffer, QName, nQName);
1088         write_output_buffer(This->buffer, gtW, 1);
1089     }
1090
1091     set_element_name(This, NULL, 0);
1092
1093     return S_OK;
1094 }
1095
1096 static HRESULT WINAPI SAXContentHandler_characters(
1097     ISAXContentHandler *iface,
1098     const WCHAR *chars,
1099     int nchars)
1100 {
1101     mxwriter *This = impl_from_ISAXContentHandler( iface );
1102
1103     TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
1104
1105     if (!chars) return E_INVALIDARG;
1106
1107     close_element_starttag(This);
1108     set_element_name(This, NULL, 0);
1109
1110     if (nchars)
1111     {
1112         if (This->cdata)
1113             write_output_buffer(This->buffer, chars, nchars);
1114         else
1115         {
1116             int len = nchars;
1117             WCHAR *escaped;
1118
1119             escaped = get_escaped_string(chars, EscapeText, &len);
1120             write_output_buffer(This->buffer, escaped, len);
1121             heap_free(escaped);
1122         }
1123     }
1124
1125     return S_OK;
1126 }
1127
1128 static HRESULT WINAPI SAXContentHandler_ignorableWhitespace(
1129     ISAXContentHandler *iface,
1130     const WCHAR *chars,
1131     int nchars)
1132 {
1133     mxwriter *This = impl_from_ISAXContentHandler( iface );
1134     FIXME("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
1135     return E_NOTIMPL;
1136 }
1137
1138 static HRESULT WINAPI SAXContentHandler_processingInstruction(
1139     ISAXContentHandler *iface,
1140     const WCHAR *target,
1141     int ntarget,
1142     const WCHAR *data,
1143     int ndata)
1144 {
1145     mxwriter *This = impl_from_ISAXContentHandler( iface );
1146     FIXME("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
1147     return E_NOTIMPL;
1148 }
1149
1150 static HRESULT WINAPI SAXContentHandler_skippedEntity(
1151     ISAXContentHandler *iface,
1152     const WCHAR *name,
1153     int nname)
1154 {
1155     mxwriter *This = impl_from_ISAXContentHandler( iface );
1156     FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
1157     return E_NOTIMPL;
1158 }
1159
1160 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl =
1161 {
1162     SAXContentHandler_QueryInterface,
1163     SAXContentHandler_AddRef,
1164     SAXContentHandler_Release,
1165     SAXContentHandler_putDocumentLocator,
1166     SAXContentHandler_startDocument,
1167     SAXContentHandler_endDocument,
1168     SAXContentHandler_startPrefixMapping,
1169     SAXContentHandler_endPrefixMapping,
1170     SAXContentHandler_startElement,
1171     SAXContentHandler_endElement,
1172     SAXContentHandler_characters,
1173     SAXContentHandler_ignorableWhitespace,
1174     SAXContentHandler_processingInstruction,
1175     SAXContentHandler_skippedEntity
1176 };
1177
1178 /*** ISAXLexicalHandler ***/
1179 static HRESULT WINAPI SAXLexicalHandler_QueryInterface(ISAXLexicalHandler *iface,
1180     REFIID riid, void **obj)
1181 {
1182     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1183     return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1184 }
1185
1186 static ULONG WINAPI SAXLexicalHandler_AddRef(ISAXLexicalHandler *iface)
1187 {
1188     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1189     return IMXWriter_AddRef(&This->IMXWriter_iface);
1190 }
1191
1192 static ULONG WINAPI SAXLexicalHandler_Release(ISAXLexicalHandler *iface)
1193 {
1194     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1195     return IMXWriter_Release(&This->IMXWriter_iface);
1196 }
1197
1198 static HRESULT WINAPI SAXLexicalHandler_startDTD(ISAXLexicalHandler *iface,
1199     const WCHAR *name, int name_len, const WCHAR *publicId, int publicId_len,
1200     const WCHAR *systemId, int systemId_len)
1201 {
1202     static const WCHAR doctypeW[] = {'<','!','D','O','C','T','Y','P','E',' '};
1203     static const WCHAR openintW[] = {'[','\r','\n'};
1204
1205     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1206
1207     TRACE("(%p)->(%s %s %s)\n", This, debugstr_wn(name, name_len), debugstr_wn(publicId, publicId_len),
1208         debugstr_wn(systemId, systemId_len));
1209
1210     if (!name) return E_INVALIDARG;
1211
1212     write_output_buffer(This->buffer, doctypeW, sizeof(doctypeW)/sizeof(WCHAR));
1213
1214     if (*name)
1215     {
1216         write_output_buffer(This->buffer, name, name_len);
1217         write_output_buffer(This->buffer, spaceW, 1);
1218     }
1219
1220     if (publicId)
1221     {
1222         static const WCHAR publicW[] = {'P','U','B','L','I','C',' '};
1223
1224         write_output_buffer(This->buffer, publicW, sizeof(publicW)/sizeof(WCHAR));
1225         write_output_buffer_quoted(This->buffer, publicId, publicId_len);
1226
1227         if (!systemId) return E_INVALIDARG;
1228
1229         if (*publicId)
1230             write_output_buffer(This->buffer, spaceW, 1);
1231
1232         write_output_buffer_quoted(This->buffer, systemId, systemId_len);
1233
1234         if (*systemId)
1235             write_output_buffer(This->buffer, spaceW, 1);
1236     }
1237     else if (systemId)
1238     {
1239         static const WCHAR systemW[] = {'S','Y','S','T','E','M',' '};
1240
1241         write_output_buffer(This->buffer, systemW, sizeof(systemW)/sizeof(WCHAR));
1242         write_output_buffer_quoted(This->buffer, systemId, systemId_len);
1243         if (*systemId)
1244             write_output_buffer(This->buffer, spaceW, 1);
1245     }
1246
1247     write_output_buffer(This->buffer, openintW, sizeof(openintW)/sizeof(WCHAR));
1248
1249     return S_OK;
1250 }
1251
1252 static HRESULT WINAPI SAXLexicalHandler_endDTD(ISAXLexicalHandler *iface)
1253 {
1254     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1255     static const WCHAR closedtdW[] = {']','>','\r','\n'};
1256
1257     TRACE("(%p)\n", This);
1258
1259     write_output_buffer(This->buffer, closedtdW, sizeof(closedtdW)/sizeof(WCHAR));
1260
1261     return S_OK;
1262 }
1263
1264 static HRESULT WINAPI SAXLexicalHandler_startEntity(ISAXLexicalHandler *iface, const WCHAR *name, int len)
1265 {
1266     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1267     FIXME("(%p)->(%s): stub\n", This, debugstr_wn(name, len));
1268     return E_NOTIMPL;
1269 }
1270
1271 static HRESULT WINAPI SAXLexicalHandler_endEntity(ISAXLexicalHandler *iface, const WCHAR *name, int len)
1272 {
1273     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1274     FIXME("(%p)->(%s): stub\n", This, debugstr_wn(name, len));
1275     return E_NOTIMPL;
1276 }
1277
1278 static HRESULT WINAPI SAXLexicalHandler_startCDATA(ISAXLexicalHandler *iface)
1279 {
1280     static const WCHAR scdataW[] = {'<','!','[','C','D','A','T','A','['};
1281     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1282
1283     TRACE("(%p)\n", This);
1284
1285     write_output_buffer(This->buffer, scdataW, sizeof(scdataW)/sizeof(WCHAR));
1286     This->cdata = TRUE;
1287
1288     return S_OK;
1289 }
1290
1291 static HRESULT WINAPI SAXLexicalHandler_endCDATA(ISAXLexicalHandler *iface)
1292 {
1293     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1294     static const WCHAR ecdataW[] = {']',']','>'};
1295
1296     TRACE("(%p)\n", This);
1297
1298     write_output_buffer(This->buffer, ecdataW, sizeof(ecdataW)/sizeof(WCHAR));
1299     This->cdata = FALSE;
1300
1301     return S_OK;
1302 }
1303
1304 static HRESULT WINAPI SAXLexicalHandler_comment(ISAXLexicalHandler *iface, const WCHAR *chars, int nchars)
1305 {
1306     mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1307     static const WCHAR copenW[] = {'<','!','-','-'};
1308     static const WCHAR ccloseW[] = {'-','-','>','\r','\n'};
1309
1310     TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
1311
1312     if (!chars) return E_INVALIDARG;
1313
1314     close_element_starttag(This);
1315
1316     write_output_buffer(This->buffer, copenW, sizeof(copenW)/sizeof(WCHAR));
1317     if (nchars)
1318         write_output_buffer(This->buffer, chars, nchars);
1319     write_output_buffer(This->buffer, ccloseW, sizeof(ccloseW)/sizeof(WCHAR));
1320
1321     return S_OK;
1322 }
1323
1324 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1325 {
1326     SAXLexicalHandler_QueryInterface,
1327     SAXLexicalHandler_AddRef,
1328     SAXLexicalHandler_Release,
1329     SAXLexicalHandler_startDTD,
1330     SAXLexicalHandler_endDTD,
1331     SAXLexicalHandler_startEntity,
1332     SAXLexicalHandler_endEntity,
1333     SAXLexicalHandler_startCDATA,
1334     SAXLexicalHandler_endCDATA,
1335     SAXLexicalHandler_comment
1336 };
1337
1338 /*** ISAXDeclHandler ***/
1339 static HRESULT WINAPI SAXDeclHandler_QueryInterface(ISAXDeclHandler *iface,
1340     REFIID riid, void **obj)
1341 {
1342     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1343     return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1344 }
1345
1346 static ULONG WINAPI SAXDeclHandler_AddRef(ISAXDeclHandler *iface)
1347 {
1348     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1349     return IMXWriter_AddRef(&This->IMXWriter_iface);
1350 }
1351
1352 static ULONG WINAPI SAXDeclHandler_Release(ISAXDeclHandler *iface)
1353 {
1354     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1355     return IMXWriter_Release(&This->IMXWriter_iface);
1356 }
1357
1358 static HRESULT WINAPI SAXDeclHandler_elementDecl(ISAXDeclHandler *iface,
1359     const WCHAR *name, int n_name, const WCHAR *model, int n_model)
1360 {
1361     static const WCHAR elementW[] = {'<','!','E','L','E','M','E','N','T',' '};
1362     static const WCHAR closeelementW[] = {'>','\r','\n'};
1363     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1364
1365     TRACE("(%p)->(%s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1366         debugstr_wn(model, n_model), n_model);
1367
1368     if (!name || !model) return E_INVALIDARG;
1369
1370     write_output_buffer(This->buffer, elementW, sizeof(elementW)/sizeof(WCHAR));
1371     if (n_name) {
1372         write_output_buffer(This->buffer, name, n_name);
1373         write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1374     }
1375     if (n_model)
1376         write_output_buffer(This->buffer, model, n_model);
1377     write_output_buffer(This->buffer, closeelementW, sizeof(closeelementW)/sizeof(WCHAR));
1378
1379     return S_OK;
1380 }
1381
1382 static HRESULT WINAPI SAXDeclHandler_attributeDecl(ISAXDeclHandler *iface,
1383     const WCHAR *element, int n_element, const WCHAR *attr, int n_attr,
1384     const WCHAR *type, int n_type, const WCHAR *Default, int n_default,
1385     const WCHAR *value, int n_value)
1386 {
1387     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1388     FIXME("(%p)->(%s:%d %s:%d %s:%d %s:%d %s:%d): stub\n", This, debugstr_wn(element, n_element), n_element,
1389         debugstr_wn(attr, n_attr), n_attr, debugstr_wn(type, n_type), n_type, debugstr_wn(Default, n_default), n_default,
1390         debugstr_wn(value, n_value), n_value);
1391     return E_NOTIMPL;
1392 }
1393
1394 static HRESULT WINAPI SAXDeclHandler_internalEntityDecl(ISAXDeclHandler *iface,
1395     const WCHAR *name, int n_name, const WCHAR *value, int n_value)
1396 {
1397     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1398     FIXME("(%p)->(%s:%d %s:%d): stub\n", This, debugstr_wn(name, n_name), n_name,
1399         debugstr_wn(value, n_value), n_value);
1400     return E_NOTIMPL;
1401 }
1402
1403 static HRESULT WINAPI SAXDeclHandler_externalEntityDecl(ISAXDeclHandler *iface,
1404     const WCHAR *name, int n_name, const WCHAR *publicId, int n_publicId,
1405     const WCHAR *systemId, int n_systemId)
1406 {
1407     mxwriter *This = impl_from_ISAXDeclHandler( iface );
1408     FIXME("(%p)->(%s:%d %s:%d %s:%d): stub\n", This, debugstr_wn(name, n_name), n_name,
1409         debugstr_wn(publicId, n_publicId), n_publicId, debugstr_wn(systemId, n_systemId), n_systemId);
1410     return E_NOTIMPL;
1411 }
1412
1413 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = {
1414     SAXDeclHandler_QueryInterface,
1415     SAXDeclHandler_AddRef,
1416     SAXDeclHandler_Release,
1417     SAXDeclHandler_elementDecl,
1418     SAXDeclHandler_attributeDecl,
1419     SAXDeclHandler_internalEntityDecl,
1420     SAXDeclHandler_externalEntityDecl
1421 };
1422
1423 static const tid_t mxwriter_iface_tids[] = {
1424     IMXWriter_tid,
1425     0
1426 };
1427
1428 static dispex_static_data_t mxwriter_dispex = {
1429     NULL,
1430     IMXWriter_tid,
1431     NULL,
1432     mxwriter_iface_tids
1433 };
1434
1435 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
1436 {
1437     static const WCHAR version10W[] = {'1','.','0',0};
1438     mxwriter *This;
1439     HRESULT hr;
1440
1441     TRACE("(%p, %p)\n", outer, ppObj);
1442
1443     if (outer) FIXME("support aggregation, outer\n");
1444
1445     This = heap_alloc( sizeof (*This) );
1446     if(!This)
1447         return E_OUTOFMEMORY;
1448
1449     This->IMXWriter_iface.lpVtbl = &MXWriterVtbl;
1450     This->ISAXContentHandler_iface.lpVtbl = &SAXContentHandlerVtbl;
1451     This->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1452     This->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1453     This->ref = 1;
1454     This->class_version = version;
1455
1456     This->props[MXWriter_BOM] = VARIANT_TRUE;
1457     This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
1458     This->props[MXWriter_Indent] = VARIANT_FALSE;
1459     This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
1460     This->props[MXWriter_Standalone] = VARIANT_FALSE;
1461     This->prop_changed = FALSE;
1462     This->encoding = SysAllocString(utf16W);
1463     This->version  = SysAllocString(version10W);
1464     This->xml_enc  = XmlEncoding_UTF16;
1465
1466     This->element = NULL;
1467     This->cdata = FALSE;
1468
1469     This->dest = NULL;
1470     This->dest_written = 0;
1471
1472     hr = alloc_output_buffer(This->xml_enc, &This->buffer);
1473     if (hr != S_OK) {
1474         SysFreeString(This->encoding);
1475         SysFreeString(This->version);
1476         heap_free(This);
1477         return hr;
1478     }
1479
1480     init_dispex(&This->dispex, (IUnknown*)&This->IMXWriter_iface, &mxwriter_dispex);
1481
1482     *ppObj = &This->IMXWriter_iface;
1483
1484     TRACE("returning iface %p\n", *ppObj);
1485
1486     return S_OK;
1487 }
1488
1489 static HRESULT WINAPI MXAttributes_QueryInterface(IMXAttributes *iface, REFIID riid, void **ppObj)
1490 {
1491     mxattributes *This = impl_from_IMXAttributes( iface );
1492
1493     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppObj);
1494
1495     *ppObj = NULL;
1496
1497     if ( IsEqualGUID( riid, &IID_IUnknown )  ||
1498          IsEqualGUID( riid, &IID_IDispatch ) ||
1499          IsEqualGUID( riid, &IID_IMXAttributes ))
1500     {
1501         *ppObj = iface;
1502     }
1503     else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
1504     {
1505         *ppObj = &This->ISAXAttributes_iface;
1506     }
1507     else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
1508     {
1509         *ppObj = &This->IVBSAXAttributes_iface;
1510     }
1511     else if (dispex_query_interface(&This->dispex, riid, ppObj))
1512     {
1513         return *ppObj ? S_OK : E_NOINTERFACE;
1514     }
1515     else
1516     {
1517         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1518         return E_NOINTERFACE;
1519     }
1520
1521     IMXAttributes_AddRef( iface );
1522
1523     return S_OK;
1524 }
1525
1526 static ULONG WINAPI MXAttributes_AddRef(IMXAttributes *iface)
1527 {
1528     mxattributes *This = impl_from_IMXAttributes( iface );
1529     ULONG ref = InterlockedIncrement( &This->ref );
1530     TRACE("(%p)->(%d)\n", This, ref );
1531     return ref;
1532 }
1533
1534 static ULONG WINAPI MXAttributes_Release(IMXAttributes *iface)
1535 {
1536     mxattributes *This = impl_from_IMXAttributes( iface );
1537     LONG ref = InterlockedDecrement( &This->ref );
1538
1539     TRACE("(%p)->(%d)\n", This, ref);
1540
1541     if (ref == 0)
1542     {
1543         int i;
1544
1545         for (i = 0; i < This->length; i++)
1546         {
1547             SysFreeString(This->attr[i].qname);
1548             SysFreeString(This->attr[i].local);
1549             SysFreeString(This->attr[i].uri);
1550             SysFreeString(This->attr[i].type);
1551             SysFreeString(This->attr[i].value);
1552         }
1553
1554         release_dispex(&This->dispex);
1555         heap_free(This->attr);
1556         heap_free(This);
1557     }
1558
1559     return ref;
1560 }
1561
1562 static HRESULT WINAPI MXAttributes_GetTypeInfoCount(IMXAttributes *iface, UINT* pctinfo)
1563 {
1564     mxattributes *This = impl_from_IMXAttributes( iface );
1565     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1566 }
1567
1568 static HRESULT WINAPI MXAttributes_GetTypeInfo(IMXAttributes *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1569 {
1570     mxattributes *This = impl_from_IMXAttributes( iface );
1571     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1572 }
1573
1574 static HRESULT WINAPI MXAttributes_GetIDsOfNames(
1575     IMXAttributes *iface,
1576     REFIID riid,
1577     LPOLESTR* rgszNames,
1578     UINT cNames,
1579     LCID lcid,
1580     DISPID* rgDispId)
1581 {
1582     mxattributes *This = impl_from_IMXAttributes( iface );
1583     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1584         riid, rgszNames, cNames, lcid, rgDispId);
1585 }
1586
1587 static HRESULT WINAPI MXAttributes_Invoke(
1588     IMXAttributes *iface,
1589     DISPID dispIdMember,
1590     REFIID riid,
1591     LCID lcid,
1592     WORD wFlags,
1593     DISPPARAMS* pDispParams,
1594     VARIANT* pVarResult,
1595     EXCEPINFO* pExcepInfo,
1596     UINT* puArgErr)
1597 {
1598     mxattributes *This = impl_from_IMXAttributes( iface );
1599     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1600         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1601 }
1602
1603 static HRESULT WINAPI MXAttributes_addAttribute(IMXAttributes *iface,
1604     BSTR uri, BSTR localName, BSTR QName, BSTR type, BSTR value)
1605 {
1606     mxattributes *This = impl_from_IMXAttributes( iface );
1607     mxattribute *attr;
1608     HRESULT hr;
1609
1610     TRACE("(%p)->(%s %s %s %s %s)\n", This, debugstr_w(uri), debugstr_w(localName),
1611         debugstr_w(QName), debugstr_w(type), debugstr_w(value));
1612
1613     if ((!uri || !localName || !QName || !type || !value) && This->class_version != MSXML6)
1614         return E_INVALIDARG;
1615
1616     /* ensure array is large enough */
1617     hr = mxattributes_grow(This);
1618     if (hr != S_OK) return hr;
1619
1620     attr = &This->attr[This->length];
1621
1622     attr->qname = SysAllocString(QName);
1623     attr->local = SysAllocString(localName);
1624     attr->uri   = SysAllocString(uri);
1625     attr->type  = SysAllocString(type ? type : emptyW);
1626     attr->value = SysAllocString(value);
1627     This->length++;
1628
1629     return S_OK;
1630 }
1631
1632 static HRESULT WINAPI MXAttributes_addAttributeFromIndex(IMXAttributes *iface,
1633     VARIANT atts, int index)
1634 {
1635     mxattributes *This = impl_from_IMXAttributes( iface );
1636     FIXME("(%p)->(%s %d): stub\n", This, debugstr_variant(&atts), index);
1637     return E_NOTIMPL;
1638 }
1639
1640 static HRESULT WINAPI MXAttributes_clear(IMXAttributes *iface)
1641 {
1642     mxattributes *This = impl_from_IMXAttributes( iface );
1643     FIXME("(%p): stub\n", This);
1644     return E_NOTIMPL;
1645 }
1646
1647 static HRESULT WINAPI MXAttributes_removeAttribute(IMXAttributes *iface, int index)
1648 {
1649     mxattributes *This = impl_from_IMXAttributes( iface );
1650     FIXME("(%p)->(%d): stub\n", This, index);
1651     return E_NOTIMPL;
1652 }
1653
1654 static HRESULT WINAPI MXAttributes_setAttribute(IMXAttributes *iface, int index,
1655     BSTR uri, BSTR localName, BSTR QName, BSTR type, BSTR value)
1656 {
1657     mxattributes *This = impl_from_IMXAttributes( iface );
1658     FIXME("(%p)->(%d %s %s %s %s %s): stub\n", This, index, debugstr_w(uri),
1659         debugstr_w(localName), debugstr_w(QName), debugstr_w(type), debugstr_w(value));
1660     return E_NOTIMPL;
1661 }
1662
1663 static HRESULT WINAPI MXAttributes_setAttributes(IMXAttributes *iface, VARIANT atts)
1664 {
1665     mxattributes *This = impl_from_IMXAttributes( iface );
1666     FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&atts));
1667     return E_NOTIMPL;
1668 }
1669
1670 static HRESULT WINAPI MXAttributes_setLocalName(IMXAttributes *iface, int index,
1671     BSTR localName)
1672 {
1673     mxattributes *This = impl_from_IMXAttributes( iface );
1674     FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(localName));
1675     return E_NOTIMPL;
1676 }
1677
1678 static HRESULT WINAPI MXAttributes_setQName(IMXAttributes *iface, int index, BSTR QName)
1679 {
1680     mxattributes *This = impl_from_IMXAttributes( iface );
1681     FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(QName));
1682     return E_NOTIMPL;
1683 }
1684
1685 static HRESULT WINAPI MXAttributes_setURI(IMXAttributes *iface, int index, BSTR uri)
1686 {
1687     mxattributes *This = impl_from_IMXAttributes( iface );
1688     FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(uri));
1689     return E_NOTIMPL;
1690 }
1691
1692 static HRESULT WINAPI MXAttributes_setValue(IMXAttributes *iface, int index, BSTR value)
1693 {
1694     mxattributes *This = impl_from_IMXAttributes( iface );
1695     FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(value));
1696     return E_NOTIMPL;
1697 }
1698
1699 static const IMXAttributesVtbl MXAttributesVtbl = {
1700     MXAttributes_QueryInterface,
1701     MXAttributes_AddRef,
1702     MXAttributes_Release,
1703     MXAttributes_GetTypeInfoCount,
1704     MXAttributes_GetTypeInfo,
1705     MXAttributes_GetIDsOfNames,
1706     MXAttributes_Invoke,
1707     MXAttributes_addAttribute,
1708     MXAttributes_addAttributeFromIndex,
1709     MXAttributes_clear,
1710     MXAttributes_removeAttribute,
1711     MXAttributes_setAttribute,
1712     MXAttributes_setAttributes,
1713     MXAttributes_setLocalName,
1714     MXAttributes_setQName,
1715     MXAttributes_setURI,
1716     MXAttributes_setValue
1717 };
1718
1719 static HRESULT WINAPI SAXAttributes_QueryInterface(ISAXAttributes *iface, REFIID riid, void **ppObj)
1720 {
1721     mxattributes *This = impl_from_ISAXAttributes( iface );
1722     return IMXAttributes_QueryInterface(&This->IMXAttributes_iface, riid, ppObj);
1723 }
1724
1725 static ULONG WINAPI SAXAttributes_AddRef(ISAXAttributes *iface)
1726 {
1727     mxattributes *This = impl_from_ISAXAttributes( iface );
1728     return IMXAttributes_AddRef(&This->IMXAttributes_iface);
1729 }
1730
1731 static ULONG WINAPI SAXAttributes_Release(ISAXAttributes *iface)
1732 {
1733     mxattributes *This = impl_from_ISAXAttributes( iface );
1734     return IMXAttributes_Release(&This->IMXAttributes_iface);
1735 }
1736
1737 static HRESULT WINAPI SAXAttributes_getLength(ISAXAttributes *iface, int *length)
1738 {
1739     mxattributes *This = impl_from_ISAXAttributes( iface );
1740     TRACE("(%p)->(%p)\n", This, length);
1741
1742     if (!length && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
1743        return E_POINTER;
1744
1745     *length = This->length;
1746
1747     return S_OK;
1748 }
1749
1750 static HRESULT WINAPI SAXAttributes_getURI(ISAXAttributes *iface, int nIndex, const WCHAR **pUrl,
1751     int *pUriSize)
1752 {
1753     mxattributes *This = impl_from_ISAXAttributes( iface );
1754     FIXME("(%p)->(%d %p %p): stub\n", This, nIndex, pUrl, pUriSize);
1755     return E_NOTIMPL;
1756 }
1757
1758 static HRESULT WINAPI SAXAttributes_getLocalName(ISAXAttributes *iface, int nIndex, const WCHAR **localName,
1759     int *length)
1760 {
1761     mxattributes *This = impl_from_ISAXAttributes( iface );
1762     FIXME("(%p)->(%d %p %p): stub\n", This, nIndex, localName, length);
1763     return E_NOTIMPL;
1764 }
1765
1766 static HRESULT WINAPI SAXAttributes_getQName(ISAXAttributes *iface, int index, const WCHAR **qname, int *length)
1767 {
1768     mxattributes *This = impl_from_ISAXAttributes( iface );
1769
1770     TRACE("(%p)->(%d %p %p)\n", This, index, qname, length);
1771
1772     if (index >= This->length) return E_INVALIDARG;
1773     if (!qname || !length) return E_POINTER;
1774
1775     *qname = This->attr[index].qname;
1776     *length = SysStringLen(This->attr[index].qname);
1777
1778     return S_OK;
1779 }
1780
1781 static HRESULT WINAPI SAXAttributes_getName(ISAXAttributes *iface, int nIndex, const WCHAR **pUri, int *pUriLength,
1782     const WCHAR ** pLocalName, int * pLocalNameSize, const WCHAR ** pQName, int * pQNameLength)
1783 {
1784     mxattributes *This = impl_from_ISAXAttributes( iface );
1785     FIXME("(%p)->(%d %p %p %p %p %p %p): stub\n", This, nIndex, pUri, pUriLength, pLocalName, pLocalNameSize,
1786         pQName, pQNameLength);
1787     return E_NOTIMPL;
1788 }
1789
1790 static HRESULT WINAPI SAXAttributes_getIndexFromName(ISAXAttributes *iface, const WCHAR * pUri, int cUriLength,
1791     const WCHAR * pLocalName, int cocalNameLength, int * index)
1792 {
1793     mxattributes *This = impl_from_ISAXAttributes( iface );
1794     FIXME("(%p)->(%s:%d %s:%d %p): stub\n", This, debugstr_wn(pUri, cUriLength), cUriLength,
1795         debugstr_wn(pLocalName, cocalNameLength), cocalNameLength, index);
1796     return E_NOTIMPL;
1797 }
1798
1799 static HRESULT WINAPI SAXAttributes_getIndexFromQName(ISAXAttributes *iface, const WCHAR *qname,
1800     int len, int *index)
1801 {
1802     mxattributes *This = impl_from_ISAXAttributes( iface );
1803     int i;
1804
1805     TRACE("(%p)->(%s:%d %p)\n", This, debugstr_wn(qname, len), len, index);
1806
1807     if (!index && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
1808         return E_POINTER;
1809
1810     if (!qname || !index || !len) return E_INVALIDARG;
1811
1812     for (i = 0; i < This->length; i++)
1813     {
1814         if (len != SysStringLen(This->attr[i].qname)) continue;
1815         if (strncmpW(qname, This->attr[i].qname, len)) continue;
1816
1817         *index = i;
1818         return S_OK;
1819     }
1820
1821     return E_INVALIDARG;
1822 }
1823
1824 static HRESULT WINAPI SAXAttributes_getType(ISAXAttributes *iface, int index, const WCHAR **type,
1825     int *len)
1826 {
1827     mxattributes *This = impl_from_ISAXAttributes( iface );
1828
1829     TRACE("(%p)->(%d %p %p)\n", This, index, type, len);
1830
1831     if (index >= This->length) return E_INVALIDARG;
1832
1833     if ((!type || !len) && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
1834        return E_POINTER;
1835
1836     *type = This->attr[index].type;
1837     *len = SysStringLen(This->attr[index].type);
1838
1839     return S_OK;
1840 }
1841
1842 static HRESULT WINAPI SAXAttributes_getTypeFromName(ISAXAttributes *iface, const WCHAR * pUri, int nUri,
1843     const WCHAR * pLocalName, int nLocalName, const WCHAR ** pType, int * nType)
1844 {
1845     mxattributes *This = impl_from_ISAXAttributes( iface );
1846     FIXME("(%p)->(%s:%d %s:%d %p %p): stub\n", This, debugstr_wn(pUri, nUri), nUri,
1847         debugstr_wn(pLocalName, nLocalName), nLocalName, pType, nType);
1848     return E_NOTIMPL;
1849 }
1850
1851 static HRESULT WINAPI SAXAttributes_getTypeFromQName(ISAXAttributes *iface, const WCHAR * pQName,
1852     int nQName, const WCHAR ** pType, int * nType)
1853 {
1854     mxattributes *This = impl_from_ISAXAttributes( iface );
1855     FIXME("(%p)->(%s:%d %p %p): stub\n", This, debugstr_wn(pQName, nQName), nQName, pType, nType);
1856     return E_NOTIMPL;
1857 }
1858
1859 static HRESULT WINAPI SAXAttributes_getValue(ISAXAttributes *iface, int index, const WCHAR **value,
1860     int *len)
1861 {
1862     mxattributes *This = impl_from_ISAXAttributes( iface );
1863
1864     TRACE("(%p)->(%d %p %p)\n", This, index, value, len);
1865
1866     if (index >= This->length) return E_INVALIDARG;
1867
1868     if ((!value || !len) && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
1869        return E_POINTER;
1870
1871     *value = This->attr[index].value;
1872     *len = SysStringLen(This->attr[index].value);
1873
1874     return S_OK;
1875 }
1876
1877 static HRESULT WINAPI SAXAttributes_getValueFromName(ISAXAttributes *iface, const WCHAR * pUri,
1878     int nUri, const WCHAR * pLocalName, int nLocalName, const WCHAR ** pValue, int * nValue)
1879 {
1880     mxattributes *This = impl_from_ISAXAttributes( iface );
1881     FIXME("(%p)->(%s:%d %s:%d %p %p): stub\n", This, debugstr_wn(pUri, nUri), nUri,
1882         debugstr_wn(pLocalName, nLocalName), nLocalName, pValue, nValue);
1883     return E_NOTIMPL;
1884 }
1885
1886 static HRESULT WINAPI SAXAttributes_getValueFromQName(ISAXAttributes *iface, const WCHAR *qname,
1887     int qname_len, const WCHAR **value, int *value_len)
1888 {
1889     mxattributes *This = impl_from_ISAXAttributes( iface );
1890     HRESULT hr;
1891     int index;
1892
1893     TRACE("(%p)->(%s:%d %p %p)\n", This, debugstr_wn(qname, qname_len), qname_len, value, value_len);
1894
1895     if (!qname || !value || !value_len)
1896         return (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3) ? E_POINTER : E_INVALIDARG;
1897
1898     hr = ISAXAttributes_getIndexFromQName(iface, qname, qname_len, &index);
1899     if (hr == S_OK)
1900         hr = ISAXAttributes_getValue(iface, index, value, value_len);
1901
1902     return hr;
1903 }
1904
1905 static const ISAXAttributesVtbl SAXAttributesVtbl = {
1906     SAXAttributes_QueryInterface,
1907     SAXAttributes_AddRef,
1908     SAXAttributes_Release,
1909     SAXAttributes_getLength,
1910     SAXAttributes_getURI,
1911     SAXAttributes_getLocalName,
1912     SAXAttributes_getQName,
1913     SAXAttributes_getName,
1914     SAXAttributes_getIndexFromName,
1915     SAXAttributes_getIndexFromQName,
1916     SAXAttributes_getType,
1917     SAXAttributes_getTypeFromName,
1918     SAXAttributes_getTypeFromQName,
1919     SAXAttributes_getValue,
1920     SAXAttributes_getValueFromName,
1921     SAXAttributes_getValueFromQName
1922 };
1923
1924 static HRESULT WINAPI VBSAXAttributes_QueryInterface(
1925         IVBSAXAttributes* iface,
1926         REFIID riid,
1927         void **ppvObject)
1928 {
1929     mxattributes *This = impl_from_IVBSAXAttributes( iface );
1930     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
1931     return ISAXAttributes_QueryInterface(&This->ISAXAttributes_iface, riid, ppvObject);
1932 }
1933
1934 static ULONG WINAPI VBSAXAttributes_AddRef(IVBSAXAttributes* iface)
1935 {
1936     mxattributes *This = impl_from_IVBSAXAttributes( iface );
1937     return ISAXAttributes_AddRef(&This->ISAXAttributes_iface);
1938 }
1939
1940 static ULONG WINAPI VBSAXAttributes_Release(IVBSAXAttributes* iface)
1941 {
1942     mxattributes *This = impl_from_IVBSAXAttributes( iface );
1943     return ISAXAttributes_Release(&This->ISAXAttributes_iface);
1944 }
1945
1946 static HRESULT WINAPI VBSAXAttributes_GetTypeInfoCount( IVBSAXAttributes *iface, UINT* pctinfo )
1947 {
1948     mxattributes *This = impl_from_IVBSAXAttributes( iface );
1949
1950     TRACE("(%p)->(%p)\n", This, pctinfo);
1951
1952     *pctinfo = 1;
1953
1954     return S_OK;
1955 }
1956
1957 static HRESULT WINAPI VBSAXAttributes_GetTypeInfo(
1958     IVBSAXAttributes *iface,
1959     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
1960 {
1961     mxattributes *This = impl_from_IVBSAXAttributes( iface );
1962     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1963     return get_typeinfo(IVBSAXAttributes_tid, ppTInfo);
1964 }
1965
1966 static HRESULT WINAPI VBSAXAttributes_GetIDsOfNames(
1967     IVBSAXAttributes *iface,
1968     REFIID riid,
1969     LPOLESTR* rgszNames,
1970     UINT cNames,
1971     LCID lcid,
1972     DISPID* rgDispId)
1973 {
1974     mxattributes *This = impl_from_IVBSAXAttributes( iface );
1975     ITypeInfo *typeinfo;
1976     HRESULT hr;
1977
1978     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1979           lcid, rgDispId);
1980
1981     if(!rgszNames || cNames == 0 || !rgDispId)
1982         return E_INVALIDARG;
1983
1984     hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
1985     if(SUCCEEDED(hr))
1986     {
1987         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1988         ITypeInfo_Release(typeinfo);
1989     }
1990
1991     return hr;
1992 }
1993
1994 static HRESULT WINAPI VBSAXAttributes_Invoke(
1995     IVBSAXAttributes *iface,
1996     DISPID dispIdMember,
1997     REFIID riid,
1998     LCID lcid,
1999     WORD wFlags,
2000     DISPPARAMS* pDispParams,
2001     VARIANT* pVarResult,
2002     EXCEPINFO* pExcepInfo,
2003     UINT* puArgErr)
2004 {
2005     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2006     ITypeInfo *typeinfo;
2007     HRESULT hr;
2008
2009     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2010           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2011
2012     hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
2013     if(SUCCEEDED(hr))
2014     {
2015         hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXAttributes_iface, dispIdMember, wFlags,
2016                 pDispParams, pVarResult, pExcepInfo, puArgErr);
2017         ITypeInfo_Release(typeinfo);
2018     }
2019
2020     return hr;
2021 }
2022
2023 static HRESULT WINAPI VBSAXAttributes_get_length(IVBSAXAttributes* iface, int *len)
2024 {
2025     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2026     return ISAXAttributes_getLength(&This->ISAXAttributes_iface, len);
2027 }
2028
2029 static HRESULT WINAPI VBSAXAttributes_getURI(IVBSAXAttributes* iface, int index, BSTR *uri)
2030 {
2031     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2032     int len;
2033
2034     return ISAXAttributes_getURI(&This->ISAXAttributes_iface, index, (const WCHAR**)uri, &len);
2035 }
2036
2037 static HRESULT WINAPI VBSAXAttributes_getLocalName(IVBSAXAttributes* iface, int index, BSTR *name)
2038 {
2039     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2040     int len;
2041
2042     return ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, index, (const WCHAR**)name, &len);
2043 }
2044
2045 static HRESULT WINAPI VBSAXAttributes_getQName(IVBSAXAttributes* iface, int index, BSTR *qname)
2046 {
2047     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2048     int len;
2049
2050     return ISAXAttributes_getQName(&This->ISAXAttributes_iface, index, (const WCHAR**)qname, &len);
2051 }
2052
2053 static HRESULT WINAPI VBSAXAttributes_getIndexFromName(IVBSAXAttributes* iface, BSTR uri, BSTR name, int *index)
2054 {
2055     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2056     return ISAXAttributes_getIndexFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
2057             name, SysStringLen(name), index);
2058 }
2059
2060 static HRESULT WINAPI VBSAXAttributes_getIndexFromQName(IVBSAXAttributes* iface, BSTR qname, int *index)
2061 {
2062     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2063     return ISAXAttributes_getIndexFromQName(&This->ISAXAttributes_iface, qname,
2064             SysStringLen(qname), index);
2065 }
2066
2067 static HRESULT WINAPI VBSAXAttributes_getType(IVBSAXAttributes* iface, int index,BSTR *type)
2068 {
2069     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2070     int len;
2071
2072     return ISAXAttributes_getType(&This->ISAXAttributes_iface, index, (const WCHAR**)type, &len);
2073 }
2074
2075 static HRESULT WINAPI VBSAXAttributes_getTypeFromName(IVBSAXAttributes* iface, BSTR uri,
2076     BSTR name, BSTR *type)
2077 {
2078     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2079     int len;
2080
2081     return ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
2082             name, SysStringLen(name), (const WCHAR**)type, &len);
2083 }
2084
2085 static HRESULT WINAPI VBSAXAttributes_getTypeFromQName(IVBSAXAttributes* iface, BSTR qname, BSTR *type)
2086 {
2087     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2088     int len;
2089
2090     return ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
2091             (const WCHAR**)type, &len);
2092 }
2093
2094 static HRESULT WINAPI VBSAXAttributes_getValue(IVBSAXAttributes* iface, int index, BSTR *value)
2095 {
2096     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2097     int len;
2098
2099     return ISAXAttributes_getValue(&This->ISAXAttributes_iface, index, (const WCHAR**)value, &len);
2100 }
2101
2102 static HRESULT WINAPI VBSAXAttributes_getValueFromName(IVBSAXAttributes* iface, BSTR uri, BSTR name,
2103     BSTR *value)
2104 {
2105     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2106     int len;
2107
2108     return ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
2109             name, SysStringLen(name), (const WCHAR**)value, &len);
2110 }
2111
2112 static HRESULT WINAPI VBSAXAttributes_getValueFromQName(IVBSAXAttributes* iface, BSTR qname, BSTR *value)
2113 {
2114     mxattributes *This = impl_from_IVBSAXAttributes( iface );
2115     int len;
2116
2117     return ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
2118         (const WCHAR**)value, &len);
2119 }
2120
2121 static const struct IVBSAXAttributesVtbl VBSAXAttributesVtbl =
2122 {
2123     VBSAXAttributes_QueryInterface,
2124     VBSAXAttributes_AddRef,
2125     VBSAXAttributes_Release,
2126     VBSAXAttributes_GetTypeInfoCount,
2127     VBSAXAttributes_GetTypeInfo,
2128     VBSAXAttributes_GetIDsOfNames,
2129     VBSAXAttributes_Invoke,
2130     VBSAXAttributes_get_length,
2131     VBSAXAttributes_getURI,
2132     VBSAXAttributes_getLocalName,
2133     VBSAXAttributes_getQName,
2134     VBSAXAttributes_getIndexFromName,
2135     VBSAXAttributes_getIndexFromQName,
2136     VBSAXAttributes_getType,
2137     VBSAXAttributes_getTypeFromName,
2138     VBSAXAttributes_getTypeFromQName,
2139     VBSAXAttributes_getValue,
2140     VBSAXAttributes_getValueFromName,
2141     VBSAXAttributes_getValueFromQName
2142 };
2143
2144 static const tid_t mxattrs_iface_tids[] = {
2145     IMXAttributes_tid,
2146     0
2147 };
2148
2149 static dispex_static_data_t mxattrs_dispex = {
2150     NULL,
2151     IMXAttributes_tid,
2152     NULL,
2153     mxattrs_iface_tids
2154 };
2155
2156 HRESULT SAXAttributes_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
2157 {
2158     static const int default_count = 10;
2159     mxattributes *This;
2160
2161     TRACE("(%p, %p)\n", outer, ppObj);
2162
2163     This = heap_alloc( sizeof (*This) );
2164     if( !This )
2165         return E_OUTOFMEMORY;
2166
2167     This->IMXAttributes_iface.lpVtbl = &MXAttributesVtbl;
2168     This->ISAXAttributes_iface.lpVtbl = &SAXAttributesVtbl;
2169     This->IVBSAXAttributes_iface.lpVtbl = &VBSAXAttributesVtbl;
2170     This->ref = 1;
2171
2172     This->class_version = version;
2173
2174     This->attr = heap_alloc(default_count*sizeof(mxattribute));
2175     This->length = 0;
2176     This->allocated = default_count;
2177
2178     *ppObj = &This->IMXAttributes_iface;
2179
2180     init_dispex(&This->dispex, (IUnknown*)&This->IMXAttributes_iface, &mxattrs_dispex);
2181
2182     TRACE("returning iface %p\n", *ppObj);
2183
2184     return S_OK;
2185 }