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