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