[MSXML3] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / msxml3 / mxwriter.c
1 /*
2 * MXWriter implementation
3 *
4 * Copyright 2011-2014, 2016 Nikolay Sivov for CodeWeavers
5 * Copyright 2011 Thomas Mullaly
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #define COBJMACROS
23 #include "config.h"
24
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 #endif
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "ole2.h"
33
34 #include "msxml6.h"
35
36 #include "wine/debug.h"
37 #include "wine/list.h"
38
39 #include "msxml_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
42
43 static const WCHAR emptyW[] = {0};
44 static const WCHAR spaceW[] = {' '};
45 static const WCHAR quotW[] = {'\"'};
46 static const WCHAR closetagW[] = {'>','\r','\n'};
47 static const WCHAR crlfW[] = {'\r','\n'};
48 static const WCHAR entityW[] = {'<','!','E','N','T','I','T','Y',' '};
49 static const WCHAR publicW[] = {'P','U','B','L','I','C',' '};
50 static const WCHAR systemW[] = {'S','Y','S','T','E','M',' '};
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 MXWriter_BOM = 0,
105 MXWriter_DisableEscaping,
106 MXWriter_Indent,
107 MXWriter_OmitXmlDecl,
108 MXWriter_Standalone,
109 MXWriter_LastProp
110 } mxwriter_prop;
111
112 typedef enum
113 {
114 EscapeValue,
115 EscapeText
116 } escape_mode;
117
118 typedef struct
119 {
120 struct list entry;
121 char *data;
122 unsigned int allocated;
123 unsigned int written;
124 } encoded_buffer;
125
126 typedef struct
127 {
128 encoded_buffer encoded;
129 UINT code_page;
130 UINT utf16_total; /* total number of bytes written since last buffer reinitialization */
131 struct list blocks; /* only used when output was not set, for BSTR case */
132 } output_buffer;
133
134 typedef struct
135 {
136 DispatchEx dispex;
137 IMXWriter IMXWriter_iface;
138 ISAXContentHandler ISAXContentHandler_iface;
139 ISAXLexicalHandler ISAXLexicalHandler_iface;
140 ISAXDeclHandler ISAXDeclHandler_iface;
141 ISAXDTDHandler ISAXDTDHandler_iface;
142 ISAXErrorHandler ISAXErrorHandler_iface;
143 IVBSAXDeclHandler IVBSAXDeclHandler_iface;
144 IVBSAXLexicalHandler IVBSAXLexicalHandler_iface;
145 IVBSAXContentHandler IVBSAXContentHandler_iface;
146 IVBSAXDTDHandler IVBSAXDTDHandler_iface;
147 IVBSAXErrorHandler IVBSAXErrorHandler_iface;
148
149 LONG ref;
150 MSXML_VERSION class_version;
151
152 VARIANT_BOOL props[MXWriter_LastProp];
153 BOOL prop_changed;
154 BOOL cdata;
155
156 BOOL text; /* last node was text node, so we shouldn't indent next node */
157 BOOL newline; /* newline was already added as a part of previous call */
158 UINT indent; /* indentation level for next node */
159
160 BSTR version;
161
162 BSTR encoding; /* exact property value */
163 xml_encoding xml_enc;
164
165 /* contains a pending (or not closed yet) element name or NULL if
166 we don't have to close */
167 BSTR element;
168
169 IStream *dest;
170
171 output_buffer buffer;
172 } mxwriter;
173
174 typedef struct
175 {
176 BSTR qname;
177 BSTR local;
178 BSTR uri;
179 BSTR type;
180 BSTR value;
181 } mxattribute;
182
183 typedef struct
184 {
185 DispatchEx dispex;
186 IMXAttributes IMXAttributes_iface;
187 ISAXAttributes ISAXAttributes_iface;
188 IVBSAXAttributes IVBSAXAttributes_iface;
189 LONG ref;
190
191 MSXML_VERSION class_version;
192
193 mxattribute *attr;
194 int length;
195 int allocated;
196 } mxattributes;
197
198 static inline mxattributes *impl_from_IMXAttributes( IMXAttributes *iface )
199 {
200 return CONTAINING_RECORD(iface, mxattributes, IMXAttributes_iface);
201 }
202
203 static inline mxattributes *impl_from_ISAXAttributes( ISAXAttributes *iface )
204 {
205 return CONTAINING_RECORD(iface, mxattributes, ISAXAttributes_iface);
206 }
207
208 static inline mxattributes *impl_from_IVBSAXAttributes( IVBSAXAttributes *iface )
209 {
210 return CONTAINING_RECORD(iface, mxattributes, IVBSAXAttributes_iface);
211 }
212
213 static HRESULT mxattributes_grow(mxattributes *This)
214 {
215 if (This->length < This->allocated) return S_OK;
216
217 This->allocated *= 2;
218 This->attr = heap_realloc(This->attr, This->allocated*sizeof(mxattribute));
219
220 return This->attr ? S_OK : E_OUTOFMEMORY;
221 }
222
223 static xml_encoding parse_encoding_name(const WCHAR *encoding)
224 {
225 int min, max, n, c;
226
227 min = 0;
228 max = ARRAY_SIZE(xml_encoding_map) - 1;
229
230 while (min <= max)
231 {
232 n = (min+max)/2;
233
234 c = strcmpiW(xml_encoding_map[n].encoding, encoding);
235 if (!c)
236 return xml_encoding_map[n].enc;
237
238 if (c > 0)
239 max = n-1;
240 else
241 min = n+1;
242 }
243
244 return XmlEncoding_Unknown;
245 }
246
247 static HRESULT init_encoded_buffer(encoded_buffer *buffer)
248 {
249 const int initial_len = 0x1000;
250 buffer->data = heap_alloc(initial_len);
251 if (!buffer->data) return E_OUTOFMEMORY;
252
253 memset(buffer->data, 0, 4);
254 buffer->allocated = initial_len;
255 buffer->written = 0;
256
257 return S_OK;
258 }
259
260 static void free_encoded_buffer(encoded_buffer *buffer)
261 {
262 heap_free(buffer->data);
263 }
264
265 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
266 {
267 const struct xml_encoding_data *data;
268
269 if (encoding == XmlEncoding_Unknown)
270 {
271 FIXME("unsupported encoding %d\n", encoding);
272 return E_NOTIMPL;
273 }
274
275 data = &xml_encoding_map[encoding];
276 *cp = data->cp;
277
278 return S_OK;
279 }
280
281 static HRESULT init_output_buffer(xml_encoding encoding, output_buffer *buffer)
282 {
283 HRESULT hr;
284
285 hr = get_code_page(encoding, &buffer->code_page);
286 if (hr != S_OK)
287 return hr;
288
289 hr = init_encoded_buffer(&buffer->encoded);
290 if (hr != S_OK)
291 return hr;
292
293 list_init(&buffer->blocks);
294 buffer->utf16_total = 0;
295
296 return S_OK;
297 }
298
299 static void free_output_buffer(output_buffer *buffer)
300 {
301 encoded_buffer *cur, *cur2;
302
303 free_encoded_buffer(&buffer->encoded);
304
305 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &buffer->blocks, encoded_buffer, entry)
306 {
307 list_remove(&cur->entry);
308 free_encoded_buffer(cur);
309 heap_free(cur);
310 }
311 }
312
313 static HRESULT write_output_buffer(mxwriter *writer, const WCHAR *data, int len)
314 {
315 output_buffer *buffer = &writer->buffer;
316 encoded_buffer *buff;
317 unsigned int written;
318 int src_len;
319
320 if (!len || !*data)
321 return S_OK;
322
323 src_len = len == -1 ? strlenW(data) : len;
324 if (writer->dest)
325 {
326 buff = &buffer->encoded;
327
328 if (buffer->code_page == ~0)
329 {
330 unsigned int avail = buff->allocated - buff->written;
331
332 src_len *= sizeof(WCHAR);
333 written = min(avail, src_len);
334
335 /* fill internal buffer first */
336 if (avail)
337 {
338 memcpy(buff->data + buff->written, data, written);
339 data += written / sizeof(WCHAR);
340 buff->written += written;
341 avail -= written;
342 src_len -= written;
343 }
344
345 if (!avail)
346 {
347 IStream_Write(writer->dest, buff->data, buff->written, &written);
348 buff->written = 0;
349 if (src_len >= buff->allocated)
350 IStream_Write(writer->dest, data, src_len, &written);
351 else if (src_len)
352 {
353 memcpy(buff->data, data, src_len);
354 buff->written += src_len;
355 }
356 }
357 }
358 else
359 {
360 unsigned int avail = buff->allocated - buff->written;
361 int length;
362
363 length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, NULL, 0, NULL, NULL);
364 if (avail >= length)
365 {
366 length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, buff->data + buff->written, length, NULL, NULL);
367 buff->written += length;
368 }
369 else
370 {
371 /* drain what we go so far */
372 if (buff->written)
373 {
374 IStream_Write(writer->dest, buff->data, buff->written, &written);
375 buff->written = 0;
376 avail = buff->allocated;
377 }
378
379 if (avail >= length)
380 {
381 length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, buff->data + buff->written, length, NULL, NULL);
382 buff->written += length;
383 }
384 else
385 {
386 char *mb;
387
388 /* if current chunk is larger than total buffer size, convert it at once using temporary allocated buffer */
389 mb = heap_alloc(length);
390 if (!mb)
391 return E_OUTOFMEMORY;
392
393 length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, mb, length, NULL, NULL);
394 IStream_Write(writer->dest, mb, length, &written);
395 heap_free(mb);
396 }
397 }
398 }
399 }
400 /* When writer has no output set we have to accumulate everything to return it later in a form of BSTR.
401 To achieve that:
402
403 - fill a buffer already allocated as part of output buffer;
404 - when current buffer is full, allocate another one and switch to it; buffers themselves never grow,
405 but are linked together, with head pointing to first allocated buffer after initial one got filled;
406 - later during get_output() contents are concatenated by copying one after another to destination BSTR buffer,
407 that's returned to the client. */
408 else
409 {
410 /* select last used block */
411 if (list_empty(&buffer->blocks))
412 buff = &buffer->encoded;
413 else
414 buff = LIST_ENTRY(list_tail(&buffer->blocks), encoded_buffer, entry);
415
416 src_len *= sizeof(WCHAR);
417 while (src_len)
418 {
419 unsigned int avail = buff->allocated - buff->written;
420 unsigned int written = min(avail, src_len);
421
422 if (avail)
423 {
424 memcpy(buff->data + buff->written, data, written);
425 buff->written += written;
426 buffer->utf16_total += written;
427 src_len -= written;
428 }
429
430 /* alloc new block if needed and retry */
431 if (src_len)
432 {
433 encoded_buffer *next = heap_alloc(sizeof(*next));
434 HRESULT hr;
435
436 if (FAILED(hr = init_encoded_buffer(next))) {
437 heap_free(next);
438 return hr;
439 }
440
441 list_add_tail(&buffer->blocks, &next->entry);
442 buff = next;
443 }
444 }
445 }
446
447 return S_OK;
448 }
449
450 static HRESULT write_output_buffer_quoted(mxwriter *writer, const WCHAR *data, int len)
451 {
452 write_output_buffer(writer, quotW, 1);
453 write_output_buffer(writer, data, len);
454 write_output_buffer(writer, quotW, 1);
455
456 return S_OK;
457 }
458
459 /* frees buffer data, reallocates with a default lengths */
460 static void close_output_buffer(mxwriter *writer)
461 {
462 encoded_buffer *cur, *cur2;
463
464 heap_free(writer->buffer.encoded.data);
465
466 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &writer->buffer.blocks, encoded_buffer, entry)
467 {
468 list_remove(&cur->entry);
469 free_encoded_buffer(cur);
470 heap_free(cur);
471 }
472
473 init_encoded_buffer(&writer->buffer.encoded);
474 get_code_page(writer->xml_enc, &writer->buffer.code_page);
475 writer->buffer.utf16_total = 0;
476 list_init(&writer->buffer.blocks);
477 }
478
479 /* Escapes special characters like:
480 '<' -> "&lt;"
481 '&' -> "&amp;"
482 '"' -> "&quot;"
483 '>' -> "&gt;"
484
485 On call 'len' contains a length of 'str' in chars or -1 if it's null terminated.
486 After a call it's updated with actual new length if it wasn't -1 initially.
487 */
488 static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len)
489 {
490 static const WCHAR ltW[] = {'&','l','t',';'};
491 static const WCHAR ampW[] = {'&','a','m','p',';'};
492 static const WCHAR equotW[] = {'&','q','u','o','t',';'};
493 static const WCHAR gtW[] = {'&','g','t',';'};
494
495 const int default_alloc = 100;
496 const int grow_thresh = 10;
497 int p = *len, conv_len;
498 WCHAR *ptr, *ret;
499
500 /* default buffer size to something if length is unknown */
501 conv_len = max(2**len, default_alloc);
502 ptr = ret = heap_alloc(conv_len*sizeof(WCHAR));
503
504 while (p)
505 {
506 if (ptr - ret > conv_len - grow_thresh)
507 {
508 int written = ptr - ret;
509 conv_len *= 2;
510 ptr = ret = heap_realloc(ret, conv_len*sizeof(WCHAR));
511 ptr += written;
512 }
513
514 switch (*str)
515 {
516 case '<':
517 memcpy(ptr, ltW, sizeof(ltW));
518 ptr += ARRAY_SIZE(ltW);
519 break;
520 case '&':
521 memcpy(ptr, ampW, sizeof(ampW));
522 ptr += ARRAY_SIZE(ampW);
523 break;
524 case '>':
525 memcpy(ptr, gtW, sizeof(gtW));
526 ptr += ARRAY_SIZE(gtW);
527 break;
528 case '"':
529 if (mode == EscapeValue)
530 {
531 memcpy(ptr, equotW, sizeof(equotW));
532 ptr += ARRAY_SIZE(equotW);
533 break;
534 }
535 /* fallthrough for text mode */
536 default:
537 *ptr++ = *str;
538 break;
539 }
540
541 str++;
542 p--;
543 }
544
545 *len = ptr-ret;
546 *++ptr = 0;
547
548 return ret;
549 }
550
551 static void write_prolog_buffer(mxwriter *writer)
552 {
553 static const WCHAR versionW[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','='};
554 static const WCHAR encodingW[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
555 static const WCHAR standaloneW[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
556 static const WCHAR yesW[] = {'y','e','s','\"','?','>'};
557 static const WCHAR noW[] = {'n','o','\"','?','>'};
558
559 /* version */
560 write_output_buffer(writer, versionW, ARRAY_SIZE(versionW));
561 write_output_buffer_quoted(writer, writer->version, -1);
562
563 /* encoding */
564 write_output_buffer(writer, encodingW, ARRAY_SIZE(encodingW));
565
566 if (writer->dest)
567 write_output_buffer(writer, writer->encoding, -1);
568 else
569 write_output_buffer(writer, utf16W, ARRAY_SIZE(utf16W) - 1);
570 write_output_buffer(writer, quotW, 1);
571
572 /* standalone */
573 write_output_buffer(writer, standaloneW, ARRAY_SIZE(standaloneW));
574 if (writer->props[MXWriter_Standalone] == VARIANT_TRUE)
575 write_output_buffer(writer, yesW, ARRAY_SIZE(yesW));
576 else
577 write_output_buffer(writer, noW, ARRAY_SIZE(noW));
578
579 write_output_buffer(writer, crlfW, ARRAY_SIZE(crlfW));
580 writer->newline = TRUE;
581 }
582
583 /* Attempts to the write data from the mxwriter's buffer to
584 * the destination stream (if there is one).
585 */
586 static HRESULT write_data_to_stream(mxwriter *writer)
587 {
588 encoded_buffer *buffer = &writer->buffer.encoded;
589 ULONG written = 0;
590
591 if (!writer->dest)
592 return S_OK;
593
594 if (buffer->written == 0)
595 {
596 if (writer->xml_enc == XmlEncoding_UTF8)
597 IStream_Write(writer->dest, buffer->data, 0, &written);
598 }
599 else
600 {
601 IStream_Write(writer->dest, buffer->data, buffer->written, &written);
602 buffer->written = 0;
603 }
604
605 return S_OK;
606 }
607
608 /* Newly added element start tag left unclosed cause for empty elements
609 we have to close it differently. */
610 static void close_element_starttag(mxwriter *writer)
611 {
612 static const WCHAR gtW[] = {'>'};
613 if (!writer->element) return;
614 write_output_buffer(writer, gtW, 1);
615 }
616
617 static void write_node_indent(mxwriter *writer)
618 {
619 static const WCHAR tabW[] = {'\t'};
620 int indent = writer->indent;
621
622 if (!writer->props[MXWriter_Indent] || writer->text)
623 {
624 writer->text = FALSE;
625 return;
626 }
627
628 /* This is to workaround PI output logic that always puts newline chars,
629 document prolog PI does that too. */
630 if (!writer->newline)
631 write_output_buffer(writer, crlfW, ARRAY_SIZE(crlfW));
632 while (indent--)
633 write_output_buffer(writer, tabW, 1);
634
635 writer->newline = FALSE;
636 writer->text = FALSE;
637 }
638
639 static inline void writer_inc_indent(mxwriter *This)
640 {
641 This->indent++;
642 }
643
644 static inline void writer_dec_indent(mxwriter *This)
645 {
646 if (This->indent) This->indent--;
647 /* depth is decreased only when element is closed, meaning it's not a text node
648 at this point */
649 This->text = FALSE;
650 }
651
652 static void set_element_name(mxwriter *This, const WCHAR *name, int len)
653 {
654 SysFreeString(This->element);
655 if (name)
656 This->element = len != -1 ? SysAllocStringLen(name, len) : SysAllocString(name);
657 else
658 This->element = NULL;
659 }
660
661 static inline HRESULT flush_output_buffer(mxwriter *This)
662 {
663 close_element_starttag(This);
664 set_element_name(This, NULL, 0);
665 This->cdata = FALSE;
666 return write_data_to_stream(This);
667 }
668
669 /* Resets the mxwriter's output buffer by closing it, then creating a new
670 * output buffer using the given encoding.
671 */
672 static inline void reset_output_buffer(mxwriter *This)
673 {
674 close_output_buffer(This);
675 }
676
677 static HRESULT writer_set_property(mxwriter *writer, mxwriter_prop property, VARIANT_BOOL value)
678 {
679 writer->props[property] = value;
680 writer->prop_changed = TRUE;
681 return S_OK;
682 }
683
684 static HRESULT writer_get_property(const mxwriter *writer, mxwriter_prop property, VARIANT_BOOL *value)
685 {
686 if (!value) return E_POINTER;
687 *value = writer->props[property];
688 return S_OK;
689 }
690
691 static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
692 {
693 return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
694 }
695
696 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
697 {
698 return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
699 }
700
701 static inline mxwriter *impl_from_IVBSAXContentHandler(IVBSAXContentHandler *iface)
702 {
703 return CONTAINING_RECORD(iface, mxwriter, IVBSAXContentHandler_iface);
704 }
705
706 static inline mxwriter *impl_from_ISAXLexicalHandler(ISAXLexicalHandler *iface)
707 {
708 return CONTAINING_RECORD(iface, mxwriter, ISAXLexicalHandler_iface);
709 }
710
711 static inline mxwriter *impl_from_IVBSAXLexicalHandler(IVBSAXLexicalHandler *iface)
712 {
713 return CONTAINING_RECORD(iface, mxwriter, IVBSAXLexicalHandler_iface);
714 }
715
716 static inline mxwriter *impl_from_ISAXDeclHandler(ISAXDeclHandler *iface)
717 {
718 return CONTAINING_RECORD(iface, mxwriter, ISAXDeclHandler_iface);
719 }
720
721 static inline mxwriter *impl_from_IVBSAXDeclHandler(IVBSAXDeclHandler *iface)
722 {
723 return CONTAINING_RECORD(iface, mxwriter, IVBSAXDeclHandler_iface);
724 }
725
726 static inline mxwriter *impl_from_ISAXDTDHandler(ISAXDTDHandler *iface)
727 {
728 return CONTAINING_RECORD(iface, mxwriter, ISAXDTDHandler_iface);
729 }
730
731 static inline mxwriter *impl_from_IVBSAXDTDHandler(IVBSAXDTDHandler *iface)
732 {
733 return CONTAINING_RECORD(iface, mxwriter, IVBSAXDTDHandler_iface);
734 }
735
736 static inline mxwriter *impl_from_ISAXErrorHandler(ISAXErrorHandler *iface)
737 {
738 return CONTAINING_RECORD(iface, mxwriter, ISAXErrorHandler_iface);
739 }
740
741 static inline mxwriter *impl_from_IVBSAXErrorHandler(IVBSAXErrorHandler *iface)
742 {
743 return CONTAINING_RECORD(iface, mxwriter, IVBSAXErrorHandler_iface);
744 }
745
746 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
747 {
748 mxwriter *This = impl_from_IMXWriter( iface );
749
750 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
751
752 *obj = NULL;
753
754 if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
755 IsEqualGUID( riid, &IID_IDispatch ) ||
756 IsEqualGUID( riid, &IID_IUnknown ) )
757 {
758 *obj = &This->IMXWriter_iface;
759 }
760 else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
761 {
762 *obj = &This->ISAXContentHandler_iface;
763 }
764 else if ( IsEqualGUID( riid, &IID_ISAXLexicalHandler ) )
765 {
766 *obj = &This->ISAXLexicalHandler_iface;
767 }
768 else if ( IsEqualGUID( riid, &IID_ISAXDeclHandler ) )
769 {
770 *obj = &This->ISAXDeclHandler_iface;
771 }
772 else if ( IsEqualGUID( riid, &IID_ISAXDTDHandler ) )
773 {
774 *obj = &This->ISAXDTDHandler_iface;
775 }
776 else if ( IsEqualGUID( riid, &IID_ISAXErrorHandler ) )
777 {
778 *obj = &This->ISAXErrorHandler_iface;
779 }
780 else if ( IsEqualGUID( riid, &IID_IVBSAXDeclHandler ) )
781 {
782 *obj = &This->IVBSAXDeclHandler_iface;
783 }
784 else if ( IsEqualGUID( riid, &IID_IVBSAXLexicalHandler ) )
785 {
786 *obj = &This->IVBSAXLexicalHandler_iface;
787 }
788 else if ( IsEqualGUID( riid, &IID_IVBSAXContentHandler ) )
789 {
790 *obj = &This->IVBSAXContentHandler_iface;
791 }
792 else if ( IsEqualGUID( riid, &IID_IVBSAXDTDHandler ) )
793 {
794 *obj = &This->IVBSAXDTDHandler_iface;
795 }
796 else if ( IsEqualGUID( riid, &IID_IVBSAXErrorHandler ) )
797 {
798 *obj = &This->IVBSAXErrorHandler_iface;
799 }
800 else if (dispex_query_interface(&This->dispex, riid, obj))
801 {
802 return *obj ? S_OK : E_NOINTERFACE;
803 }
804 else
805 {
806 ERR("interface %s not implemented\n", debugstr_guid(riid));
807 *obj = NULL;
808 return E_NOINTERFACE;
809 }
810
811 IMXWriter_AddRef(iface);
812 return S_OK;
813 }
814
815 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
816 {
817 mxwriter *This = impl_from_IMXWriter( iface );
818 LONG ref = InterlockedIncrement(&This->ref);
819
820 TRACE("(%p)->(%d)\n", This, ref);
821
822 return ref;
823 }
824
825 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
826 {
827 mxwriter *This = impl_from_IMXWriter( iface );
828 ULONG ref = InterlockedDecrement(&This->ref);
829
830 TRACE("(%p)->(%d)\n", This, ref);
831
832 if(!ref)
833 {
834 /* Windows flushes the buffer when the interface is destroyed. */
835 flush_output_buffer(This);
836 free_output_buffer(&This->buffer);
837
838 if (This->dest) IStream_Release(This->dest);
839 SysFreeString(This->version);
840 SysFreeString(This->encoding);
841
842 SysFreeString(This->element);
843 heap_free(This);
844 }
845
846 return ref;
847 }
848
849 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
850 {
851 mxwriter *This = impl_from_IMXWriter( iface );
852 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
853 }
854
855 static HRESULT WINAPI mxwriter_GetTypeInfo(
856 IMXWriter *iface,
857 UINT iTInfo, LCID lcid,
858 ITypeInfo** ppTInfo )
859 {
860 mxwriter *This = impl_from_IMXWriter( iface );
861 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
862 iTInfo, lcid, ppTInfo);
863 }
864
865 static HRESULT WINAPI mxwriter_GetIDsOfNames(
866 IMXWriter *iface,
867 REFIID riid, LPOLESTR* rgszNames,
868 UINT cNames, LCID lcid, DISPID* rgDispId )
869 {
870 mxwriter *This = impl_from_IMXWriter( iface );
871 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
872 riid, rgszNames, cNames, lcid, rgDispId);
873 }
874
875 static HRESULT WINAPI mxwriter_Invoke(
876 IMXWriter *iface,
877 DISPID dispIdMember, REFIID riid, LCID lcid,
878 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
879 EXCEPINFO* pExcepInfo, UINT* puArgErr )
880 {
881 mxwriter *This = impl_from_IMXWriter( iface );
882 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
883 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
884 }
885
886 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
887 {
888 mxwriter *This = impl_from_IMXWriter( iface );
889 HRESULT hr;
890
891 TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
892
893 hr = flush_output_buffer(This);
894 if (FAILED(hr))
895 return hr;
896
897 switch (V_VT(&dest))
898 {
899 case VT_EMPTY:
900 {
901 if (This->dest) IStream_Release(This->dest);
902 This->dest = NULL;
903 reset_output_buffer(This);
904 break;
905 }
906 case VT_UNKNOWN:
907 {
908 IStream *stream;
909
910 hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
911 if (hr == S_OK)
912 {
913 /* Recreate the output buffer to make sure it's using the correct encoding. */
914 reset_output_buffer(This);
915
916 if (This->dest) IStream_Release(This->dest);
917 This->dest = stream;
918 break;
919 }
920
921 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
922 return E_NOTIMPL;
923 }
924 default:
925 FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
926 return E_NOTIMPL;
927 }
928
929 return S_OK;
930 }
931
932 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
933 {
934 mxwriter *This = impl_from_IMXWriter( iface );
935
936 TRACE("(%p)->(%p)\n", This, dest);
937
938 if (!dest) return E_POINTER;
939
940 if (This->dest)
941 {
942 /* we only support IStream output so far */
943 V_VT(dest) = VT_UNKNOWN;
944 V_UNKNOWN(dest) = (IUnknown*)This->dest;
945 IStream_AddRef(This->dest);
946 }
947 else
948 {
949 encoded_buffer *buff;
950 char *dest_ptr;
951 HRESULT hr;
952
953 hr = flush_output_buffer(This);
954 if (FAILED(hr))
955 return hr;
956
957 V_VT(dest) = VT_BSTR;
958 V_BSTR(dest) = SysAllocStringLen(NULL, This->buffer.utf16_total / sizeof(WCHAR));
959 if (!V_BSTR(dest))
960 return E_OUTOFMEMORY;
961
962 dest_ptr = (char*)V_BSTR(dest);
963 buff = &This->buffer.encoded;
964
965 if (buff->written)
966 {
967 memcpy(dest_ptr, buff->data, buff->written);
968 dest_ptr += buff->written;
969 }
970
971 LIST_FOR_EACH_ENTRY(buff, &This->buffer.blocks, encoded_buffer, entry)
972 {
973 memcpy(dest_ptr, buff->data, buff->written);
974 dest_ptr += buff->written;
975 }
976 }
977
978 return S_OK;
979 }
980
981 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
982 {
983 mxwriter *This = impl_from_IMXWriter( iface );
984 xml_encoding enc;
985 HRESULT hr;
986
987 TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
988
989 enc = parse_encoding_name(encoding);
990 if (enc == XmlEncoding_Unknown)
991 {
992 FIXME("unsupported encoding %s\n", debugstr_w(encoding));
993 return E_INVALIDARG;
994 }
995
996 hr = flush_output_buffer(This);
997 if (FAILED(hr))
998 return hr;
999
1000 SysReAllocString(&This->encoding, encoding);
1001 This->xml_enc = enc;
1002
1003 TRACE("got encoding %d\n", This->xml_enc);
1004 reset_output_buffer(This);
1005 return S_OK;
1006 }
1007
1008 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
1009 {
1010 mxwriter *This = impl_from_IMXWriter( iface );
1011
1012 TRACE("(%p)->(%p)\n", This, encoding);
1013
1014 if (!encoding) return E_POINTER;
1015
1016 *encoding = SysAllocString(This->encoding);
1017 if (!*encoding) return E_OUTOFMEMORY;
1018
1019 return S_OK;
1020 }
1021
1022 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
1023 {
1024 mxwriter *This = impl_from_IMXWriter( iface );
1025
1026 TRACE("(%p)->(%d)\n", This, value);
1027 return writer_set_property(This, MXWriter_BOM, value);
1028 }
1029
1030 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
1031 {
1032 mxwriter *This = impl_from_IMXWriter( iface );
1033
1034 TRACE("(%p)->(%p)\n", This, value);
1035 return writer_get_property(This, MXWriter_BOM, value);
1036 }
1037
1038 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
1039 {
1040 mxwriter *This = impl_from_IMXWriter( iface );
1041
1042 TRACE("(%p)->(%d)\n", This, value);
1043 return writer_set_property(This, MXWriter_Indent, value);
1044 }
1045
1046 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
1047 {
1048 mxwriter *This = impl_from_IMXWriter( iface );
1049
1050 TRACE("(%p)->(%p)\n", This, value);
1051 return writer_get_property(This, MXWriter_Indent, value);
1052 }
1053
1054 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
1055 {
1056 mxwriter *This = impl_from_IMXWriter( iface );
1057
1058 TRACE("(%p)->(%d)\n", This, value);
1059 return writer_set_property(This, MXWriter_Standalone, value);
1060 }
1061
1062 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
1063 {
1064 mxwriter *This = impl_from_IMXWriter( iface );
1065
1066 TRACE("(%p)->(%p)\n", This, value);
1067 return writer_get_property(This, MXWriter_Standalone, value);
1068 }
1069
1070 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
1071 {
1072 mxwriter *This = impl_from_IMXWriter( iface );
1073
1074 TRACE("(%p)->(%d)\n", This, value);
1075 return writer_set_property(This, MXWriter_OmitXmlDecl, value);
1076 }
1077
1078 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
1079 {
1080 mxwriter *This = impl_from_IMXWriter( iface );
1081
1082 TRACE("(%p)->(%p)\n", This, value);
1083 return writer_get_property(This, MXWriter_OmitXmlDecl, value);
1084 }
1085
1086 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
1087 {
1088 mxwriter *This = impl_from_IMXWriter( iface );
1089
1090 TRACE("(%p)->(%s)\n", This, debugstr_w(version));
1091
1092 if (!version) return E_INVALIDARG;
1093
1094 SysFreeString(This->version);
1095 This->version = SysAllocString(version);
1096
1097 return S_OK;
1098 }
1099
1100 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
1101 {
1102 mxwriter *This = impl_from_IMXWriter( iface );
1103
1104 TRACE("(%p)->(%p)\n", This, version);
1105
1106 if (!version) return E_POINTER;
1107
1108 return return_bstr(This->version, version);
1109 }
1110
1111 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
1112 {
1113 mxwriter *This = impl_from_IMXWriter( iface );
1114
1115 TRACE("(%p)->(%d)\n", This, value);
1116 return writer_set_property(This, MXWriter_DisableEscaping, value);
1117 }
1118
1119 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
1120 {
1121 mxwriter *This = impl_from_IMXWriter( iface );
1122
1123 TRACE("(%p)->(%p)\n", This, value);
1124 return writer_get_property(This, MXWriter_DisableEscaping, value);
1125 }
1126
1127 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
1128 {
1129 mxwriter *This = impl_from_IMXWriter( iface );
1130 TRACE("(%p)\n", This);
1131 return flush_output_buffer(This);
1132 }
1133
1134 static const struct IMXWriterVtbl MXWriterVtbl =
1135 {
1136 mxwriter_QueryInterface,
1137 mxwriter_AddRef,
1138 mxwriter_Release,
1139 mxwriter_GetTypeInfoCount,
1140 mxwriter_GetTypeInfo,
1141 mxwriter_GetIDsOfNames,
1142 mxwriter_Invoke,
1143 mxwriter_put_output,
1144 mxwriter_get_output,
1145 mxwriter_put_encoding,
1146 mxwriter_get_encoding,
1147 mxwriter_put_byteOrderMark,
1148 mxwriter_get_byteOrderMark,
1149 mxwriter_put_indent,
1150 mxwriter_get_indent,
1151 mxwriter_put_standalone,
1152 mxwriter_get_standalone,
1153 mxwriter_put_omitXMLDeclaration,
1154 mxwriter_get_omitXMLDeclaration,
1155 mxwriter_put_version,
1156 mxwriter_get_version,
1157 mxwriter_put_disableOutputEscaping,
1158 mxwriter_get_disableOutputEscaping,
1159 mxwriter_flush
1160 };
1161
1162 /*** ISAXContentHandler ***/
1163 static HRESULT WINAPI SAXContentHandler_QueryInterface(
1164 ISAXContentHandler *iface,
1165 REFIID riid,
1166 void **obj)
1167 {
1168 mxwriter *This = impl_from_ISAXContentHandler( iface );
1169 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1170 }
1171
1172 static ULONG WINAPI SAXContentHandler_AddRef(ISAXContentHandler *iface)
1173 {
1174 mxwriter *This = impl_from_ISAXContentHandler( iface );
1175 return IMXWriter_AddRef(&This->IMXWriter_iface);
1176 }
1177
1178 static ULONG WINAPI SAXContentHandler_Release(ISAXContentHandler *iface)
1179 {
1180 mxwriter *This = impl_from_ISAXContentHandler( iface );
1181 return IMXWriter_Release(&This->IMXWriter_iface);
1182 }
1183
1184 static HRESULT WINAPI SAXContentHandler_putDocumentLocator(
1185 ISAXContentHandler *iface,
1186 ISAXLocator *locator)
1187 {
1188 mxwriter *This = impl_from_ISAXContentHandler( iface );
1189 FIXME("(%p)->(%p)\n", This, locator);
1190 return E_NOTIMPL;
1191 }
1192
1193 static HRESULT WINAPI SAXContentHandler_startDocument(ISAXContentHandler *iface)
1194 {
1195 mxwriter *This = impl_from_ISAXContentHandler( iface );
1196
1197 TRACE("(%p)\n", This);
1198
1199 /* If properties have been changed since the last "endDocument" call
1200 * we need to reset the output buffer. If we don't the output buffer
1201 * could end up with multiple XML documents in it, plus this seems to
1202 * be how Windows works.
1203 */
1204 if (This->prop_changed) {
1205 reset_output_buffer(This);
1206 This->prop_changed = FALSE;
1207 }
1208
1209 if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
1210
1211 write_prolog_buffer(This);
1212
1213 if (This->dest && This->xml_enc == XmlEncoding_UTF16) {
1214 static const char utf16BOM[] = {0xff,0xfe};
1215
1216 if (This->props[MXWriter_BOM] == VARIANT_TRUE)
1217 /* Windows passes a NULL pointer as the pcbWritten parameter and
1218 * ignores any error codes returned from this Write call.
1219 */
1220 IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
1221 }
1222
1223 return S_OK;
1224 }
1225
1226 static HRESULT WINAPI SAXContentHandler_endDocument(ISAXContentHandler *iface)
1227 {
1228 mxwriter *This = impl_from_ISAXContentHandler( iface );
1229 TRACE("(%p)\n", This);
1230 This->prop_changed = FALSE;
1231 return flush_output_buffer(This);
1232 }
1233
1234 static HRESULT WINAPI SAXContentHandler_startPrefixMapping(
1235 ISAXContentHandler *iface,
1236 const WCHAR *prefix,
1237 int nprefix,
1238 const WCHAR *uri,
1239 int nuri)
1240 {
1241 mxwriter *This = impl_from_ISAXContentHandler( iface );
1242 TRACE("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
1243 return S_OK;
1244 }
1245
1246 static HRESULT WINAPI SAXContentHandler_endPrefixMapping(
1247 ISAXContentHandler *iface,
1248 const WCHAR *prefix,
1249 int nprefix)
1250 {
1251 mxwriter *This = impl_from_ISAXContentHandler( iface );
1252 TRACE("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
1253 return S_OK;
1254 }
1255
1256 static void mxwriter_write_attribute(mxwriter *writer, const WCHAR *qname, int qname_len,
1257 const WCHAR *value, int value_len, BOOL escape)
1258 {
1259 static const WCHAR eqW[] = {'='};
1260
1261 /* space separator in front of every attribute */
1262 write_output_buffer(writer, spaceW, 1);
1263 write_output_buffer(writer, qname, qname_len);
1264 write_output_buffer(writer, eqW, 1);
1265
1266 if (escape)
1267 {
1268 WCHAR *escaped = get_escaped_string(value, EscapeValue, &value_len);
1269 write_output_buffer_quoted(writer, escaped, value_len);
1270 heap_free(escaped);
1271 }
1272 else
1273 write_output_buffer_quoted(writer, value, value_len);
1274 }
1275
1276 static void mxwriter_write_starttag(mxwriter *writer, const WCHAR *qname, int len)
1277 {
1278 static const WCHAR ltW[] = {'<'};
1279
1280 close_element_starttag(writer);
1281 set_element_name(writer, qname ? qname : emptyW, qname ? len : 0);
1282
1283 write_node_indent(writer);
1284
1285 write_output_buffer(writer, ltW, 1);
1286 write_output_buffer(writer, qname ? qname : emptyW, qname ? len : 0);
1287 writer_inc_indent(writer);
1288 }
1289
1290 static HRESULT WINAPI SAXContentHandler_startElement(
1291 ISAXContentHandler *iface,
1292 const WCHAR *namespaceUri,
1293 int nnamespaceUri,
1294 const WCHAR *local_name,
1295 int nlocal_name,
1296 const WCHAR *QName,
1297 int nQName,
1298 ISAXAttributes *attr)
1299 {
1300 mxwriter *This = impl_from_ISAXContentHandler( iface );
1301
1302 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
1303 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
1304
1305 if (((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6) ||
1306 (nQName == -1 && This->class_version == MSXML6))
1307 return E_INVALIDARG;
1308
1309 mxwriter_write_starttag(This, QName, nQName);
1310
1311 if (attr)
1312 {
1313 int length, i, escape;
1314 HRESULT hr;
1315
1316 hr = ISAXAttributes_getLength(attr, &length);
1317 if (FAILED(hr)) return hr;
1318
1319 escape = This->props[MXWriter_DisableEscaping] == VARIANT_FALSE ||
1320 (This->class_version == MSXML4 || This->class_version == MSXML6);
1321
1322 for (i = 0; i < length; i++)
1323 {
1324 int qname_len = 0, value_len = 0;
1325 const WCHAR *qname, *value;
1326
1327 hr = ISAXAttributes_getQName(attr, i, &qname, &qname_len);
1328 if (FAILED(hr)) return hr;
1329
1330 hr = ISAXAttributes_getValue(attr, i, &value, &value_len);
1331 if (FAILED(hr)) return hr;
1332
1333 mxwriter_write_attribute(This, qname, qname_len, value, value_len, escape);
1334 }
1335 }
1336
1337 return S_OK;
1338 }
1339
1340 static HRESULT WINAPI SAXContentHandler_endElement(
1341 ISAXContentHandler *iface,
1342 const WCHAR *namespaceUri,
1343 int nnamespaceUri,
1344 const WCHAR * local_name,
1345 int nlocal_name,
1346 const WCHAR *QName,
1347 int nQName)
1348 {
1349 mxwriter *This = impl_from_ISAXContentHandler( iface );
1350
1351 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(namespaceUri, nnamespaceUri), nnamespaceUri,
1352 debugstr_wn(local_name, nlocal_name), nlocal_name, debugstr_wn(QName, nQName), nQName);
1353
1354 if (((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6) ||
1355 (nQName == -1 && This->class_version == MSXML6))
1356 return E_INVALIDARG;
1357
1358 writer_dec_indent(This);
1359
1360 if (This->element)
1361 {
1362 static const WCHAR closeW[] = {'/','>'};
1363 write_output_buffer(This, closeW, 2);
1364 }
1365 else
1366 {
1367 static const WCHAR closetagW[] = {'<','/'};
1368 static const WCHAR gtW[] = {'>'};
1369
1370 write_node_indent(This);
1371 write_output_buffer(This, closetagW, 2);
1372 write_output_buffer(This, QName, nQName);
1373 write_output_buffer(This, gtW, 1);
1374 }
1375
1376 set_element_name(This, NULL, 0);
1377
1378 return S_OK;
1379 }
1380
1381 static HRESULT WINAPI SAXContentHandler_characters(
1382 ISAXContentHandler *iface,
1383 const WCHAR *chars,
1384 int nchars)
1385 {
1386 mxwriter *This = impl_from_ISAXContentHandler( iface );
1387
1388 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
1389
1390 if (!chars) return E_INVALIDARG;
1391
1392 close_element_starttag(This);
1393 set_element_name(This, NULL, 0);
1394
1395 if (!This->cdata)
1396 This->text = TRUE;
1397
1398 if (nchars)
1399 {
1400 if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE)
1401 write_output_buffer(This, chars, nchars);
1402 else
1403 {
1404 int len = nchars;
1405 WCHAR *escaped;
1406
1407 escaped = get_escaped_string(chars, EscapeText, &len);
1408 write_output_buffer(This, escaped, len);
1409 heap_free(escaped);
1410 }
1411 }
1412
1413 return S_OK;
1414 }
1415
1416 static HRESULT WINAPI SAXContentHandler_ignorableWhitespace(
1417 ISAXContentHandler *iface,
1418 const WCHAR *chars,
1419 int nchars)
1420 {
1421 mxwriter *This = impl_from_ISAXContentHandler( iface );
1422
1423 TRACE("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
1424
1425 if (!chars) return E_INVALIDARG;
1426
1427 write_output_buffer(This, chars, nchars);
1428
1429 return S_OK;
1430 }
1431
1432 static HRESULT WINAPI SAXContentHandler_processingInstruction(
1433 ISAXContentHandler *iface,
1434 const WCHAR *target,
1435 int ntarget,
1436 const WCHAR *data,
1437 int ndata)
1438 {
1439 mxwriter *This = impl_from_ISAXContentHandler( iface );
1440 static const WCHAR openpiW[] = {'<','?'};
1441 static const WCHAR closepiW[] = {'?','>','\r','\n'};
1442
1443 TRACE("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
1444
1445 if (!target) return E_INVALIDARG;
1446
1447 write_node_indent(This);
1448 write_output_buffer(This, openpiW, ARRAY_SIZE(openpiW));
1449
1450 if (*target)
1451 write_output_buffer(This, target, ntarget);
1452
1453 if (data && *data && ndata)
1454 {
1455 write_output_buffer(This, spaceW, 1);
1456 write_output_buffer(This, data, ndata);
1457 }
1458
1459 write_output_buffer(This, closepiW, ARRAY_SIZE(closepiW));
1460 This->newline = TRUE;
1461
1462 return S_OK;
1463 }
1464
1465 static HRESULT WINAPI SAXContentHandler_skippedEntity(
1466 ISAXContentHandler *iface,
1467 const WCHAR *name,
1468 int nname)
1469 {
1470 mxwriter *This = impl_from_ISAXContentHandler( iface );
1471 FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
1472 return E_NOTIMPL;
1473 }
1474
1475 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl =
1476 {
1477 SAXContentHandler_QueryInterface,
1478 SAXContentHandler_AddRef,
1479 SAXContentHandler_Release,
1480 SAXContentHandler_putDocumentLocator,
1481 SAXContentHandler_startDocument,
1482 SAXContentHandler_endDocument,
1483 SAXContentHandler_startPrefixMapping,
1484 SAXContentHandler_endPrefixMapping,
1485 SAXContentHandler_startElement,
1486 SAXContentHandler_endElement,
1487 SAXContentHandler_characters,
1488 SAXContentHandler_ignorableWhitespace,
1489 SAXContentHandler_processingInstruction,
1490 SAXContentHandler_skippedEntity
1491 };
1492
1493 /*** ISAXLexicalHandler ***/
1494 static HRESULT WINAPI SAXLexicalHandler_QueryInterface(ISAXLexicalHandler *iface,
1495 REFIID riid, void **obj)
1496 {
1497 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1498 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1499 }
1500
1501 static ULONG WINAPI SAXLexicalHandler_AddRef(ISAXLexicalHandler *iface)
1502 {
1503 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1504 return IMXWriter_AddRef(&This->IMXWriter_iface);
1505 }
1506
1507 static ULONG WINAPI SAXLexicalHandler_Release(ISAXLexicalHandler *iface)
1508 {
1509 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1510 return IMXWriter_Release(&This->IMXWriter_iface);
1511 }
1512
1513 static HRESULT WINAPI SAXLexicalHandler_startDTD(ISAXLexicalHandler *iface,
1514 const WCHAR *name, int name_len, const WCHAR *publicId, int publicId_len,
1515 const WCHAR *systemId, int systemId_len)
1516 {
1517 static const WCHAR doctypeW[] = {'<','!','D','O','C','T','Y','P','E',' '};
1518 static const WCHAR openintW[] = {'[','\r','\n'};
1519
1520 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1521
1522 TRACE("(%p)->(%s %s %s)\n", This, debugstr_wn(name, name_len), debugstr_wn(publicId, publicId_len),
1523 debugstr_wn(systemId, systemId_len));
1524
1525 if (!name) return E_INVALIDARG;
1526
1527 write_output_buffer(This, doctypeW, ARRAY_SIZE(doctypeW));
1528
1529 if (*name)
1530 {
1531 write_output_buffer(This, name, name_len);
1532 write_output_buffer(This, spaceW, 1);
1533 }
1534
1535 if (publicId)
1536 {
1537 write_output_buffer(This, publicW, ARRAY_SIZE(publicW));
1538 write_output_buffer_quoted(This, publicId, publicId_len);
1539
1540 if (!systemId) return E_INVALIDARG;
1541
1542 if (*publicId)
1543 write_output_buffer(This, spaceW, 1);
1544
1545 write_output_buffer_quoted(This, systemId, systemId_len);
1546
1547 if (*systemId)
1548 write_output_buffer(This, spaceW, 1);
1549 }
1550 else if (systemId)
1551 {
1552 write_output_buffer(This, systemW, ARRAY_SIZE(systemW));
1553 write_output_buffer_quoted(This, systemId, systemId_len);
1554 if (*systemId)
1555 write_output_buffer(This, spaceW, 1);
1556 }
1557
1558 write_output_buffer(This, openintW, ARRAY_SIZE(openintW));
1559
1560 return S_OK;
1561 }
1562
1563 static HRESULT WINAPI SAXLexicalHandler_endDTD(ISAXLexicalHandler *iface)
1564 {
1565 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1566 static const WCHAR closedtdW[] = {']','>','\r','\n'};
1567
1568 TRACE("(%p)\n", This);
1569
1570 write_output_buffer(This, closedtdW, ARRAY_SIZE(closedtdW));
1571
1572 return S_OK;
1573 }
1574
1575 static HRESULT WINAPI SAXLexicalHandler_startEntity(ISAXLexicalHandler *iface, const WCHAR *name, int len)
1576 {
1577 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1578 FIXME("(%p)->(%s): stub\n", This, debugstr_wn(name, len));
1579 return E_NOTIMPL;
1580 }
1581
1582 static HRESULT WINAPI SAXLexicalHandler_endEntity(ISAXLexicalHandler *iface, const WCHAR *name, int len)
1583 {
1584 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1585 FIXME("(%p)->(%s): stub\n", This, debugstr_wn(name, len));
1586 return E_NOTIMPL;
1587 }
1588
1589 static HRESULT WINAPI SAXLexicalHandler_startCDATA(ISAXLexicalHandler *iface)
1590 {
1591 static const WCHAR scdataW[] = {'<','!','[','C','D','A','T','A','['};
1592 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1593
1594 TRACE("(%p)\n", This);
1595
1596 write_node_indent(This);
1597 write_output_buffer(This, scdataW, ARRAY_SIZE(scdataW));
1598 This->cdata = TRUE;
1599
1600 return S_OK;
1601 }
1602
1603 static HRESULT WINAPI SAXLexicalHandler_endCDATA(ISAXLexicalHandler *iface)
1604 {
1605 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1606 static const WCHAR ecdataW[] = {']',']','>'};
1607
1608 TRACE("(%p)\n", This);
1609
1610 write_output_buffer(This, ecdataW, ARRAY_SIZE(ecdataW));
1611 This->cdata = FALSE;
1612
1613 return S_OK;
1614 }
1615
1616 static HRESULT WINAPI SAXLexicalHandler_comment(ISAXLexicalHandler *iface, const WCHAR *chars, int nchars)
1617 {
1618 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1619 static const WCHAR copenW[] = {'<','!','-','-'};
1620 static const WCHAR ccloseW[] = {'-','-','>','\r','\n'};
1621
1622 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
1623
1624 if (!chars) return E_INVALIDARG;
1625
1626 close_element_starttag(This);
1627 write_node_indent(This);
1628
1629 write_output_buffer(This, copenW, ARRAY_SIZE(copenW));
1630 if (nchars)
1631 write_output_buffer(This, chars, nchars);
1632 write_output_buffer(This, ccloseW, ARRAY_SIZE(ccloseW));
1633
1634 return S_OK;
1635 }
1636
1637 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1638 {
1639 SAXLexicalHandler_QueryInterface,
1640 SAXLexicalHandler_AddRef,
1641 SAXLexicalHandler_Release,
1642 SAXLexicalHandler_startDTD,
1643 SAXLexicalHandler_endDTD,
1644 SAXLexicalHandler_startEntity,
1645 SAXLexicalHandler_endEntity,
1646 SAXLexicalHandler_startCDATA,
1647 SAXLexicalHandler_endCDATA,
1648 SAXLexicalHandler_comment
1649 };
1650
1651 /*** ISAXDeclHandler ***/
1652 static HRESULT WINAPI SAXDeclHandler_QueryInterface(ISAXDeclHandler *iface,
1653 REFIID riid, void **obj)
1654 {
1655 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1656 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1657 }
1658
1659 static ULONG WINAPI SAXDeclHandler_AddRef(ISAXDeclHandler *iface)
1660 {
1661 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1662 return IMXWriter_AddRef(&This->IMXWriter_iface);
1663 }
1664
1665 static ULONG WINAPI SAXDeclHandler_Release(ISAXDeclHandler *iface)
1666 {
1667 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1668 return IMXWriter_Release(&This->IMXWriter_iface);
1669 }
1670
1671 static HRESULT WINAPI SAXDeclHandler_elementDecl(ISAXDeclHandler *iface,
1672 const WCHAR *name, int n_name, const WCHAR *model, int n_model)
1673 {
1674 static const WCHAR elementW[] = {'<','!','E','L','E','M','E','N','T',' '};
1675 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1676
1677 TRACE("(%p)->(%s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1678 debugstr_wn(model, n_model), n_model);
1679
1680 if (!name || !model) return E_INVALIDARG;
1681
1682 write_output_buffer(This, elementW, ARRAY_SIZE(elementW));
1683 if (n_name) {
1684 write_output_buffer(This, name, n_name);
1685 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1686 }
1687 if (n_model)
1688 write_output_buffer(This, model, n_model);
1689 write_output_buffer(This, closetagW, ARRAY_SIZE(closetagW));
1690
1691 return S_OK;
1692 }
1693
1694 static HRESULT WINAPI SAXDeclHandler_attributeDecl(ISAXDeclHandler *iface,
1695 const WCHAR *element, int n_element, const WCHAR *attr, int n_attr,
1696 const WCHAR *type, int n_type, const WCHAR *Default, int n_default,
1697 const WCHAR *value, int n_value)
1698 {
1699 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1700 static const WCHAR attlistW[] = {'<','!','A','T','T','L','I','S','T',' '};
1701 static const WCHAR closetagW[] = {'>','\r','\n'};
1702
1703 TRACE("(%p)->(%s:%d %s:%d %s:%d %s:%d %s:%d)\n", This, debugstr_wn(element, n_element), n_element,
1704 debugstr_wn(attr, n_attr), n_attr, debugstr_wn(type, n_type), n_type, debugstr_wn(Default, n_default), n_default,
1705 debugstr_wn(value, n_value), n_value);
1706
1707 write_output_buffer(This, attlistW, ARRAY_SIZE(attlistW));
1708 if (n_element) {
1709 write_output_buffer(This, element, n_element);
1710 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1711 }
1712
1713 if (n_attr) {
1714 write_output_buffer(This, attr, n_attr);
1715 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1716 }
1717
1718 if (n_type) {
1719 write_output_buffer(This, type, n_type);
1720 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1721 }
1722
1723 if (n_default) {
1724 write_output_buffer(This, Default, n_default);
1725 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1726 }
1727
1728 if (n_value)
1729 write_output_buffer_quoted(This, value, n_value);
1730
1731 write_output_buffer(This, closetagW, ARRAY_SIZE(closetagW));
1732
1733 return S_OK;
1734 }
1735
1736 static HRESULT WINAPI SAXDeclHandler_internalEntityDecl(ISAXDeclHandler *iface,
1737 const WCHAR *name, int n_name, const WCHAR *value, int n_value)
1738 {
1739 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1740
1741 TRACE("(%p)->(%s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1742 debugstr_wn(value, n_value), n_value);
1743
1744 if (!name || !value) return E_INVALIDARG;
1745
1746 write_output_buffer(This, entityW, ARRAY_SIZE(entityW));
1747 if (n_name) {
1748 write_output_buffer(This, name, n_name);
1749 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1750 }
1751
1752 if (n_value)
1753 write_output_buffer_quoted(This, value, n_value);
1754
1755 write_output_buffer(This, closetagW, ARRAY_SIZE(closetagW));
1756
1757 return S_OK;
1758 }
1759
1760 static HRESULT WINAPI SAXDeclHandler_externalEntityDecl(ISAXDeclHandler *iface,
1761 const WCHAR *name, int n_name, const WCHAR *publicId, int n_publicId,
1762 const WCHAR *systemId, int n_systemId)
1763 {
1764 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1765
1766 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1767 debugstr_wn(publicId, n_publicId), n_publicId, debugstr_wn(systemId, n_systemId), n_systemId);
1768
1769 if (!name || !systemId) return E_INVALIDARG;
1770
1771 write_output_buffer(This, entityW, ARRAY_SIZE(entityW));
1772 if (n_name) {
1773 write_output_buffer(This, name, n_name);
1774 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1775 }
1776
1777 if (publicId)
1778 {
1779 write_output_buffer(This, publicW, ARRAY_SIZE(publicW));
1780 write_output_buffer_quoted(This, publicId, n_publicId);
1781 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
1782 write_output_buffer_quoted(This, systemId, n_systemId);
1783 }
1784 else
1785 {
1786 write_output_buffer(This, systemW, ARRAY_SIZE(systemW));
1787 write_output_buffer_quoted(This, systemId, n_systemId);
1788 }
1789
1790 write_output_buffer(This, closetagW, ARRAY_SIZE(closetagW));
1791
1792 return S_OK;
1793 }
1794
1795 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = {
1796 SAXDeclHandler_QueryInterface,
1797 SAXDeclHandler_AddRef,
1798 SAXDeclHandler_Release,
1799 SAXDeclHandler_elementDecl,
1800 SAXDeclHandler_attributeDecl,
1801 SAXDeclHandler_internalEntityDecl,
1802 SAXDeclHandler_externalEntityDecl
1803 };
1804
1805 /*** IVBSAXDeclHandler ***/
1806 static HRESULT WINAPI VBSAXDeclHandler_QueryInterface(IVBSAXDeclHandler *iface,
1807 REFIID riid, void **obj)
1808 {
1809 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1810 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1811 }
1812
1813 static ULONG WINAPI VBSAXDeclHandler_AddRef(IVBSAXDeclHandler *iface)
1814 {
1815 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1816 return IMXWriter_AddRef(&This->IMXWriter_iface);
1817 }
1818
1819 static ULONG WINAPI VBSAXDeclHandler_Release(IVBSAXDeclHandler *iface)
1820 {
1821 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1822 return IMXWriter_Release(&This->IMXWriter_iface);
1823 }
1824
1825 static HRESULT WINAPI VBSAXDeclHandler_GetTypeInfoCount(IVBSAXDeclHandler *iface, UINT* pctinfo)
1826 {
1827 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1828 return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
1829 }
1830
1831 static HRESULT WINAPI VBSAXDeclHandler_GetTypeInfo(IVBSAXDeclHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1832 {
1833 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1834 return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
1835 }
1836
1837 static HRESULT WINAPI VBSAXDeclHandler_GetIDsOfNames(IVBSAXDeclHandler *iface, REFIID riid, LPOLESTR* rgszNames,
1838 UINT cNames, LCID lcid, DISPID* rgDispId )
1839 {
1840 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1841 return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
1842 }
1843
1844 static HRESULT WINAPI VBSAXDeclHandler_Invoke(IVBSAXDeclHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1845 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
1846 {
1847 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1848 return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
1849 pExcepInfo, puArgErr);
1850 }
1851
1852 static HRESULT WINAPI VBSAXDeclHandler_elementDecl(IVBSAXDeclHandler *iface, BSTR *name, BSTR *model)
1853 {
1854 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1855
1856 TRACE("(%p)->(%p %p)\n", This, name, model);
1857
1858 if (!name || !model)
1859 return E_POINTER;
1860
1861 return ISAXDeclHandler_elementDecl(&This->ISAXDeclHandler_iface, *name, -1, *model, -1);
1862 }
1863
1864 static HRESULT WINAPI VBSAXDeclHandler_attributeDecl(IVBSAXDeclHandler *iface,
1865 BSTR *element, BSTR *attr, BSTR *type, BSTR *default_value, BSTR *value)
1866 {
1867 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1868
1869 TRACE("(%p)->(%p %p %p %p %p)\n", This, element, attr, type, default_value, value);
1870
1871 if (!element || !attr || !type || !default_value || !value)
1872 return E_POINTER;
1873
1874 return ISAXDeclHandler_attributeDecl(&This->ISAXDeclHandler_iface, *element, -1, *attr, -1, *type, -1,
1875 *default_value, -1, *value, -1);
1876 }
1877
1878 static HRESULT WINAPI VBSAXDeclHandler_internalEntityDecl(IVBSAXDeclHandler *iface, BSTR *name, BSTR *value)
1879 {
1880 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1881
1882 TRACE("(%p)->(%p %p)\n", This, name, value);
1883
1884 if (!name || !value)
1885 return E_POINTER;
1886
1887 return ISAXDeclHandler_internalEntityDecl(&This->ISAXDeclHandler_iface, *name, -1, *value, -1);
1888 }
1889
1890 static HRESULT WINAPI VBSAXDeclHandler_externalEntityDecl(IVBSAXDeclHandler *iface,
1891 BSTR *name, BSTR *publicid, BSTR *systemid)
1892 {
1893 mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
1894
1895 TRACE("(%p)->(%p %p %p)\n", This, name, publicid, systemid);
1896
1897 if (!name || !publicid || !systemid)
1898 return E_POINTER;
1899
1900 return ISAXDeclHandler_externalEntityDecl(&This->ISAXDeclHandler_iface, *name, -1, *publicid, -1, *systemid, -1);
1901 }
1902
1903 static const IVBSAXDeclHandlerVtbl VBSAXDeclHandlerVtbl = {
1904 VBSAXDeclHandler_QueryInterface,
1905 VBSAXDeclHandler_AddRef,
1906 VBSAXDeclHandler_Release,
1907 VBSAXDeclHandler_GetTypeInfoCount,
1908 VBSAXDeclHandler_GetTypeInfo,
1909 VBSAXDeclHandler_GetIDsOfNames,
1910 VBSAXDeclHandler_Invoke,
1911 VBSAXDeclHandler_elementDecl,
1912 VBSAXDeclHandler_attributeDecl,
1913 VBSAXDeclHandler_internalEntityDecl,
1914 VBSAXDeclHandler_externalEntityDecl
1915 };
1916
1917 /*** IVBSAXLexicalHandler ***/
1918 static HRESULT WINAPI VBSAXLexicalHandler_QueryInterface(IVBSAXLexicalHandler *iface,
1919 REFIID riid, void **obj)
1920 {
1921 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1922 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1923 }
1924
1925 static ULONG WINAPI VBSAXLexicalHandler_AddRef(IVBSAXLexicalHandler *iface)
1926 {
1927 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1928 return IMXWriter_AddRef(&This->IMXWriter_iface);
1929 }
1930
1931 static ULONG WINAPI VBSAXLexicalHandler_Release(IVBSAXLexicalHandler *iface)
1932 {
1933 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1934 return IMXWriter_Release(&This->IMXWriter_iface);
1935 }
1936
1937 static HRESULT WINAPI VBSAXLexicalHandler_GetTypeInfoCount(IVBSAXLexicalHandler *iface, UINT* pctinfo)
1938 {
1939 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1940 return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
1941 }
1942
1943 static HRESULT WINAPI VBSAXLexicalHandler_GetTypeInfo(IVBSAXLexicalHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1944 {
1945 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1946 return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
1947 }
1948
1949 static HRESULT WINAPI VBSAXLexicalHandler_GetIDsOfNames(IVBSAXLexicalHandler *iface, REFIID riid, LPOLESTR* rgszNames,
1950 UINT cNames, LCID lcid, DISPID* rgDispId )
1951 {
1952 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1953 return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
1954 }
1955
1956 static HRESULT WINAPI VBSAXLexicalHandler_Invoke(IVBSAXLexicalHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1957 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
1958 {
1959 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1960 return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
1961 pExcepInfo, puArgErr);
1962 }
1963
1964 static HRESULT WINAPI VBSAXLexicalHandler_startDTD(IVBSAXLexicalHandler *iface, BSTR *name, BSTR *publicId, BSTR *systemId)
1965 {
1966 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1967
1968 TRACE("(%p)->(%p %p %p)\n", This, name, publicId, systemId);
1969
1970 if (!name || !publicId || !systemId)
1971 return E_POINTER;
1972
1973 return ISAXLexicalHandler_startDTD(&This->ISAXLexicalHandler_iface, *name, -1, *publicId, -1, *systemId, -1);
1974 }
1975
1976 static HRESULT WINAPI VBSAXLexicalHandler_endDTD(IVBSAXLexicalHandler *iface)
1977 {
1978 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1979 return ISAXLexicalHandler_endDTD(&This->ISAXLexicalHandler_iface);
1980 }
1981
1982 static HRESULT WINAPI VBSAXLexicalHandler_startEntity(IVBSAXLexicalHandler *iface, BSTR *name)
1983 {
1984 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1985
1986 TRACE("(%p)->(%p)\n", This, name);
1987
1988 if (!name)
1989 return E_POINTER;
1990
1991 return ISAXLexicalHandler_startEntity(&This->ISAXLexicalHandler_iface, *name, -1);
1992 }
1993
1994 static HRESULT WINAPI VBSAXLexicalHandler_endEntity(IVBSAXLexicalHandler *iface, BSTR *name)
1995 {
1996 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
1997
1998 TRACE("(%p)->(%p)\n", This, name);
1999
2000 if (!name)
2001 return E_POINTER;
2002
2003 return ISAXLexicalHandler_endEntity(&This->ISAXLexicalHandler_iface, *name, -1);
2004 }
2005
2006 static HRESULT WINAPI VBSAXLexicalHandler_startCDATA(IVBSAXLexicalHandler *iface)
2007 {
2008 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
2009 return ISAXLexicalHandler_startCDATA(&This->ISAXLexicalHandler_iface);
2010 }
2011
2012 static HRESULT WINAPI VBSAXLexicalHandler_endCDATA(IVBSAXLexicalHandler *iface)
2013 {
2014 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
2015 return ISAXLexicalHandler_endCDATA(&This->ISAXLexicalHandler_iface);
2016 }
2017
2018 static HRESULT WINAPI VBSAXLexicalHandler_comment(IVBSAXLexicalHandler *iface, BSTR *chars)
2019 {
2020 mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
2021
2022 TRACE("(%p)->(%p)\n", This, chars);
2023
2024 if (!chars)
2025 return E_POINTER;
2026
2027 return ISAXLexicalHandler_comment(&This->ISAXLexicalHandler_iface, *chars, -1);
2028 }
2029
2030 static const IVBSAXLexicalHandlerVtbl VBSAXLexicalHandlerVtbl = {
2031 VBSAXLexicalHandler_QueryInterface,
2032 VBSAXLexicalHandler_AddRef,
2033 VBSAXLexicalHandler_Release,
2034 VBSAXLexicalHandler_GetTypeInfoCount,
2035 VBSAXLexicalHandler_GetTypeInfo,
2036 VBSAXLexicalHandler_GetIDsOfNames,
2037 VBSAXLexicalHandler_Invoke,
2038 VBSAXLexicalHandler_startDTD,
2039 VBSAXLexicalHandler_endDTD,
2040 VBSAXLexicalHandler_startEntity,
2041 VBSAXLexicalHandler_endEntity,
2042 VBSAXLexicalHandler_startCDATA,
2043 VBSAXLexicalHandler_endCDATA,
2044 VBSAXLexicalHandler_comment
2045 };
2046
2047 /*** IVBSAXContentHandler ***/
2048 static HRESULT WINAPI VBSAXContentHandler_QueryInterface(IVBSAXContentHandler *iface, REFIID riid, void **obj)
2049 {
2050 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2051 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
2052 }
2053
2054 static ULONG WINAPI VBSAXContentHandler_AddRef(IVBSAXContentHandler *iface)
2055 {
2056 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2057 return IMXWriter_AddRef(&This->IMXWriter_iface);
2058 }
2059
2060 static ULONG WINAPI VBSAXContentHandler_Release(IVBSAXContentHandler *iface)
2061 {
2062 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2063 return IMXWriter_Release(&This->IMXWriter_iface);
2064 }
2065
2066 static HRESULT WINAPI VBSAXContentHandler_GetTypeInfoCount(IVBSAXContentHandler *iface, UINT* pctinfo)
2067 {
2068 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2069 return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
2070 }
2071
2072 static HRESULT WINAPI VBSAXContentHandler_GetTypeInfo(IVBSAXContentHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2073 {
2074 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2075 return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
2076 }
2077
2078 static HRESULT WINAPI VBSAXContentHandler_GetIDsOfNames(IVBSAXContentHandler *iface, REFIID riid, LPOLESTR* rgszNames,
2079 UINT cNames, LCID lcid, DISPID* rgDispId )
2080 {
2081 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2082 return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
2083 }
2084
2085 static HRESULT WINAPI VBSAXContentHandler_Invoke(IVBSAXContentHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
2086 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
2087 {
2088 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2089 return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
2090 pExcepInfo, puArgErr);
2091 }
2092
2093 static HRESULT WINAPI VBSAXContentHandler_putref_documentLocator(IVBSAXContentHandler *iface, IVBSAXLocator *locator)
2094 {
2095 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2096 TRACE("(%p)->(%p)\n", This, locator);
2097 return S_OK;
2098 }
2099
2100 static HRESULT WINAPI VBSAXContentHandler_startDocument(IVBSAXContentHandler *iface)
2101 {
2102 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2103 return ISAXContentHandler_startDocument(&This->ISAXContentHandler_iface);
2104 }
2105
2106 static HRESULT WINAPI VBSAXContentHandler_endDocument(IVBSAXContentHandler *iface)
2107 {
2108 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2109 return ISAXContentHandler_endDocument(&This->ISAXContentHandler_iface);
2110 }
2111
2112 static HRESULT WINAPI VBSAXContentHandler_startPrefixMapping(IVBSAXContentHandler *iface, BSTR *prefix, BSTR *uri)
2113 {
2114 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2115
2116 TRACE("(%p)->(%p %p)\n", This, prefix, uri);
2117
2118 if (!prefix || !uri)
2119 return E_POINTER;
2120
2121 return ISAXContentHandler_startPrefixMapping(&This->ISAXContentHandler_iface, *prefix, -1, *uri, -1);
2122 }
2123
2124 static HRESULT WINAPI VBSAXContentHandler_endPrefixMapping(IVBSAXContentHandler *iface, BSTR *prefix)
2125 {
2126 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2127
2128 TRACE("(%p)->(%p)\n", This, prefix);
2129
2130 if (!prefix)
2131 return E_POINTER;
2132
2133 return ISAXContentHandler_endPrefixMapping(&This->ISAXContentHandler_iface, *prefix, -1);
2134 }
2135
2136 static HRESULT WINAPI VBSAXContentHandler_startElement(IVBSAXContentHandler *iface,
2137 BSTR *namespaceURI, BSTR *localName, BSTR *QName, IVBSAXAttributes *attrs)
2138 {
2139 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2140
2141 TRACE("(%p)->(%p %p %p %p)\n", This, namespaceURI, localName, QName, attrs);
2142
2143 if (!namespaceURI || !localName || !QName)
2144 return E_POINTER;
2145
2146 TRACE("(%s %s %s)\n", debugstr_w(*namespaceURI), debugstr_w(*localName), debugstr_w(*QName));
2147
2148 mxwriter_write_starttag(This, *QName, SysStringLen(*QName));
2149
2150 if (attrs)
2151 {
2152 int length, i, escape;
2153 HRESULT hr;
2154
2155 hr = IVBSAXAttributes_get_length(attrs, &length);
2156 if (FAILED(hr)) return hr;
2157
2158 escape = This->props[MXWriter_DisableEscaping] == VARIANT_FALSE ||
2159 (This->class_version == MSXML4 || This->class_version == MSXML6);
2160
2161 for (i = 0; i < length; i++)
2162 {
2163 BSTR qname, value;
2164
2165 hr = IVBSAXAttributes_getQName(attrs, i, &qname);
2166 if (FAILED(hr)) return hr;
2167
2168 hr = IVBSAXAttributes_getValue(attrs, i, &value);
2169 if (FAILED(hr))
2170 {
2171 SysFreeString(qname);
2172 return hr;
2173 }
2174
2175 mxwriter_write_attribute(This, qname, SysStringLen(qname), value, SysStringLen(value), escape);
2176 SysFreeString(qname);
2177 SysFreeString(value);
2178 }
2179 }
2180
2181 return S_OK;
2182 }
2183
2184 static HRESULT WINAPI VBSAXContentHandler_endElement(IVBSAXContentHandler *iface, BSTR *namespaceURI,
2185 BSTR *localName, BSTR *QName)
2186 {
2187 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2188
2189 TRACE("(%p)->(%p %p %p)\n", This, namespaceURI, localName, QName);
2190
2191 if (!namespaceURI || !localName || !QName)
2192 return E_POINTER;
2193
2194 return ISAXContentHandler_endElement(&This->ISAXContentHandler_iface,
2195 *namespaceURI, SysStringLen(*namespaceURI),
2196 *localName, SysStringLen(*localName),
2197 *QName, SysStringLen(*QName));
2198 }
2199
2200 static HRESULT WINAPI VBSAXContentHandler_characters(IVBSAXContentHandler *iface, BSTR *chars)
2201 {
2202 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2203
2204 TRACE("(%p)->(%p)\n", This, chars);
2205
2206 if (!chars)
2207 return E_POINTER;
2208
2209 return ISAXContentHandler_characters(&This->ISAXContentHandler_iface, *chars, SysStringLen(*chars));
2210 }
2211
2212 static HRESULT WINAPI VBSAXContentHandler_ignorableWhitespace(IVBSAXContentHandler *iface, BSTR *chars)
2213 {
2214 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2215
2216 TRACE("(%p)->(%p)\n", This, chars);
2217
2218 if (!chars)
2219 return E_POINTER;
2220
2221 return ISAXContentHandler_ignorableWhitespace(&This->ISAXContentHandler_iface, *chars, -1);
2222 }
2223
2224 static HRESULT WINAPI VBSAXContentHandler_processingInstruction(IVBSAXContentHandler *iface,
2225 BSTR *target, BSTR *data)
2226 {
2227 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2228
2229 TRACE("(%p)->(%p %p)\n", This, target, data);
2230
2231 if (!target || !data)
2232 return E_POINTER;
2233
2234 return ISAXContentHandler_processingInstruction(&This->ISAXContentHandler_iface, *target, -1, *data, -1);
2235 }
2236
2237 static HRESULT WINAPI VBSAXContentHandler_skippedEntity(IVBSAXContentHandler *iface, BSTR *name)
2238 {
2239 mxwriter *This = impl_from_IVBSAXContentHandler( iface );
2240
2241 TRACE("(%p)->(%p)\n", This, name);
2242
2243 if (!name)
2244 return E_POINTER;
2245
2246 return ISAXContentHandler_skippedEntity(&This->ISAXContentHandler_iface, *name, -1);
2247 }
2248
2249 static const IVBSAXContentHandlerVtbl VBSAXContentHandlerVtbl = {
2250 VBSAXContentHandler_QueryInterface,
2251 VBSAXContentHandler_AddRef,
2252 VBSAXContentHandler_Release,
2253 VBSAXContentHandler_GetTypeInfoCount,
2254 VBSAXContentHandler_GetTypeInfo,
2255 VBSAXContentHandler_GetIDsOfNames,
2256 VBSAXContentHandler_Invoke,
2257 VBSAXContentHandler_putref_documentLocator,
2258 VBSAXContentHandler_startDocument,
2259 VBSAXContentHandler_endDocument,
2260 VBSAXContentHandler_startPrefixMapping,
2261 VBSAXContentHandler_endPrefixMapping,
2262 VBSAXContentHandler_startElement,
2263 VBSAXContentHandler_endElement,
2264 VBSAXContentHandler_characters,
2265 VBSAXContentHandler_ignorableWhitespace,
2266 VBSAXContentHandler_processingInstruction,
2267 VBSAXContentHandler_skippedEntity
2268 };
2269
2270 static HRESULT WINAPI SAXDTDHandler_QueryInterface(ISAXDTDHandler *iface, REFIID riid, void **obj)
2271 {
2272 mxwriter *This = impl_from_ISAXDTDHandler( iface );
2273 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
2274 }
2275
2276 static ULONG WINAPI SAXDTDHandler_AddRef(ISAXDTDHandler *iface)
2277 {
2278 mxwriter *This = impl_from_ISAXDTDHandler( iface );
2279 return IMXWriter_AddRef(&This->IMXWriter_iface);
2280 }
2281
2282 static ULONG WINAPI SAXDTDHandler_Release(ISAXDTDHandler *iface)
2283 {
2284 mxwriter *This = impl_from_ISAXDTDHandler( iface );
2285 return IMXWriter_Release(&This->IMXWriter_iface);
2286 }
2287
2288 static HRESULT WINAPI SAXDTDHandler_notationDecl(ISAXDTDHandler *iface,
2289 const WCHAR *name, INT n_name,
2290 const WCHAR *publicid, INT n_publicid,
2291 const WCHAR *systemid, INT n_systemid)
2292 {
2293 static const WCHAR notationW[] = {'<','!','N','O','T','A','T','I','O','N',' '};
2294 mxwriter *This = impl_from_ISAXDTDHandler( iface );
2295
2296 TRACE("(%p)->(%s:%d, %s:%d, %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
2297 debugstr_wn(publicid, n_publicid), n_publicid, debugstr_wn(systemid, n_systemid), n_systemid);
2298
2299 if (!name || !n_name)
2300 return E_INVALIDARG;
2301
2302 write_output_buffer(This, notationW, ARRAY_SIZE(notationW));
2303 write_output_buffer(This, name, n_name);
2304
2305 if (!publicid && !systemid)
2306 return E_INVALIDARG;
2307
2308 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
2309 if (publicid)
2310 {
2311 write_output_buffer(This, publicW, ARRAY_SIZE(publicW));
2312 write_output_buffer_quoted(This, publicid, n_publicid);
2313 if (systemid)
2314 {
2315 write_output_buffer(This, spaceW, ARRAY_SIZE(spaceW));
2316 write_output_buffer_quoted(This, systemid, n_systemid);
2317 }
2318 }
2319 else
2320 {
2321 write_output_buffer(This, systemW, ARRAY_SIZE(systemW));
2322 write_output_buffer_quoted(This, systemid, n_systemid);
2323 }
2324
2325 write_output_buffer(This, closetagW, ARRAY_SIZE(closetagW));
2326
2327 return S_OK;
2328 }
2329
2330 static HRESULT WINAPI SAXDTDHandler_unparsedEntityDecl(ISAXDTDHandler *iface,
2331 const WCHAR *name, INT nname,
2332 const WCHAR *publicid, INT npublicid,
2333 const WCHAR *systemid, INT nsystemid,
2334 const WCHAR *notation, INT nnotation)
2335 {
2336 mxwriter *This = impl_from_ISAXDTDHandler( iface );
2337 FIXME("(%p)->(%s:%d, %s:%d, %s:%d, %s:%d): stub\n", This, debugstr_wn(name, nname), nname,
2338 debugstr_wn(publicid, npublicid), npublicid, debugstr_wn(systemid, nsystemid), nsystemid,
2339 debugstr_wn(notation, nnotation), nnotation);
2340 return E_NOTIMPL;
2341 }
2342
2343 static const ISAXDTDHandlerVtbl SAXDTDHandlerVtbl = {
2344 SAXDTDHandler_QueryInterface,
2345 SAXDTDHandler_AddRef,
2346 SAXDTDHandler_Release,
2347 SAXDTDHandler_notationDecl,
2348 SAXDTDHandler_unparsedEntityDecl
2349 };
2350
2351 /*** IVBSAXDTDHandler ***/
2352 static HRESULT WINAPI VBSAXDTDHandler_QueryInterface(IVBSAXDTDHandler *iface, REFIID riid, void **obj)
2353 {
2354 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2355 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
2356 }
2357
2358 static ULONG WINAPI VBSAXDTDHandler_AddRef(IVBSAXDTDHandler *iface)
2359 {
2360 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2361 return IMXWriter_AddRef(&This->IMXWriter_iface);
2362 }
2363
2364 static ULONG WINAPI VBSAXDTDHandler_Release(IVBSAXDTDHandler *iface)
2365 {
2366 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2367 return IMXWriter_Release(&This->IMXWriter_iface);
2368 }
2369
2370 static HRESULT WINAPI VBSAXDTDHandler_GetTypeInfoCount(IVBSAXDTDHandler *iface, UINT* pctinfo)
2371 {
2372 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2373 return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
2374 }
2375
2376 static HRESULT WINAPI VBSAXDTDHandler_GetTypeInfo(IVBSAXDTDHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2377 {
2378 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2379 return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
2380 }
2381
2382 static HRESULT WINAPI VBSAXDTDHandler_GetIDsOfNames(IVBSAXDTDHandler *iface, REFIID riid, LPOLESTR* rgszNames,
2383 UINT cNames, LCID lcid, DISPID* rgDispId )
2384 {
2385 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2386 return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
2387 }
2388
2389 static HRESULT WINAPI VBSAXDTDHandler_Invoke(IVBSAXDTDHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
2390 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
2391 {
2392 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2393 return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
2394 pExcepInfo, puArgErr);
2395 }
2396
2397 static HRESULT WINAPI VBSAXDTDHandler_notationDecl(IVBSAXDTDHandler *iface, BSTR *name, BSTR *publicId, BSTR *systemId)
2398 {
2399 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2400
2401 TRACE("(%p)->(%p %p %p)\n", This, name, publicId, systemId);
2402
2403 if (!name || !publicId || !systemId)
2404 return E_POINTER;
2405
2406 return ISAXDTDHandler_notationDecl(&This->ISAXDTDHandler_iface, *name, -1, *publicId, -1, *systemId, -1);
2407 }
2408
2409 static HRESULT WINAPI VBSAXDTDHandler_unparsedEntityDecl(IVBSAXDTDHandler *iface, BSTR *name, BSTR *publicId,
2410 BSTR *systemId, BSTR *notation)
2411 {
2412 mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
2413
2414 TRACE("(%p)->(%p %p %p %p)\n", This, name, publicId, systemId, notation);
2415
2416 if (!name || !publicId || !systemId || !notation)
2417 return E_POINTER;
2418
2419 return ISAXDTDHandler_unparsedEntityDecl(&This->ISAXDTDHandler_iface, *name, -1, *publicId, -1,
2420 *systemId, -1, *notation, -1);
2421 }
2422
2423 static const IVBSAXDTDHandlerVtbl VBSAXDTDHandlerVtbl = {
2424 VBSAXDTDHandler_QueryInterface,
2425 VBSAXDTDHandler_AddRef,
2426 VBSAXDTDHandler_Release,
2427 VBSAXDTDHandler_GetTypeInfoCount,
2428 VBSAXDTDHandler_GetTypeInfo,
2429 VBSAXDTDHandler_GetIDsOfNames,
2430 VBSAXDTDHandler_Invoke,
2431 VBSAXDTDHandler_notationDecl,
2432 VBSAXDTDHandler_unparsedEntityDecl
2433 };
2434
2435 /* ISAXErrorHandler */
2436 static HRESULT WINAPI SAXErrorHandler_QueryInterface(ISAXErrorHandler *iface, REFIID riid, void **obj)
2437 {
2438 mxwriter *This = impl_from_ISAXErrorHandler( iface );
2439 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
2440 }
2441
2442 static ULONG WINAPI SAXErrorHandler_AddRef(ISAXErrorHandler *iface)
2443 {
2444 mxwriter *This = impl_from_ISAXErrorHandler( iface );
2445 return IMXWriter_AddRef(&This->IMXWriter_iface);
2446 }
2447
2448 static ULONG WINAPI SAXErrorHandler_Release(ISAXErrorHandler *iface)
2449 {
2450 mxwriter *This = impl_from_ISAXErrorHandler( iface );
2451 return IMXWriter_Release(&This->IMXWriter_iface);
2452 }
2453
2454 static HRESULT WINAPI SAXErrorHandler_error(ISAXErrorHandler *iface,
2455 ISAXLocator *locator, const WCHAR *message, HRESULT hr)
2456 {
2457 mxwriter *This = impl_from_ISAXErrorHandler( iface );
2458
2459 FIXME("(%p)->(%p %s 0x%08x)\n", This, locator, debugstr_w(message), hr);
2460
2461 return E_NOTIMPL;
2462 }
2463
2464 static HRESULT WINAPI SAXErrorHandler_fatalError(ISAXErrorHandler *iface,
2465 ISAXLocator *locator, const WCHAR *message, HRESULT hr)
2466 {
2467 mxwriter *This = impl_from_ISAXErrorHandler( iface );
2468
2469 FIXME("(%p)->(%p %s 0x%08x)\n", This, locator, debugstr_w(message), hr);
2470
2471 return E_NOTIMPL;
2472 }
2473
2474 static HRESULT WINAPI SAXErrorHandler_ignorableWarning(ISAXErrorHandler *iface,
2475 ISAXLocator *locator, const WCHAR *message, HRESULT hr)
2476 {
2477 mxwriter *This = impl_from_ISAXErrorHandler( iface );
2478
2479 FIXME("(%p)->(%p %s 0x%08x)\n", This, locator, debugstr_w(message), hr);
2480
2481 return E_NOTIMPL;
2482 }
2483
2484 static const ISAXErrorHandlerVtbl SAXErrorHandlerVtbl = {
2485 SAXErrorHandler_QueryInterface,
2486 SAXErrorHandler_AddRef,
2487 SAXErrorHandler_Release,
2488 SAXErrorHandler_error,
2489 SAXErrorHandler_fatalError,
2490 SAXErrorHandler_ignorableWarning
2491 };
2492
2493 /*** IVBSAXErrorHandler ***/
2494 static HRESULT WINAPI VBSAXErrorHandler_QueryInterface(IVBSAXErrorHandler *iface, REFIID riid, void **obj)
2495 {
2496 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2497 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
2498 }
2499
2500 static ULONG WINAPI VBSAXErrorHandler_AddRef(IVBSAXErrorHandler *iface)
2501 {
2502 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2503 return IMXWriter_AddRef(&This->IMXWriter_iface);
2504 }
2505
2506 static ULONG WINAPI VBSAXErrorHandler_Release(IVBSAXErrorHandler *iface)
2507 {
2508 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2509 return IMXWriter_Release(&This->IMXWriter_iface);
2510 }
2511
2512 static HRESULT WINAPI VBSAXErrorHandler_GetTypeInfoCount(IVBSAXErrorHandler *iface, UINT* pctinfo)
2513 {
2514 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2515 return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
2516 }
2517
2518 static HRESULT WINAPI VBSAXErrorHandler_GetTypeInfo(IVBSAXErrorHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2519 {
2520 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2521 return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
2522 }
2523
2524 static HRESULT WINAPI VBSAXErrorHandler_GetIDsOfNames(IVBSAXErrorHandler *iface, REFIID riid, LPOLESTR* rgszNames,
2525 UINT cNames, LCID lcid, DISPID* rgDispId )
2526 {
2527 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2528 return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
2529 }
2530
2531 static HRESULT WINAPI VBSAXErrorHandler_Invoke(IVBSAXErrorHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
2532 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
2533 {
2534 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2535 return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
2536 pExcepInfo, puArgErr);
2537 }
2538
2539 static HRESULT WINAPI VBSAXErrorHandler_error(IVBSAXErrorHandler *iface, IVBSAXLocator *locator, BSTR *message, LONG code)
2540 {
2541 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2542 FIXME("(%p)->(%p %p %x): stub\n", This, locator, message, code);
2543 return E_NOTIMPL;
2544 }
2545
2546 static HRESULT WINAPI VBSAXErrorHandler_fatalError(IVBSAXErrorHandler *iface, IVBSAXLocator *locator, BSTR *message, LONG code)
2547 {
2548 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2549 FIXME("(%p)->(%p %p %x): stub\n", This, locator, message, code);
2550 return E_NOTIMPL;
2551 }
2552
2553 static HRESULT WINAPI VBSAXErrorHandler_ignorableWarning(IVBSAXErrorHandler *iface, IVBSAXLocator *locator, BSTR *message, LONG code)
2554 {
2555 mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
2556 FIXME("(%p)->(%p %p %x): stub\n", This, locator, message, code);
2557 return E_NOTIMPL;
2558 }
2559
2560 static const IVBSAXErrorHandlerVtbl VBSAXErrorHandlerVtbl = {
2561 VBSAXErrorHandler_QueryInterface,
2562 VBSAXErrorHandler_AddRef,
2563 VBSAXErrorHandler_Release,
2564 VBSAXErrorHandler_GetTypeInfoCount,
2565 VBSAXErrorHandler_GetTypeInfo,
2566 VBSAXErrorHandler_GetIDsOfNames,
2567 VBSAXErrorHandler_Invoke,
2568 VBSAXErrorHandler_error,
2569 VBSAXErrorHandler_fatalError,
2570 VBSAXErrorHandler_ignorableWarning
2571 };
2572
2573 static const tid_t mxwriter_iface_tids[] = {
2574 IMXWriter_tid,
2575 0
2576 };
2577
2578 static dispex_static_data_t mxwriter_dispex = {
2579 NULL,
2580 IMXWriter_tid,
2581 NULL,
2582 mxwriter_iface_tids
2583 };
2584
2585 HRESULT MXWriter_create(MSXML_VERSION version, void **ppObj)
2586 {
2587 static const WCHAR version10W[] = {'1','.','0',0};
2588 mxwriter *This;
2589 HRESULT hr;
2590
2591 TRACE("(%p)\n", ppObj);
2592
2593 This = heap_alloc( sizeof (*This) );
2594 if(!This)
2595 return E_OUTOFMEMORY;
2596
2597 This->IMXWriter_iface.lpVtbl = &MXWriterVtbl;
2598 This->ISAXContentHandler_iface.lpVtbl = &SAXContentHandlerVtbl;
2599 This->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
2600 This->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
2601 This->ISAXDTDHandler_iface.lpVtbl = &SAXDTDHandlerVtbl;
2602 This->ISAXErrorHandler_iface.lpVtbl = &SAXErrorHandlerVtbl;
2603 This->IVBSAXDeclHandler_iface.lpVtbl = &VBSAXDeclHandlerVtbl;
2604 This->IVBSAXLexicalHandler_iface.lpVtbl = &VBSAXLexicalHandlerVtbl;
2605 This->IVBSAXContentHandler_iface.lpVtbl = &VBSAXContentHandlerVtbl;
2606 This->IVBSAXDTDHandler_iface.lpVtbl = &VBSAXDTDHandlerVtbl;
2607 This->IVBSAXErrorHandler_iface.lpVtbl = &VBSAXErrorHandlerVtbl;
2608 This->ref = 1;
2609 This->class_version = version;
2610
2611 This->props[MXWriter_BOM] = VARIANT_TRUE;
2612 This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
2613 This->props[MXWriter_Indent] = VARIANT_FALSE;
2614 This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
2615 This->props[MXWriter_Standalone] = VARIANT_FALSE;
2616 This->prop_changed = FALSE;
2617 This->encoding = SysAllocString(utf16W);
2618 This->version = SysAllocString(version10W);
2619 This->xml_enc = XmlEncoding_UTF16;
2620
2621 This->element = NULL;
2622 This->cdata = FALSE;
2623 This->indent = 0;
2624 This->text = FALSE;
2625 This->newline = FALSE;
2626
2627 This->dest = NULL;
2628
2629 hr = init_output_buffer(This->xml_enc, &This->buffer);
2630 if (hr != S_OK) {
2631 SysFreeString(This->encoding);
2632 SysFreeString(This->version);
2633 heap_free(This);
2634 return hr;
2635 }
2636
2637 init_dispex(&This->dispex, (IUnknown*)&This->IMXWriter_iface, &mxwriter_dispex);
2638
2639 *ppObj = &This->IMXWriter_iface;
2640
2641 TRACE("returning iface %p\n", *ppObj);
2642
2643 return S_OK;
2644 }
2645
2646 static HRESULT WINAPI MXAttributes_QueryInterface(IMXAttributes *iface, REFIID riid, void **ppObj)
2647 {
2648 mxattributes *This = impl_from_IMXAttributes( iface );
2649
2650 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppObj);
2651
2652 *ppObj = NULL;
2653
2654 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
2655 IsEqualGUID( riid, &IID_IDispatch ) ||
2656 IsEqualGUID( riid, &IID_IMXAttributes ))
2657 {
2658 *ppObj = iface;
2659 }
2660 else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
2661 {
2662 *ppObj = &This->ISAXAttributes_iface;
2663 }
2664 else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
2665 {
2666 *ppObj = &This->IVBSAXAttributes_iface;
2667 }
2668 else if (dispex_query_interface(&This->dispex, riid, ppObj))
2669 {
2670 return *ppObj ? S_OK : E_NOINTERFACE;
2671 }
2672 else
2673 {
2674 FIXME("interface %s not implemented\n", debugstr_guid(riid));
2675 return E_NOINTERFACE;
2676 }
2677
2678 IMXAttributes_AddRef( iface );
2679
2680 return S_OK;
2681 }
2682
2683 static ULONG WINAPI MXAttributes_AddRef(IMXAttributes *iface)
2684 {
2685 mxattributes *This = impl_from_IMXAttributes( iface );
2686 ULONG ref = InterlockedIncrement( &This->ref );
2687 TRACE("(%p)->(%d)\n", This, ref );
2688 return ref;
2689 }
2690
2691 static ULONG WINAPI MXAttributes_Release(IMXAttributes *iface)
2692 {
2693 mxattributes *This = impl_from_IMXAttributes( iface );
2694 LONG ref = InterlockedDecrement( &This->ref );
2695
2696 TRACE("(%p)->(%d)\n", This, ref);
2697
2698 if (ref == 0)
2699 {
2700 int i;
2701
2702 for (i = 0; i < This->length; i++)
2703 {
2704 SysFreeString(This->attr[i].qname);
2705 SysFreeString(This->attr[i].local);
2706 SysFreeString(This->attr[i].uri);
2707 SysFreeString(This->attr[i].type);
2708 SysFreeString(This->attr[i].value);
2709 }
2710
2711 heap_free(This->attr);
2712 heap_free(This);
2713 }
2714
2715 return ref;
2716 }
2717
2718 static HRESULT WINAPI MXAttributes_GetTypeInfoCount(IMXAttributes *iface, UINT* pctinfo)
2719 {
2720 mxattributes *This = impl_from_IMXAttributes( iface );
2721 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2722 }
2723
2724 static HRESULT WINAPI MXAttributes_GetTypeInfo(IMXAttributes *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2725 {
2726 mxattributes *This = impl_from_IMXAttributes( iface );
2727 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
2728 }
2729
2730 static HRESULT WINAPI MXAttributes_GetIDsOfNames(
2731 IMXAttributes *iface,
2732 REFIID riid,
2733 LPOLESTR* rgszNames,
2734 UINT cNames,
2735 LCID lcid,
2736 DISPID* rgDispId)
2737 {
2738 mxattributes *This = impl_from_IMXAttributes( iface );
2739 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
2740 riid, rgszNames, cNames, lcid, rgDispId);
2741 }
2742
2743 static HRESULT WINAPI MXAttributes_Invoke(
2744 IMXAttributes *iface,
2745 DISPID dispIdMember,
2746 REFIID riid,
2747 LCID lcid,
2748 WORD wFlags,
2749 DISPPARAMS* pDispParams,
2750 VARIANT* pVarResult,
2751 EXCEPINFO* pExcepInfo,
2752 UINT* puArgErr)
2753 {
2754 mxattributes *This = impl_from_IMXAttributes( iface );
2755 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
2756 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2757 }
2758
2759 static HRESULT WINAPI MXAttributes_addAttribute(IMXAttributes *iface,
2760 BSTR uri, BSTR localName, BSTR QName, BSTR type, BSTR value)
2761 {
2762 mxattributes *This = impl_from_IMXAttributes( iface );
2763 mxattribute *attr;
2764 HRESULT hr;
2765
2766 TRACE("(%p)->(%s %s %s %s %s)\n", This, debugstr_w(uri), debugstr_w(localName),
2767 debugstr_w(QName), debugstr_w(type), debugstr_w(value));
2768
2769 if ((!uri || !localName || !QName || !type || !value) && This->class_version != MSXML6)
2770 return E_INVALIDARG;
2771
2772 /* ensure array is large enough */
2773 hr = mxattributes_grow(This);
2774 if (hr != S_OK) return hr;
2775
2776 attr = &This->attr[This->length];
2777
2778 attr->qname = SysAllocString(QName);
2779 attr->local = SysAllocString(localName);
2780 attr->uri = SysAllocString(uri);
2781 attr->type = SysAllocString(type ? type : emptyW);
2782 attr->value = SysAllocString(value);
2783 This->length++;
2784
2785 return S_OK;
2786 }
2787
2788 static HRESULT WINAPI MXAttributes_addAttributeFromIndex(IMXAttributes *iface,
2789 VARIANT atts, int index)
2790 {
2791 mxattributes *This = impl_from_IMXAttributes( iface );
2792 FIXME("(%p)->(%s %d): stub\n", This, debugstr_variant(&atts), index);
2793 return E_NOTIMPL;
2794 }
2795
2796 static HRESULT WINAPI MXAttributes_clear(IMXAttributes *iface)
2797 {
2798 mxattributes *This = impl_from_IMXAttributes( iface );
2799 int i;
2800
2801 TRACE("(%p)\n", This);
2802
2803 for (i = 0; i < This->length; i++)
2804 {
2805 SysFreeString(This->attr[i].qname);
2806 SysFreeString(This->attr[i].local);
2807 SysFreeString(This->attr[i].uri);
2808 SysFreeString(This->attr[i].type);
2809 SysFreeString(This->attr[i].value);
2810 memset(&This->attr[i], 0, sizeof(mxattribute));
2811 }
2812
2813 This->length = 0;
2814
2815 return S_OK;
2816 }
2817
2818 static mxattribute *get_attribute_byindex(mxattributes *attrs, int index)
2819 {
2820 if (index < 0 || index >= attrs->length) return NULL;
2821 return &attrs->attr[index];
2822 }
2823
2824 static HRESULT WINAPI MXAttributes_removeAttribute(IMXAttributes *iface, int index)
2825 {
2826 mxattributes *This = impl_from_IMXAttributes( iface );
2827 mxattribute *dst;
2828
2829 TRACE("(%p)->(%d)\n", This, index);
2830
2831 if (!(dst = get_attribute_byindex(This, index))) return E_INVALIDARG;
2832
2833 /* no need to remove last attribute, just make it inaccessible */
2834 if (index + 1 == This->length)
2835 {
2836 This->length--;
2837 return S_OK;
2838 }
2839
2840 memmove(dst, dst + 1, (This->length-index-1)*sizeof(*dst));
2841 This->length--;
2842
2843 return S_OK;
2844 }
2845
2846 static HRESULT WINAPI MXAttributes_setAttribute(IMXAttributes *iface, int index,
2847 BSTR uri, BSTR localName, BSTR QName, BSTR type, BSTR value)
2848 {
2849 mxattributes *This = impl_from_IMXAttributes( iface );
2850 FIXME("(%p)->(%d %s %s %s %s %s): stub\n", This, index, debugstr_w(uri),
2851 debugstr_w(localName), debugstr_w(QName), debugstr_w(type), debugstr_w(value));
2852 return E_NOTIMPL;
2853 }
2854
2855 static HRESULT WINAPI MXAttributes_setAttributes(IMXAttributes *iface, VARIANT atts)
2856 {
2857 mxattributes *This = impl_from_IMXAttributes( iface );
2858 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&atts));
2859 return E_NOTIMPL;
2860 }
2861
2862 static HRESULT WINAPI MXAttributes_setLocalName(IMXAttributes *iface, int index,
2863 BSTR localName)
2864 {
2865 mxattributes *This = impl_from_IMXAttributes( iface );
2866 mxattribute *attr;
2867
2868 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(localName));
2869
2870 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
2871
2872 SysFreeString(attr->local);
2873 attr->local = SysAllocString(localName);
2874
2875 return S_OK;
2876 }
2877
2878 static HRESULT WINAPI MXAttributes_setQName(IMXAttributes *iface, int index, BSTR QName)
2879 {
2880 mxattributes *This = impl_from_IMXAttributes( iface );
2881 mxattribute *attr;
2882
2883 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(QName));
2884
2885 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
2886
2887 SysFreeString(attr->qname);
2888 attr->qname = SysAllocString(QName);
2889
2890 return S_OK;
2891 }
2892
2893 static HRESULT WINAPI MXAttributes_setURI(IMXAttributes *iface, int index, BSTR uri)
2894 {
2895 mxattributes *This = impl_from_IMXAttributes( iface );
2896 mxattribute *attr;
2897
2898 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(uri));
2899
2900 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
2901
2902 SysFreeString(attr->uri);
2903 attr->uri = SysAllocString(uri);
2904
2905 return S_OK;
2906 }
2907
2908 static HRESULT WINAPI MXAttributes_setValue(IMXAttributes *iface, int index, BSTR value)
2909 {
2910 mxattributes *This = impl_from_IMXAttributes( iface );
2911 mxattribute *attr;
2912
2913 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(value));
2914
2915 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
2916
2917 SysFreeString(attr->value);
2918 attr->value = SysAllocString(value);
2919
2920 return S_OK;
2921 }
2922
2923 static const IMXAttributesVtbl MXAttributesVtbl = {
2924 MXAttributes_QueryInterface,
2925 MXAttributes_AddRef,
2926 MXAttributes_Release,
2927 MXAttributes_GetTypeInfoCount,
2928 MXAttributes_GetTypeInfo,
2929 MXAttributes_GetIDsOfNames,
2930 MXAttributes_Invoke,
2931 MXAttributes_addAttribute,
2932 MXAttributes_addAttributeFromIndex,
2933 MXAttributes_clear,
2934 MXAttributes_removeAttribute,
2935 MXAttributes_setAttribute,
2936 MXAttributes_setAttributes,
2937 MXAttributes_setLocalName,
2938 MXAttributes_setQName,
2939 MXAttributes_setURI,
2940 MXAttributes_setValue
2941 };
2942
2943 static HRESULT WINAPI SAXAttributes_QueryInterface(ISAXAttributes *iface, REFIID riid, void **ppObj)
2944 {
2945 mxattributes *This = impl_from_ISAXAttributes( iface );
2946 return IMXAttributes_QueryInterface(&This->IMXAttributes_iface, riid, ppObj);
2947 }
2948
2949 static ULONG WINAPI SAXAttributes_AddRef(ISAXAttributes *iface)
2950 {
2951 mxattributes *This = impl_from_ISAXAttributes( iface );
2952 return IMXAttributes_AddRef(&This->IMXAttributes_iface);
2953 }
2954
2955 static ULONG WINAPI SAXAttributes_Release(ISAXAttributes *iface)
2956 {
2957 mxattributes *This = impl_from_ISAXAttributes( iface );
2958 return IMXAttributes_Release(&This->IMXAttributes_iface);
2959 }
2960
2961 static HRESULT WINAPI SAXAttributes_getLength(ISAXAttributes *iface, int *length)
2962 {
2963 mxattributes *This = impl_from_ISAXAttributes( iface );
2964 TRACE("(%p)->(%p)\n", This, length);
2965
2966 if (!length && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
2967 return E_POINTER;
2968
2969 *length = This->length;
2970
2971 return S_OK;
2972 }
2973
2974 static HRESULT WINAPI SAXAttributes_getURI(ISAXAttributes *iface, int index, const WCHAR **uri,
2975 int *len)
2976 {
2977 mxattributes *This = impl_from_ISAXAttributes( iface );
2978
2979 TRACE("(%p)->(%d %p %p)\n", This, index, uri, len);
2980
2981 if (index >= This->length || index < 0) return E_INVALIDARG;
2982 if (!uri || !len) return E_POINTER;
2983
2984 *len = SysStringLen(This->attr[index].uri);
2985 *uri = This->attr[index].uri;
2986
2987 return S_OK;
2988 }
2989
2990 static HRESULT WINAPI SAXAttributes_getLocalName(ISAXAttributes *iface, int index, const WCHAR **name,
2991 int *len)
2992 {
2993 mxattributes *This = impl_from_ISAXAttributes( iface );
2994
2995 TRACE("(%p)->(%d %p %p)\n", This, index, name, len);
2996
2997 if (index >= This->length || index < 0) return E_INVALIDARG;
2998 if (!name || !len) return E_POINTER;
2999
3000 *len = SysStringLen(This->attr[index].local);
3001 *name = This->attr[index].local;
3002
3003 return S_OK;
3004 }
3005
3006 static HRESULT WINAPI SAXAttributes_getQName(ISAXAttributes *iface, int index, const WCHAR **qname, int *length)
3007 {
3008 mxattributes *This = impl_from_ISAXAttributes( iface );
3009
3010 TRACE("(%p)->(%d %p %p)\n", This, index, qname, length);
3011
3012 if (index >= This->length) return E_INVALIDARG;
3013 if (!qname || !length) return E_POINTER;
3014
3015 *qname = This->attr[index].qname;
3016 *length = SysStringLen(This->attr[index].qname);
3017
3018 return S_OK;
3019 }
3020
3021 static HRESULT WINAPI SAXAttributes_getName(ISAXAttributes *iface, int index, const WCHAR **uri, int *uri_len,
3022 const WCHAR **local, int *local_len, const WCHAR **qname, int *qname_len)
3023 {
3024 mxattributes *This = impl_from_ISAXAttributes( iface );
3025
3026 TRACE("(%p)->(%d %p %p %p %p %p %p)\n", This, index, uri, uri_len, local, local_len, qname, qname_len);
3027
3028 if (index >= This->length || index < 0)
3029 return E_INVALIDARG;
3030
3031 if (!uri || !uri_len || !local || !local_len || !qname || !qname_len)
3032 return E_POINTER;
3033
3034 *uri_len = SysStringLen(This->attr[index].uri);
3035 *uri = This->attr[index].uri;
3036
3037 *local_len = SysStringLen(This->attr[index].local);
3038 *local = This->attr[index].local;
3039
3040 *qname_len = SysStringLen(This->attr[index].qname);
3041 *qname = This->attr[index].qname;
3042
3043 TRACE("(%s, %s, %s)\n", debugstr_w(*uri), debugstr_w(*local), debugstr_w(*qname));
3044
3045 return S_OK;
3046 }
3047
3048 static HRESULT WINAPI SAXAttributes_getIndexFromName(ISAXAttributes *iface, const WCHAR *uri, int uri_len,
3049 const WCHAR *name, int len, int *index)
3050 {
3051 mxattributes *This = impl_from_ISAXAttributes( iface );
3052 int i;
3053
3054 TRACE("(%p)->(%s:%d %s:%d %p)\n", This, debugstr_wn(uri, uri_len), uri_len,
3055 debugstr_wn(name, len), len, index);
3056
3057 if (!index && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
3058 return E_POINTER;
3059
3060 if (!uri || !name || !index) return E_INVALIDARG;
3061
3062 for (i = 0; i < This->length; i++)
3063 {
3064 if (uri_len != SysStringLen(This->attr[i].uri)) continue;
3065 if (strncmpW(uri, This->attr[i].uri, uri_len)) continue;
3066
3067 if (len != SysStringLen(This->attr[i].local)) continue;
3068 if (strncmpW(name, This->attr[i].local, len)) continue;
3069
3070 *index = i;
3071 return S_OK;
3072 }
3073
3074 return E_INVALIDARG;
3075 }
3076
3077 static HRESULT WINAPI SAXAttributes_getIndexFromQName(ISAXAttributes *iface, const WCHAR *qname,
3078 int len, int *index)
3079 {
3080 mxattributes *This = impl_from_ISAXAttributes( iface );
3081 int i;
3082
3083 TRACE("(%p)->(%s:%d %p)\n", This, debugstr_wn(qname, len), len, index);
3084
3085 if (!index && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
3086 return E_POINTER;
3087
3088 if (!qname || !index || !len) return E_INVALIDARG;
3089
3090 for (i = 0; i < This->length; i++)
3091 {
3092 if (len != SysStringLen(This->attr[i].qname)) continue;
3093 if (strncmpW(qname, This->attr[i].qname, len)) continue;
3094
3095 *index = i;
3096 return S_OK;
3097 }
3098
3099 return E_INVALIDARG;
3100 }
3101
3102 static HRESULT WINAPI SAXAttributes_getType(ISAXAttributes *iface, int index, const WCHAR **type,
3103 int *len)
3104 {
3105 mxattributes *This = impl_from_ISAXAttributes( iface );
3106
3107 TRACE("(%p)->(%d %p %p)\n", This, index, type, len);
3108
3109 if (index >= This->length) return E_INVALIDARG;
3110
3111 if ((!type || !len) && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
3112 return E_POINTER;
3113
3114 *type = This->attr[index].type;
3115 *len = SysStringLen(This->attr[index].type);
3116
3117 return S_OK;
3118 }
3119
3120 static HRESULT WINAPI SAXAttributes_getTypeFromName(ISAXAttributes *iface, const WCHAR * pUri, int nUri,
3121 const WCHAR * pLocalName, int nLocalName, const WCHAR ** pType, int * nType)
3122 {
3123 mxattributes *This = impl_from_ISAXAttributes( iface );
3124 FIXME("(%p)->(%s:%d %s:%d %p %p): stub\n", This, debugstr_wn(pUri, nUri), nUri,
3125 debugstr_wn(pLocalName, nLocalName), nLocalName, pT