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