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