ntdll/tests: Skip test if LdrAddRefDll is missing.
[wine.git] / dlls / msxml3 / mxwriter.c
blobdd4e6293c514955c9e350525117dbd59011fb898
1 /*
2 * MXWriter implementation
4 * Copyright 2011-2013 Nikolay Sivov for CodeWeavers
5 * Copyright 2011 Thomas Mullaly
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.
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.
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
22 #define COBJMACROS
23 #include "config.h"
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "ole2.h"
34 #include "msxml6.h"
36 #include "wine/debug.h"
38 #include "msxml_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
42 static const WCHAR emptyW[] = {0};
43 static const WCHAR spaceW[] = {' '};
44 static const WCHAR quotW[] = {'\"'};
45 static const WCHAR closetagW[] = {'>','\r','\n'};
46 static const WCHAR crlfW[] = {'\r','\n'};
47 static const WCHAR entityW[] = {'<','!','E','N','T','I','T','Y',' '};
49 /* should be ordered as encoding names are sorted */
50 typedef enum
52 XmlEncoding_ISO_8859_1 = 0,
53 XmlEncoding_ISO_8859_13,
54 XmlEncoding_ISO_8859_15,
55 XmlEncoding_ISO_8859_2,
56 XmlEncoding_ISO_8859_3,
57 XmlEncoding_ISO_8859_4,
58 XmlEncoding_ISO_8859_5,
59 XmlEncoding_ISO_8859_7,
60 XmlEncoding_ISO_8859_9,
61 XmlEncoding_UTF16,
62 XmlEncoding_UTF8,
63 XmlEncoding_Unknown
64 } xml_encoding;
66 struct xml_encoding_data
68 const WCHAR *encoding;
69 xml_encoding enc;
70 UINT cp;
73 static const WCHAR iso_8859_1W[] = {'i','s','o','-','8','8','5','9','-','1',0};
74 static const WCHAR iso_8859_2W[] = {'i','s','o','-','8','8','5','9','-','2',0};
75 static const WCHAR iso_8859_3W[] = {'i','s','o','-','8','8','5','9','-','3',0};
76 static const WCHAR iso_8859_4W[] = {'i','s','o','-','8','8','5','9','-','4',0};
77 static const WCHAR iso_8859_5W[] = {'i','s','o','-','8','8','5','9','-','5',0};
78 static const WCHAR iso_8859_7W[] = {'i','s','o','-','8','8','5','9','-','7',0};
79 static const WCHAR iso_8859_9W[] = {'i','s','o','-','8','8','5','9','-','9',0};
80 static const WCHAR iso_8859_13W[] = {'i','s','o','-','8','8','5','9','-','1','3',0};
81 static const WCHAR iso_8859_15W[] = {'i','s','o','-','8','8','5','9','-','1','5',0};
82 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
83 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
85 static const struct xml_encoding_data xml_encoding_map[] = {
86 { iso_8859_1W, XmlEncoding_ISO_8859_1, 28591 },
87 { iso_8859_13W, XmlEncoding_ISO_8859_13, 28603 },
88 { iso_8859_15W, XmlEncoding_ISO_8859_15, 28605 },
89 { iso_8859_2W, XmlEncoding_ISO_8859_2, 28592 },
90 { iso_8859_3W, XmlEncoding_ISO_8859_3, 28593 },
91 { iso_8859_4W, XmlEncoding_ISO_8859_4, 28594 },
92 { iso_8859_5W, XmlEncoding_ISO_8859_5, 28595 },
93 { iso_8859_7W, XmlEncoding_ISO_8859_7, 28597 },
94 { iso_8859_9W, XmlEncoding_ISO_8859_9, 28599 },
95 { utf16W, XmlEncoding_UTF16, ~0 },
96 { utf8W, XmlEncoding_UTF8, CP_UTF8 }
99 typedef enum
101 OutputBuffer_Native = 0x001,
102 OutputBuffer_Encoded = 0x010,
103 OutputBuffer_Both = 0x100
104 } output_mode;
106 typedef enum
108 MXWriter_BOM = 0,
109 MXWriter_DisableEscaping,
110 MXWriter_Indent,
111 MXWriter_OmitXmlDecl,
112 MXWriter_Standalone,
113 MXWriter_LastProp
114 } mxwriter_prop;
116 typedef enum
118 EscapeValue,
119 EscapeText
120 } escape_mode;
122 typedef struct
124 char *data;
125 unsigned int allocated;
126 unsigned int written;
127 } encoded_buffer;
129 typedef struct
131 encoded_buffer utf16;
132 encoded_buffer encoded;
133 UINT code_page;
134 } output_buffer;
136 typedef struct
138 DispatchEx dispex;
139 IMXWriter IMXWriter_iface;
140 ISAXContentHandler ISAXContentHandler_iface;
141 ISAXLexicalHandler ISAXLexicalHandler_iface;
142 ISAXDeclHandler ISAXDeclHandler_iface;
144 LONG ref;
145 MSXML_VERSION class_version;
147 VARIANT_BOOL props[MXWriter_LastProp];
148 BOOL prop_changed;
149 BOOL cdata;
151 BOOL text; /* last node was text node, so we shouldn't indent next node */
152 BOOL newline; /* newline was already added as a part of previous call */
153 UINT indent; /* indentation level for next node */
155 BSTR version;
157 BSTR encoding; /* exact property value */
158 xml_encoding xml_enc;
160 /* contains a pending (or not closed yet) element name or NULL if
161 we don't have to close */
162 BSTR element;
164 IStream *dest;
165 ULONG dest_written;
167 output_buffer *buffer;
168 } mxwriter;
170 typedef struct
172 BSTR qname;
173 BSTR local;
174 BSTR uri;
175 BSTR type;
176 BSTR value;
177 } mxattribute;
179 typedef struct
181 DispatchEx dispex;
182 IMXAttributes IMXAttributes_iface;
183 ISAXAttributes ISAXAttributes_iface;
184 IVBSAXAttributes IVBSAXAttributes_iface;
185 LONG ref;
187 MSXML_VERSION class_version;
189 mxattribute *attr;
190 int length;
191 int allocated;
192 } mxattributes;
194 static inline mxattributes *impl_from_IMXAttributes( IMXAttributes *iface )
196 return CONTAINING_RECORD(iface, mxattributes, IMXAttributes_iface);
199 static inline mxattributes *impl_from_ISAXAttributes( ISAXAttributes *iface )
201 return CONTAINING_RECORD(iface, mxattributes, ISAXAttributes_iface);
204 static inline mxattributes *impl_from_IVBSAXAttributes( IVBSAXAttributes *iface )
206 return CONTAINING_RECORD(iface, mxattributes, IVBSAXAttributes_iface);
209 static HRESULT mxattributes_grow(mxattributes *This)
211 if (This->length < This->allocated) return S_OK;
213 This->allocated *= 2;
214 This->attr = heap_realloc(This->attr, This->allocated*sizeof(mxattribute));
216 return This->attr ? S_OK : E_OUTOFMEMORY;
219 static xml_encoding parse_encoding_name(const WCHAR *encoding)
221 int min, max, n, c;
223 min = 0;
224 max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
226 while (min <= max)
228 n = (min+max)/2;
230 c = strcmpiW(xml_encoding_map[n].encoding, encoding);
231 if (!c)
232 return xml_encoding_map[n].enc;
234 if (c > 0)
235 max = n-1;
236 else
237 min = n+1;
240 return XmlEncoding_Unknown;
243 static HRESULT init_encoded_buffer(encoded_buffer *buffer)
245 const int initial_len = 0x2000;
246 buffer->data = heap_alloc(initial_len);
247 if (!buffer->data) return E_OUTOFMEMORY;
249 memset(buffer->data, 0, 4);
250 buffer->allocated = initial_len;
251 buffer->written = 0;
253 return S_OK;
256 static void free_encoded_buffer(encoded_buffer *buffer)
258 heap_free(buffer->data);
261 static HRESULT get_code_page(xml_encoding encoding, UINT *cp)
263 const struct xml_encoding_data *data;
265 if (encoding == XmlEncoding_Unknown)
267 FIXME("unsupported encoding %d\n", encoding);
268 return E_NOTIMPL;
271 data = &xml_encoding_map[encoding];
272 *cp = data->cp;
274 return S_OK;
277 static HRESULT alloc_output_buffer(xml_encoding encoding, output_buffer **buffer)
279 output_buffer *ret;
280 HRESULT hr;
282 ret = heap_alloc(sizeof(*ret));
283 if (!ret) return E_OUTOFMEMORY;
285 hr = get_code_page(encoding, &ret->code_page);
286 if (hr != S_OK) {
287 heap_free(ret);
288 return hr;
291 hr = init_encoded_buffer(&ret->utf16);
292 if (hr != S_OK) {
293 heap_free(ret);
294 return hr;
297 /* currently we always create a default output buffer that is UTF-16 only,
298 but it's possible to allocate with specific encoding too */
299 if (encoding != XmlEncoding_UTF16) {
300 hr = init_encoded_buffer(&ret->encoded);
301 if (hr != S_OK) {
302 free_encoded_buffer(&ret->utf16);
303 heap_free(ret);
304 return hr;
307 else
308 memset(&ret->encoded, 0, sizeof(ret->encoded));
310 *buffer = ret;
312 return S_OK;
315 static void free_output_buffer(output_buffer *buffer)
317 free_encoded_buffer(&buffer->encoded);
318 free_encoded_buffer(&buffer->utf16);
319 heap_free(buffer);
322 static void grow_buffer(encoded_buffer *buffer, int length)
324 /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
325 if (buffer->allocated < buffer->written + length + 4)
327 int grown_size = max(2*buffer->allocated, buffer->allocated + length);
328 buffer->data = heap_realloc(buffer->data, grown_size);
329 buffer->allocated = grown_size;
333 static HRESULT write_output_buffer_mode(output_buffer *buffer, output_mode mode, const WCHAR *data, int len)
335 int length;
336 char *ptr;
338 if (mode & (OutputBuffer_Encoded | OutputBuffer_Both)) {
339 if (buffer->code_page != ~0)
341 length = WideCharToMultiByte(buffer->code_page, 0, data, len, NULL, 0, NULL, NULL);
342 grow_buffer(&buffer->encoded, length);
343 ptr = buffer->encoded.data + buffer->encoded.written;
344 length = WideCharToMultiByte(buffer->code_page, 0, data, len, ptr, length, NULL, NULL);
345 buffer->encoded.written += len == -1 ? length-1 : length;
349 if (mode & (OutputBuffer_Native | OutputBuffer_Both)) {
350 /* WCHAR data just copied */
351 length = len == -1 ? strlenW(data) : len;
352 if (length)
354 length *= sizeof(WCHAR);
356 grow_buffer(&buffer->utf16, length);
357 ptr = buffer->utf16.data + buffer->utf16.written;
359 memcpy(ptr, data, length);
360 buffer->utf16.written += length;
361 ptr += length;
362 /* null termination */
363 memset(ptr, 0, sizeof(WCHAR));
367 return S_OK;
370 static HRESULT write_output_buffer(output_buffer *buffer, const WCHAR *data, int len)
372 return write_output_buffer_mode(buffer, OutputBuffer_Both, data, len);
375 static HRESULT write_output_buffer_quoted(output_buffer *buffer, const WCHAR *data, int len)
377 write_output_buffer(buffer, quotW, 1);
378 write_output_buffer(buffer, data, len);
379 write_output_buffer(buffer, quotW, 1);
381 return S_OK;
384 /* frees buffer data, reallocates with a default lengths */
385 static void close_output_buffer(mxwriter *This)
387 heap_free(This->buffer->utf16.data);
388 heap_free(This->buffer->encoded.data);
389 init_encoded_buffer(&This->buffer->utf16);
390 init_encoded_buffer(&This->buffer->encoded);
391 get_code_page(This->xml_enc, &This->buffer->code_page);
394 /* escapes special characters like:
395 '<' -> "&lt;"
396 '&' -> "&amp;"
397 '"' -> "&quot;"
398 '>' -> "&gt;"
400 static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len)
402 static const WCHAR ltW[] = {'&','l','t',';'};
403 static const WCHAR ampW[] = {'&','a','m','p',';'};
404 static const WCHAR equotW[] = {'&','q','u','o','t',';'};
405 static const WCHAR gtW[] = {'&','g','t',';'};
407 const int default_alloc = 100;
408 const int grow_thresh = 10;
409 int p = *len, conv_len;
410 WCHAR *ptr, *ret;
412 /* default buffer size to something if length is unknown */
413 conv_len = *len == -1 ? default_alloc : max(2**len, default_alloc);
414 ptr = ret = heap_alloc(conv_len*sizeof(WCHAR));
416 while (*str && p)
418 if (ptr - ret > conv_len - grow_thresh)
420 int written = ptr - ret;
421 conv_len *= 2;
422 ptr = ret = heap_realloc(ret, conv_len*sizeof(WCHAR));
423 ptr += written;
426 switch (*str)
428 case '<':
429 memcpy(ptr, ltW, sizeof(ltW));
430 ptr += sizeof(ltW)/sizeof(WCHAR);
431 break;
432 case '&':
433 memcpy(ptr, ampW, sizeof(ampW));
434 ptr += sizeof(ampW)/sizeof(WCHAR);
435 break;
436 case '>':
437 memcpy(ptr, gtW, sizeof(gtW));
438 ptr += sizeof(gtW)/sizeof(WCHAR);
439 break;
440 case '"':
441 if (mode == EscapeValue)
443 memcpy(ptr, equotW, sizeof(equotW));
444 ptr += sizeof(equotW)/sizeof(WCHAR);
445 break;
447 /* fallthrough for text mode */
448 default:
449 *ptr++ = *str;
450 break;
453 str++;
454 if (*len != -1) p--;
457 if (*len != -1) *len = ptr-ret;
458 *++ptr = 0;
460 return ret;
463 static void write_prolog_buffer(mxwriter *This)
465 static const WCHAR versionW[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','='};
466 static const WCHAR encodingW[] = {' ','e','n','c','o','d','i','n','g','=','\"'};
467 static const WCHAR standaloneW[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'};
468 static const WCHAR yesW[] = {'y','e','s','\"','?','>'};
469 static const WCHAR noW[] = {'n','o','\"','?','>'};
471 /* version */
472 write_output_buffer(This->buffer, versionW, sizeof(versionW)/sizeof(WCHAR));
473 write_output_buffer_quoted(This->buffer, This->version, -1);
475 /* encoding */
476 write_output_buffer(This->buffer, encodingW, sizeof(encodingW)/sizeof(WCHAR));
478 /* always write UTF-16 to WCHAR buffer */
479 write_output_buffer_mode(This->buffer, OutputBuffer_Native, utf16W, sizeof(utf16W)/sizeof(WCHAR) - 1);
480 write_output_buffer_mode(This->buffer, OutputBuffer_Encoded, This->encoding, -1);
481 write_output_buffer(This->buffer, quotW, 1);
483 /* standalone */
484 write_output_buffer(This->buffer, standaloneW, sizeof(standaloneW)/sizeof(WCHAR));
485 if (This->props[MXWriter_Standalone] == VARIANT_TRUE)
486 write_output_buffer(This->buffer, yesW, sizeof(yesW)/sizeof(WCHAR));
487 else
488 write_output_buffer(This->buffer, noW, sizeof(noW)/sizeof(WCHAR));
490 write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR));
491 This->newline = TRUE;
494 /* Attempts to the write data from the mxwriter's buffer to
495 * the destination stream (if there is one).
497 static HRESULT write_data_to_stream(mxwriter *This)
499 encoded_buffer *buffer;
500 ULONG written = 0;
501 HRESULT hr;
503 if (!This->dest)
504 return S_OK;
506 if (This->xml_enc != XmlEncoding_UTF16)
507 buffer = &This->buffer->encoded;
508 else
509 buffer = &This->buffer->utf16;
511 if (This->dest_written > buffer->written) {
512 ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This->dest_written, buffer->written);
513 return E_FAIL;
514 } else if (This->dest_written == buffer->written && This->xml_enc != XmlEncoding_UTF8)
515 /* Windows seems to make an empty write call when the encoding is UTF-8 and
516 * all the data has been written to the stream. It doesn't seem make this call
517 * for any other encodings.
519 return S_OK;
521 /* Write the current content from the output buffer into 'dest'.
522 * TODO: Check what Windows does if the IStream doesn't write all of
523 * the data we give it at once.
525 hr = IStream_Write(This->dest, buffer->data+This->dest_written,
526 buffer->written-This->dest_written, &written);
527 if (FAILED(hr)) {
528 WARN("Failed to write data to IStream (0x%08x)\n", hr);
529 return hr;
532 This->dest_written += written;
533 return hr;
536 /* Newly added element start tag left unclosed cause for empty elements
537 we have to close it differently. */
538 static void close_element_starttag(const mxwriter *This)
540 static const WCHAR gtW[] = {'>'};
541 if (!This->element) return;
542 write_output_buffer(This->buffer, gtW, 1);
545 static void write_node_indent(mxwriter *This)
547 static const WCHAR tabW[] = {'\t'};
548 int indent = This->indent;
550 if (!This->props[MXWriter_Indent] || This->text)
552 This->text = FALSE;
553 return;
556 /* This is to workaround PI output logic that always puts newline chars,
557 document prolog PI does that too. */
558 if (!This->newline)
559 write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR));
560 while (indent--)
561 write_output_buffer(This->buffer, tabW, 1);
563 This->newline = FALSE;
564 This->text = FALSE;
567 static inline void writer_inc_indent(mxwriter *This)
569 This->indent++;
572 static inline void writer_dec_indent(mxwriter *This)
574 if (This->indent) This->indent--;
575 /* depth is decreased only when element is closed, meaning it's not a text node
576 at this point */
577 This->text = FALSE;
580 static void set_element_name(mxwriter *This, const WCHAR *name, int len)
582 SysFreeString(This->element);
583 if (name)
584 This->element = len != -1 ? SysAllocStringLen(name, len) : SysAllocString(name);
585 else
586 This->element = NULL;
589 static inline HRESULT flush_output_buffer(mxwriter *This)
591 close_element_starttag(This);
592 set_element_name(This, NULL, 0);
593 This->cdata = FALSE;
594 return write_data_to_stream(This);
597 /* Resets the mxwriter's output buffer by closing it, then creating a new
598 * output buffer using the given encoding.
600 static inline void reset_output_buffer(mxwriter *This)
602 close_output_buffer(This);
603 This->dest_written = 0;
606 static HRESULT writer_set_property(mxwriter *writer, mxwriter_prop property, VARIANT_BOOL value)
608 writer->props[property] = value;
609 writer->prop_changed = TRUE;
610 return S_OK;
613 static HRESULT writer_get_property(const mxwriter *writer, mxwriter_prop property, VARIANT_BOOL *value)
615 if (!value) return E_POINTER;
616 *value = writer->props[property];
617 return S_OK;
620 static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
622 return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
625 static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
627 return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
630 static inline mxwriter *impl_from_ISAXLexicalHandler(ISAXLexicalHandler *iface)
632 return CONTAINING_RECORD(iface, mxwriter, ISAXLexicalHandler_iface);
635 static inline mxwriter *impl_from_ISAXDeclHandler(ISAXDeclHandler *iface)
637 return CONTAINING_RECORD(iface, mxwriter, ISAXDeclHandler_iface);
640 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
642 mxwriter *This = impl_from_IMXWriter( iface );
644 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
646 *obj = NULL;
648 if ( IsEqualGUID( riid, &IID_IMXWriter ) ||
649 IsEqualGUID( riid, &IID_IDispatch ) ||
650 IsEqualGUID( riid, &IID_IUnknown ) )
652 *obj = &This->IMXWriter_iface;
654 else if ( IsEqualGUID( riid, &IID_ISAXContentHandler ) )
656 *obj = &This->ISAXContentHandler_iface;
658 else if ( IsEqualGUID( riid, &IID_ISAXLexicalHandler ) )
660 *obj = &This->ISAXLexicalHandler_iface;
662 else if ( IsEqualGUID( riid, &IID_ISAXDeclHandler ) )
664 *obj = &This->ISAXDeclHandler_iface;
666 else if (dispex_query_interface(&This->dispex, riid, obj))
668 return *obj ? S_OK : E_NOINTERFACE;
670 else
672 ERR("interface %s not implemented\n", debugstr_guid(riid));
673 *obj = NULL;
674 return E_NOINTERFACE;
677 IMXWriter_AddRef(iface);
678 return S_OK;
681 static ULONG WINAPI mxwriter_AddRef(IMXWriter *iface)
683 mxwriter *This = impl_from_IMXWriter( iface );
684 LONG ref = InterlockedIncrement(&This->ref);
686 TRACE("(%p)->(%d)\n", This, ref);
688 return ref;
691 static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
693 mxwriter *This = impl_from_IMXWriter( iface );
694 ULONG ref = InterlockedDecrement(&This->ref);
696 TRACE("(%p)->(%d)\n", This, ref);
698 if(!ref)
700 /* Windows flushes the buffer when the interface is destroyed. */
701 flush_output_buffer(This);
702 free_output_buffer(This->buffer);
704 if (This->dest) IStream_Release(This->dest);
705 SysFreeString(This->version);
706 SysFreeString(This->encoding);
708 SysFreeString(This->element);
709 release_dispex(&This->dispex);
710 heap_free(This);
713 return ref;
716 static HRESULT WINAPI mxwriter_GetTypeInfoCount(IMXWriter *iface, UINT* pctinfo)
718 mxwriter *This = impl_from_IMXWriter( iface );
719 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
722 static HRESULT WINAPI mxwriter_GetTypeInfo(
723 IMXWriter *iface,
724 UINT iTInfo, LCID lcid,
725 ITypeInfo** ppTInfo )
727 mxwriter *This = impl_from_IMXWriter( iface );
728 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
729 iTInfo, lcid, ppTInfo);
732 static HRESULT WINAPI mxwriter_GetIDsOfNames(
733 IMXWriter *iface,
734 REFIID riid, LPOLESTR* rgszNames,
735 UINT cNames, LCID lcid, DISPID* rgDispId )
737 mxwriter *This = impl_from_IMXWriter( iface );
738 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
739 riid, rgszNames, cNames, lcid, rgDispId);
742 static HRESULT WINAPI mxwriter_Invoke(
743 IMXWriter *iface,
744 DISPID dispIdMember, REFIID riid, LCID lcid,
745 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
746 EXCEPINFO* pExcepInfo, UINT* puArgErr )
748 mxwriter *This = impl_from_IMXWriter( iface );
749 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
750 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
753 static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
755 mxwriter *This = impl_from_IMXWriter( iface );
756 HRESULT hr;
758 TRACE("(%p)->(%s)\n", This, debugstr_variant(&dest));
760 hr = flush_output_buffer(This);
761 if (FAILED(hr))
762 return hr;
764 switch (V_VT(&dest))
766 case VT_EMPTY:
768 if (This->dest) IStream_Release(This->dest);
769 This->dest = NULL;
770 reset_output_buffer(This);
771 break;
773 case VT_UNKNOWN:
775 IStream *stream;
777 hr = IUnknown_QueryInterface(V_UNKNOWN(&dest), &IID_IStream, (void**)&stream);
778 if (hr == S_OK)
780 /* Recreate the output buffer to make sure it's using the correct encoding. */
781 reset_output_buffer(This);
783 if (This->dest) IStream_Release(This->dest);
784 This->dest = stream;
785 break;
788 FIXME("unhandled interface type for VT_UNKNOWN destination\n");
789 return E_NOTIMPL;
791 default:
792 FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
793 return E_NOTIMPL;
796 return S_OK;
799 static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
801 mxwriter *This = impl_from_IMXWriter( iface );
803 TRACE("(%p)->(%p)\n", This, dest);
805 if (!dest) return E_POINTER;
807 if (!This->dest)
809 HRESULT hr = flush_output_buffer(This);
810 if (FAILED(hr))
811 return hr;
813 V_VT(dest) = VT_BSTR;
814 V_BSTR(dest) = SysAllocString((WCHAR*)This->buffer->utf16.data);
816 return S_OK;
819 /* we only support IStream output so far */
820 V_VT(dest) = VT_UNKNOWN;
821 V_UNKNOWN(dest) = (IUnknown*)This->dest;
822 IStream_AddRef(This->dest);
824 return S_OK;
827 static HRESULT WINAPI mxwriter_put_encoding(IMXWriter *iface, BSTR encoding)
829 mxwriter *This = impl_from_IMXWriter( iface );
830 xml_encoding enc;
831 HRESULT hr;
833 TRACE("(%p)->(%s)\n", This, debugstr_w(encoding));
835 enc = parse_encoding_name(encoding);
836 if (enc == XmlEncoding_Unknown)
838 FIXME("unsupported encoding %s\n", debugstr_w(encoding));
839 return E_INVALIDARG;
842 hr = flush_output_buffer(This);
843 if (FAILED(hr))
844 return hr;
846 SysReAllocString(&This->encoding, encoding);
847 This->xml_enc = enc;
849 TRACE("got encoding %d\n", This->xml_enc);
850 reset_output_buffer(This);
851 return S_OK;
854 static HRESULT WINAPI mxwriter_get_encoding(IMXWriter *iface, BSTR *encoding)
856 mxwriter *This = impl_from_IMXWriter( iface );
858 TRACE("(%p)->(%p)\n", This, encoding);
860 if (!encoding) return E_POINTER;
862 *encoding = SysAllocString(This->encoding);
863 if (!*encoding) return E_OUTOFMEMORY;
865 return S_OK;
868 static HRESULT WINAPI mxwriter_put_byteOrderMark(IMXWriter *iface, VARIANT_BOOL value)
870 mxwriter *This = impl_from_IMXWriter( iface );
872 TRACE("(%p)->(%d)\n", This, value);
873 return writer_set_property(This, MXWriter_BOM, value);
876 static HRESULT WINAPI mxwriter_get_byteOrderMark(IMXWriter *iface, VARIANT_BOOL *value)
878 mxwriter *This = impl_from_IMXWriter( iface );
880 TRACE("(%p)->(%p)\n", This, value);
881 return writer_get_property(This, MXWriter_BOM, value);
884 static HRESULT WINAPI mxwriter_put_indent(IMXWriter *iface, VARIANT_BOOL value)
886 mxwriter *This = impl_from_IMXWriter( iface );
888 TRACE("(%p)->(%d)\n", This, value);
889 return writer_set_property(This, MXWriter_Indent, value);
892 static HRESULT WINAPI mxwriter_get_indent(IMXWriter *iface, VARIANT_BOOL *value)
894 mxwriter *This = impl_from_IMXWriter( iface );
896 TRACE("(%p)->(%p)\n", This, value);
897 return writer_get_property(This, MXWriter_Indent, value);
900 static HRESULT WINAPI mxwriter_put_standalone(IMXWriter *iface, VARIANT_BOOL value)
902 mxwriter *This = impl_from_IMXWriter( iface );
904 TRACE("(%p)->(%d)\n", This, value);
905 return writer_set_property(This, MXWriter_Standalone, value);
908 static HRESULT WINAPI mxwriter_get_standalone(IMXWriter *iface, VARIANT_BOOL *value)
910 mxwriter *This = impl_from_IMXWriter( iface );
912 TRACE("(%p)->(%p)\n", This, value);
913 return writer_get_property(This, MXWriter_Standalone, value);
916 static HRESULT WINAPI mxwriter_put_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL value)
918 mxwriter *This = impl_from_IMXWriter( iface );
920 TRACE("(%p)->(%d)\n", This, value);
921 return writer_set_property(This, MXWriter_OmitXmlDecl, value);
924 static HRESULT WINAPI mxwriter_get_omitXMLDeclaration(IMXWriter *iface, VARIANT_BOOL *value)
926 mxwriter *This = impl_from_IMXWriter( iface );
928 TRACE("(%p)->(%p)\n", This, value);
929 return writer_get_property(This, MXWriter_OmitXmlDecl, value);
932 static HRESULT WINAPI mxwriter_put_version(IMXWriter *iface, BSTR version)
934 mxwriter *This = impl_from_IMXWriter( iface );
936 TRACE("(%p)->(%s)\n", This, debugstr_w(version));
938 if (!version) return E_INVALIDARG;
940 SysFreeString(This->version);
941 This->version = SysAllocString(version);
943 return S_OK;
946 static HRESULT WINAPI mxwriter_get_version(IMXWriter *iface, BSTR *version)
948 mxwriter *This = impl_from_IMXWriter( iface );
950 TRACE("(%p)->(%p)\n", This, version);
952 if (!version) return E_POINTER;
954 return return_bstr(This->version, version);
957 static HRESULT WINAPI mxwriter_put_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL value)
959 mxwriter *This = impl_from_IMXWriter( iface );
961 TRACE("(%p)->(%d)\n", This, value);
962 return writer_set_property(This, MXWriter_DisableEscaping, value);
965 static HRESULT WINAPI mxwriter_get_disableOutputEscaping(IMXWriter *iface, VARIANT_BOOL *value)
967 mxwriter *This = impl_from_IMXWriter( iface );
969 TRACE("(%p)->(%p)\n", This, value);
970 return writer_get_property(This, MXWriter_DisableEscaping, value);
973 static HRESULT WINAPI mxwriter_flush(IMXWriter *iface)
975 mxwriter *This = impl_from_IMXWriter( iface );
976 TRACE("(%p)\n", This);
977 return flush_output_buffer(This);
980 static const struct IMXWriterVtbl MXWriterVtbl =
982 mxwriter_QueryInterface,
983 mxwriter_AddRef,
984 mxwriter_Release,
985 mxwriter_GetTypeInfoCount,
986 mxwriter_GetTypeInfo,
987 mxwriter_GetIDsOfNames,
988 mxwriter_Invoke,
989 mxwriter_put_output,
990 mxwriter_get_output,
991 mxwriter_put_encoding,
992 mxwriter_get_encoding,
993 mxwriter_put_byteOrderMark,
994 mxwriter_get_byteOrderMark,
995 mxwriter_put_indent,
996 mxwriter_get_indent,
997 mxwriter_put_standalone,
998 mxwriter_get_standalone,
999 mxwriter_put_omitXMLDeclaration,
1000 mxwriter_get_omitXMLDeclaration,
1001 mxwriter_put_version,
1002 mxwriter_get_version,
1003 mxwriter_put_disableOutputEscaping,
1004 mxwriter_get_disableOutputEscaping,
1005 mxwriter_flush
1008 /*** ISAXContentHandler ***/
1009 static HRESULT WINAPI SAXContentHandler_QueryInterface(
1010 ISAXContentHandler *iface,
1011 REFIID riid,
1012 void **obj)
1014 mxwriter *This = impl_from_ISAXContentHandler( iface );
1015 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1018 static ULONG WINAPI SAXContentHandler_AddRef(ISAXContentHandler *iface)
1020 mxwriter *This = impl_from_ISAXContentHandler( iface );
1021 return IMXWriter_AddRef(&This->IMXWriter_iface);
1024 static ULONG WINAPI SAXContentHandler_Release(ISAXContentHandler *iface)
1026 mxwriter *This = impl_from_ISAXContentHandler( iface );
1027 return IMXWriter_Release(&This->IMXWriter_iface);
1030 static HRESULT WINAPI SAXContentHandler_putDocumentLocator(
1031 ISAXContentHandler *iface,
1032 ISAXLocator *locator)
1034 mxwriter *This = impl_from_ISAXContentHandler( iface );
1035 FIXME("(%p)->(%p)\n", This, locator);
1036 return E_NOTIMPL;
1039 static HRESULT WINAPI SAXContentHandler_startDocument(ISAXContentHandler *iface)
1041 mxwriter *This = impl_from_ISAXContentHandler( iface );
1043 TRACE("(%p)\n", This);
1045 /* If properties have been changed since the last "endDocument" call
1046 * we need to reset the output buffer. If we don't the output buffer
1047 * could end up with multiple XML documents in it, plus this seems to
1048 * be how Windows works.
1050 if (This->prop_changed) {
1051 reset_output_buffer(This);
1052 This->prop_changed = FALSE;
1055 if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
1057 write_prolog_buffer(This);
1059 if (This->dest && This->xml_enc == XmlEncoding_UTF16) {
1060 static const char utf16BOM[] = {0xff,0xfe};
1062 if (This->props[MXWriter_BOM] == VARIANT_TRUE)
1063 /* Windows passes a NULL pointer as the pcbWritten parameter and
1064 * ignores any error codes returned from this Write call.
1066 IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
1069 return S_OK;
1072 static HRESULT WINAPI SAXContentHandler_endDocument(ISAXContentHandler *iface)
1074 mxwriter *This = impl_from_ISAXContentHandler( iface );
1075 TRACE("(%p)\n", This);
1076 This->prop_changed = FALSE;
1077 return flush_output_buffer(This);
1080 static HRESULT WINAPI SAXContentHandler_startPrefixMapping(
1081 ISAXContentHandler *iface,
1082 const WCHAR *prefix,
1083 int nprefix,
1084 const WCHAR *uri,
1085 int nuri)
1087 mxwriter *This = impl_from_ISAXContentHandler( iface );
1088 FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
1089 return E_NOTIMPL;
1092 static HRESULT WINAPI SAXContentHandler_endPrefixMapping(
1093 ISAXContentHandler *iface,
1094 const WCHAR *prefix,
1095 int nprefix)
1097 mxwriter *This = impl_from_ISAXContentHandler( iface );
1098 FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
1099 return E_NOTIMPL;
1102 static HRESULT WINAPI SAXContentHandler_startElement(
1103 ISAXContentHandler *iface,
1104 const WCHAR *namespaceUri,
1105 int nnamespaceUri,
1106 const WCHAR *local_name,
1107 int nlocal_name,
1108 const WCHAR *QName,
1109 int nQName,
1110 ISAXAttributes *attr)
1112 mxwriter *This = impl_from_ISAXContentHandler( iface );
1113 static const WCHAR ltW[] = {'<'};
1115 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
1116 debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
1118 if (((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6) ||
1119 (nQName == -1 && This->class_version == MSXML6))
1120 return E_INVALIDARG;
1122 close_element_starttag(This);
1123 set_element_name(This, QName ? QName : emptyW,
1124 QName ? nQName : 0);
1126 write_node_indent(This);
1128 write_output_buffer(This->buffer, ltW, 1);
1129 write_output_buffer(This->buffer, QName, nQName);
1130 writer_inc_indent(This);
1132 if (attr)
1134 int length, i, escape;
1135 HRESULT hr;
1137 hr = ISAXAttributes_getLength(attr, &length);
1138 if (FAILED(hr)) return hr;
1140 escape = This->props[MXWriter_DisableEscaping] == VARIANT_FALSE ||
1141 (This->class_version == MSXML4 || This->class_version == MSXML6);
1143 for (i = 0; i < length; i++)
1145 static const WCHAR eqW[] = {'='};
1146 const WCHAR *str;
1147 int len = 0;
1149 hr = ISAXAttributes_getQName(attr, i, &str, &len);
1150 if (FAILED(hr)) return hr;
1152 /* space separator in front of every attribute */
1153 write_output_buffer(This->buffer, spaceW, 1);
1154 write_output_buffer(This->buffer, str, len);
1156 write_output_buffer(This->buffer, eqW, 1);
1158 len = 0;
1159 hr = ISAXAttributes_getValue(attr, i, &str, &len);
1160 if (FAILED(hr)) return hr;
1162 if (escape)
1164 WCHAR *escaped = get_escaped_string(str, EscapeValue, &len);
1165 write_output_buffer_quoted(This->buffer, escaped, len);
1166 heap_free(escaped);
1168 else
1169 write_output_buffer_quoted(This->buffer, str, len);
1173 return S_OK;
1176 static HRESULT WINAPI SAXContentHandler_endElement(
1177 ISAXContentHandler *iface,
1178 const WCHAR *namespaceUri,
1179 int nnamespaceUri,
1180 const WCHAR * local_name,
1181 int nlocal_name,
1182 const WCHAR *QName,
1183 int nQName)
1185 mxwriter *This = impl_from_ISAXContentHandler( iface );
1187 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(namespaceUri, nnamespaceUri), nnamespaceUri,
1188 debugstr_wn(local_name, nlocal_name), nlocal_name, debugstr_wn(QName, nQName), nQName);
1190 if (((!namespaceUri || !local_name || !QName) && This->class_version != MSXML6) ||
1191 (nQName == -1 && This->class_version == MSXML6))
1192 return E_INVALIDARG;
1194 writer_dec_indent(This);
1196 if (This->element)
1198 static const WCHAR closeW[] = {'/','>'};
1199 write_output_buffer(This->buffer, closeW, 2);
1201 else
1203 static const WCHAR closetagW[] = {'<','/'};
1204 static const WCHAR gtW[] = {'>'};
1206 write_node_indent(This);
1207 write_output_buffer(This->buffer, closetagW, 2);
1208 write_output_buffer(This->buffer, QName, nQName);
1209 write_output_buffer(This->buffer, gtW, 1);
1212 set_element_name(This, NULL, 0);
1214 return S_OK;
1217 static HRESULT WINAPI SAXContentHandler_characters(
1218 ISAXContentHandler *iface,
1219 const WCHAR *chars,
1220 int nchars)
1222 mxwriter *This = impl_from_ISAXContentHandler( iface );
1224 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
1226 if (!chars) return E_INVALIDARG;
1228 close_element_starttag(This);
1229 set_element_name(This, NULL, 0);
1231 if (!This->cdata)
1232 This->text = TRUE;
1234 if (nchars)
1236 if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE)
1237 write_output_buffer(This->buffer, chars, nchars);
1238 else
1240 int len = nchars;
1241 WCHAR *escaped;
1243 escaped = get_escaped_string(chars, EscapeText, &len);
1244 write_output_buffer(This->buffer, escaped, len);
1245 heap_free(escaped);
1249 return S_OK;
1252 static HRESULT WINAPI SAXContentHandler_ignorableWhitespace(
1253 ISAXContentHandler *iface,
1254 const WCHAR *chars,
1255 int nchars)
1257 mxwriter *This = impl_from_ISAXContentHandler( iface );
1259 TRACE("(%p)->(%s)\n", This, debugstr_wn(chars, nchars));
1261 if (!chars) return E_INVALIDARG;
1263 write_output_buffer(This->buffer, chars, nchars);
1265 return S_OK;
1268 static HRESULT WINAPI SAXContentHandler_processingInstruction(
1269 ISAXContentHandler *iface,
1270 const WCHAR *target,
1271 int ntarget,
1272 const WCHAR *data,
1273 int ndata)
1275 mxwriter *This = impl_from_ISAXContentHandler( iface );
1276 static const WCHAR openpiW[] = {'<','?'};
1277 static const WCHAR closepiW[] = {'?','>','\r','\n'};
1279 TRACE("(%p)->(%s %s)\n", This, debugstr_wn(target, ntarget), debugstr_wn(data, ndata));
1281 if (!target) return E_INVALIDARG;
1283 write_node_indent(This);
1284 write_output_buffer(This->buffer, openpiW, sizeof(openpiW)/sizeof(WCHAR));
1286 if (*target)
1287 write_output_buffer(This->buffer, target, ntarget);
1289 if (data && *data && ndata)
1291 write_output_buffer(This->buffer, spaceW, 1);
1292 write_output_buffer(This->buffer, data, ndata);
1295 write_output_buffer(This->buffer, closepiW, sizeof(closepiW)/sizeof(WCHAR));
1296 This->newline = TRUE;
1298 return S_OK;
1301 static HRESULT WINAPI SAXContentHandler_skippedEntity(
1302 ISAXContentHandler *iface,
1303 const WCHAR *name,
1304 int nname)
1306 mxwriter *This = impl_from_ISAXContentHandler( iface );
1307 FIXME("(%p)->(%s)\n", This, debugstr_wn(name, nname));
1308 return E_NOTIMPL;
1311 static const struct ISAXContentHandlerVtbl SAXContentHandlerVtbl =
1313 SAXContentHandler_QueryInterface,
1314 SAXContentHandler_AddRef,
1315 SAXContentHandler_Release,
1316 SAXContentHandler_putDocumentLocator,
1317 SAXContentHandler_startDocument,
1318 SAXContentHandler_endDocument,
1319 SAXContentHandler_startPrefixMapping,
1320 SAXContentHandler_endPrefixMapping,
1321 SAXContentHandler_startElement,
1322 SAXContentHandler_endElement,
1323 SAXContentHandler_characters,
1324 SAXContentHandler_ignorableWhitespace,
1325 SAXContentHandler_processingInstruction,
1326 SAXContentHandler_skippedEntity
1329 /*** ISAXLexicalHandler ***/
1330 static HRESULT WINAPI SAXLexicalHandler_QueryInterface(ISAXLexicalHandler *iface,
1331 REFIID riid, void **obj)
1333 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1334 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1337 static ULONG WINAPI SAXLexicalHandler_AddRef(ISAXLexicalHandler *iface)
1339 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1340 return IMXWriter_AddRef(&This->IMXWriter_iface);
1343 static ULONG WINAPI SAXLexicalHandler_Release(ISAXLexicalHandler *iface)
1345 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1346 return IMXWriter_Release(&This->IMXWriter_iface);
1349 static HRESULT WINAPI SAXLexicalHandler_startDTD(ISAXLexicalHandler *iface,
1350 const WCHAR *name, int name_len, const WCHAR *publicId, int publicId_len,
1351 const WCHAR *systemId, int systemId_len)
1353 static const WCHAR doctypeW[] = {'<','!','D','O','C','T','Y','P','E',' '};
1354 static const WCHAR openintW[] = {'[','\r','\n'};
1356 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1358 TRACE("(%p)->(%s %s %s)\n", This, debugstr_wn(name, name_len), debugstr_wn(publicId, publicId_len),
1359 debugstr_wn(systemId, systemId_len));
1361 if (!name) return E_INVALIDARG;
1363 write_output_buffer(This->buffer, doctypeW, sizeof(doctypeW)/sizeof(WCHAR));
1365 if (*name)
1367 write_output_buffer(This->buffer, name, name_len);
1368 write_output_buffer(This->buffer, spaceW, 1);
1371 if (publicId)
1373 static const WCHAR publicW[] = {'P','U','B','L','I','C',' '};
1375 write_output_buffer(This->buffer, publicW, sizeof(publicW)/sizeof(WCHAR));
1376 write_output_buffer_quoted(This->buffer, publicId, publicId_len);
1378 if (!systemId) return E_INVALIDARG;
1380 if (*publicId)
1381 write_output_buffer(This->buffer, spaceW, 1);
1383 write_output_buffer_quoted(This->buffer, systemId, systemId_len);
1385 if (*systemId)
1386 write_output_buffer(This->buffer, spaceW, 1);
1388 else if (systemId)
1390 static const WCHAR systemW[] = {'S','Y','S','T','E','M',' '};
1392 write_output_buffer(This->buffer, systemW, sizeof(systemW)/sizeof(WCHAR));
1393 write_output_buffer_quoted(This->buffer, systemId, systemId_len);
1394 if (*systemId)
1395 write_output_buffer(This->buffer, spaceW, 1);
1398 write_output_buffer(This->buffer, openintW, sizeof(openintW)/sizeof(WCHAR));
1400 return S_OK;
1403 static HRESULT WINAPI SAXLexicalHandler_endDTD(ISAXLexicalHandler *iface)
1405 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1406 static const WCHAR closedtdW[] = {']','>','\r','\n'};
1408 TRACE("(%p)\n", This);
1410 write_output_buffer(This->buffer, closedtdW, sizeof(closedtdW)/sizeof(WCHAR));
1412 return S_OK;
1415 static HRESULT WINAPI SAXLexicalHandler_startEntity(ISAXLexicalHandler *iface, const WCHAR *name, int len)
1417 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1418 FIXME("(%p)->(%s): stub\n", This, debugstr_wn(name, len));
1419 return E_NOTIMPL;
1422 static HRESULT WINAPI SAXLexicalHandler_endEntity(ISAXLexicalHandler *iface, const WCHAR *name, int len)
1424 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1425 FIXME("(%p)->(%s): stub\n", This, debugstr_wn(name, len));
1426 return E_NOTIMPL;
1429 static HRESULT WINAPI SAXLexicalHandler_startCDATA(ISAXLexicalHandler *iface)
1431 static const WCHAR scdataW[] = {'<','!','[','C','D','A','T','A','['};
1432 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1434 TRACE("(%p)\n", This);
1436 write_node_indent(This);
1437 write_output_buffer(This->buffer, scdataW, sizeof(scdataW)/sizeof(WCHAR));
1438 This->cdata = TRUE;
1440 return S_OK;
1443 static HRESULT WINAPI SAXLexicalHandler_endCDATA(ISAXLexicalHandler *iface)
1445 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1446 static const WCHAR ecdataW[] = {']',']','>'};
1448 TRACE("(%p)\n", This);
1450 write_output_buffer(This->buffer, ecdataW, sizeof(ecdataW)/sizeof(WCHAR));
1451 This->cdata = FALSE;
1453 return S_OK;
1456 static HRESULT WINAPI SAXLexicalHandler_comment(ISAXLexicalHandler *iface, const WCHAR *chars, int nchars)
1458 mxwriter *This = impl_from_ISAXLexicalHandler( iface );
1459 static const WCHAR copenW[] = {'<','!','-','-'};
1460 static const WCHAR ccloseW[] = {'-','-','>','\r','\n'};
1462 TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars);
1464 if (!chars) return E_INVALIDARG;
1466 close_element_starttag(This);
1467 write_node_indent(This);
1469 write_output_buffer(This->buffer, copenW, sizeof(copenW)/sizeof(WCHAR));
1470 if (nchars)
1471 write_output_buffer(This->buffer, chars, nchars);
1472 write_output_buffer(This->buffer, ccloseW, sizeof(ccloseW)/sizeof(WCHAR));
1474 return S_OK;
1477 static const struct ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1479 SAXLexicalHandler_QueryInterface,
1480 SAXLexicalHandler_AddRef,
1481 SAXLexicalHandler_Release,
1482 SAXLexicalHandler_startDTD,
1483 SAXLexicalHandler_endDTD,
1484 SAXLexicalHandler_startEntity,
1485 SAXLexicalHandler_endEntity,
1486 SAXLexicalHandler_startCDATA,
1487 SAXLexicalHandler_endCDATA,
1488 SAXLexicalHandler_comment
1491 /*** ISAXDeclHandler ***/
1492 static HRESULT WINAPI SAXDeclHandler_QueryInterface(ISAXDeclHandler *iface,
1493 REFIID riid, void **obj)
1495 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1496 return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
1499 static ULONG WINAPI SAXDeclHandler_AddRef(ISAXDeclHandler *iface)
1501 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1502 return IMXWriter_AddRef(&This->IMXWriter_iface);
1505 static ULONG WINAPI SAXDeclHandler_Release(ISAXDeclHandler *iface)
1507 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1508 return IMXWriter_Release(&This->IMXWriter_iface);
1511 static HRESULT WINAPI SAXDeclHandler_elementDecl(ISAXDeclHandler *iface,
1512 const WCHAR *name, int n_name, const WCHAR *model, int n_model)
1514 static const WCHAR elementW[] = {'<','!','E','L','E','M','E','N','T',' '};
1515 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1517 TRACE("(%p)->(%s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1518 debugstr_wn(model, n_model), n_model);
1520 if (!name || !model) return E_INVALIDARG;
1522 write_output_buffer(This->buffer, elementW, sizeof(elementW)/sizeof(WCHAR));
1523 if (n_name) {
1524 write_output_buffer(This->buffer, name, n_name);
1525 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1527 if (n_model)
1528 write_output_buffer(This->buffer, model, n_model);
1529 write_output_buffer(This->buffer, closetagW, sizeof(closetagW)/sizeof(WCHAR));
1531 return S_OK;
1534 static HRESULT WINAPI SAXDeclHandler_attributeDecl(ISAXDeclHandler *iface,
1535 const WCHAR *element, int n_element, const WCHAR *attr, int n_attr,
1536 const WCHAR *type, int n_type, const WCHAR *Default, int n_default,
1537 const WCHAR *value, int n_value)
1539 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1540 static const WCHAR attlistW[] = {'<','!','A','T','T','L','I','S','T',' '};
1541 static const WCHAR closetagW[] = {'>','\r','\n'};
1543 TRACE("(%p)->(%s:%d %s:%d %s:%d %s:%d %s:%d)\n", This, debugstr_wn(element, n_element), n_element,
1544 debugstr_wn(attr, n_attr), n_attr, debugstr_wn(type, n_type), n_type, debugstr_wn(Default, n_default), n_default,
1545 debugstr_wn(value, n_value), n_value);
1547 write_output_buffer(This->buffer, attlistW, sizeof(attlistW)/sizeof(WCHAR));
1548 if (n_element) {
1549 write_output_buffer(This->buffer, element, n_element);
1550 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1553 if (n_attr) {
1554 write_output_buffer(This->buffer, attr, n_attr);
1555 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1558 if (n_type) {
1559 write_output_buffer(This->buffer, type, n_type);
1560 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1563 if (n_default) {
1564 write_output_buffer(This->buffer, Default, n_default);
1565 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1568 if (n_value)
1569 write_output_buffer_quoted(This->buffer, value, n_value);
1571 write_output_buffer(This->buffer, closetagW, sizeof(closetagW)/sizeof(WCHAR));
1573 return S_OK;
1576 static HRESULT WINAPI SAXDeclHandler_internalEntityDecl(ISAXDeclHandler *iface,
1577 const WCHAR *name, int n_name, const WCHAR *value, int n_value)
1579 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1581 TRACE("(%p)->(%s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1582 debugstr_wn(value, n_value), n_value);
1584 if (!name || !value) return E_INVALIDARG;
1586 write_output_buffer(This->buffer, entityW, sizeof(entityW)/sizeof(WCHAR));
1587 if (n_name) {
1588 write_output_buffer(This->buffer, name, n_name);
1589 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1592 if (n_value)
1593 write_output_buffer_quoted(This->buffer, value, n_value);
1595 write_output_buffer(This->buffer, closetagW, sizeof(closetagW)/sizeof(WCHAR));
1597 return S_OK;
1600 static HRESULT WINAPI SAXDeclHandler_externalEntityDecl(ISAXDeclHandler *iface,
1601 const WCHAR *name, int n_name, const WCHAR *publicId, int n_publicId,
1602 const WCHAR *systemId, int n_systemId)
1604 static const WCHAR publicW[] = {'P','U','B','L','I','C',' '};
1605 static const WCHAR systemW[] = {'S','Y','S','T','E','M',' '};
1606 mxwriter *This = impl_from_ISAXDeclHandler( iface );
1608 TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name,
1609 debugstr_wn(publicId, n_publicId), n_publicId, debugstr_wn(systemId, n_systemId), n_systemId);
1611 if (!name) return E_INVALIDARG;
1612 if (publicId && !systemId) return E_INVALIDARG;
1613 if (!publicId && !systemId) return E_INVALIDARG;
1615 write_output_buffer(This->buffer, entityW, sizeof(entityW)/sizeof(WCHAR));
1616 if (n_name) {
1617 write_output_buffer(This->buffer, name, n_name);
1618 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1621 if (publicId)
1623 write_output_buffer(This->buffer, publicW, sizeof(publicW)/sizeof(WCHAR));
1624 write_output_buffer_quoted(This->buffer, publicId, n_publicId);
1625 write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR));
1626 write_output_buffer_quoted(This->buffer, systemId, n_systemId);
1628 else
1630 write_output_buffer(This->buffer, systemW, sizeof(systemW)/sizeof(WCHAR));
1631 write_output_buffer_quoted(This->buffer, systemId, n_systemId);
1634 write_output_buffer(This->buffer, closetagW, sizeof(closetagW)/sizeof(WCHAR));
1636 return S_OK;
1639 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = {
1640 SAXDeclHandler_QueryInterface,
1641 SAXDeclHandler_AddRef,
1642 SAXDeclHandler_Release,
1643 SAXDeclHandler_elementDecl,
1644 SAXDeclHandler_attributeDecl,
1645 SAXDeclHandler_internalEntityDecl,
1646 SAXDeclHandler_externalEntityDecl
1649 static const tid_t mxwriter_iface_tids[] = {
1650 IMXWriter_tid,
1654 static dispex_static_data_t mxwriter_dispex = {
1655 NULL,
1656 IMXWriter_tid,
1657 NULL,
1658 mxwriter_iface_tids
1661 HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
1663 static const WCHAR version10W[] = {'1','.','0',0};
1664 mxwriter *This;
1665 HRESULT hr;
1667 TRACE("(%p, %p)\n", outer, ppObj);
1669 if (outer) FIXME("support aggregation, outer\n");
1671 This = heap_alloc( sizeof (*This) );
1672 if(!This)
1673 return E_OUTOFMEMORY;
1675 This->IMXWriter_iface.lpVtbl = &MXWriterVtbl;
1676 This->ISAXContentHandler_iface.lpVtbl = &SAXContentHandlerVtbl;
1677 This->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1678 This->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1679 This->ref = 1;
1680 This->class_version = version;
1682 This->props[MXWriter_BOM] = VARIANT_TRUE;
1683 This->props[MXWriter_DisableEscaping] = VARIANT_FALSE;
1684 This->props[MXWriter_Indent] = VARIANT_FALSE;
1685 This->props[MXWriter_OmitXmlDecl] = VARIANT_FALSE;
1686 This->props[MXWriter_Standalone] = VARIANT_FALSE;
1687 This->prop_changed = FALSE;
1688 This->encoding = SysAllocString(utf16W);
1689 This->version = SysAllocString(version10W);
1690 This->xml_enc = XmlEncoding_UTF16;
1692 This->element = NULL;
1693 This->cdata = FALSE;
1694 This->indent = 0;
1695 This->text = FALSE;
1696 This->newline = FALSE;
1698 This->dest = NULL;
1699 This->dest_written = 0;
1701 hr = alloc_output_buffer(This->xml_enc, &This->buffer);
1702 if (hr != S_OK) {
1703 SysFreeString(This->encoding);
1704 SysFreeString(This->version);
1705 heap_free(This);
1706 return hr;
1709 init_dispex(&This->dispex, (IUnknown*)&This->IMXWriter_iface, &mxwriter_dispex);
1711 *ppObj = &This->IMXWriter_iface;
1713 TRACE("returning iface %p\n", *ppObj);
1715 return S_OK;
1718 static HRESULT WINAPI MXAttributes_QueryInterface(IMXAttributes *iface, REFIID riid, void **ppObj)
1720 mxattributes *This = impl_from_IMXAttributes( iface );
1722 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppObj);
1724 *ppObj = NULL;
1726 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
1727 IsEqualGUID( riid, &IID_IDispatch ) ||
1728 IsEqualGUID( riid, &IID_IMXAttributes ))
1730 *ppObj = iface;
1732 else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
1734 *ppObj = &This->ISAXAttributes_iface;
1736 else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
1738 *ppObj = &This->IVBSAXAttributes_iface;
1740 else if (dispex_query_interface(&This->dispex, riid, ppObj))
1742 return *ppObj ? S_OK : E_NOINTERFACE;
1744 else
1746 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1747 return E_NOINTERFACE;
1750 IMXAttributes_AddRef( iface );
1752 return S_OK;
1755 static ULONG WINAPI MXAttributes_AddRef(IMXAttributes *iface)
1757 mxattributes *This = impl_from_IMXAttributes( iface );
1758 ULONG ref = InterlockedIncrement( &This->ref );
1759 TRACE("(%p)->(%d)\n", This, ref );
1760 return ref;
1763 static ULONG WINAPI MXAttributes_Release(IMXAttributes *iface)
1765 mxattributes *This = impl_from_IMXAttributes( iface );
1766 LONG ref = InterlockedDecrement( &This->ref );
1768 TRACE("(%p)->(%d)\n", This, ref);
1770 if (ref == 0)
1772 int i;
1774 for (i = 0; i < This->length; i++)
1776 SysFreeString(This->attr[i].qname);
1777 SysFreeString(This->attr[i].local);
1778 SysFreeString(This->attr[i].uri);
1779 SysFreeString(This->attr[i].type);
1780 SysFreeString(This->attr[i].value);
1783 release_dispex(&This->dispex);
1784 heap_free(This->attr);
1785 heap_free(This);
1788 return ref;
1791 static HRESULT WINAPI MXAttributes_GetTypeInfoCount(IMXAttributes *iface, UINT* pctinfo)
1793 mxattributes *This = impl_from_IMXAttributes( iface );
1794 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1797 static HRESULT WINAPI MXAttributes_GetTypeInfo(IMXAttributes *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1799 mxattributes *This = impl_from_IMXAttributes( iface );
1800 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1803 static HRESULT WINAPI MXAttributes_GetIDsOfNames(
1804 IMXAttributes *iface,
1805 REFIID riid,
1806 LPOLESTR* rgszNames,
1807 UINT cNames,
1808 LCID lcid,
1809 DISPID* rgDispId)
1811 mxattributes *This = impl_from_IMXAttributes( iface );
1812 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1813 riid, rgszNames, cNames, lcid, rgDispId);
1816 static HRESULT WINAPI MXAttributes_Invoke(
1817 IMXAttributes *iface,
1818 DISPID dispIdMember,
1819 REFIID riid,
1820 LCID lcid,
1821 WORD wFlags,
1822 DISPPARAMS* pDispParams,
1823 VARIANT* pVarResult,
1824 EXCEPINFO* pExcepInfo,
1825 UINT* puArgErr)
1827 mxattributes *This = impl_from_IMXAttributes( iface );
1828 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1829 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1832 static HRESULT WINAPI MXAttributes_addAttribute(IMXAttributes *iface,
1833 BSTR uri, BSTR localName, BSTR QName, BSTR type, BSTR value)
1835 mxattributes *This = impl_from_IMXAttributes( iface );
1836 mxattribute *attr;
1837 HRESULT hr;
1839 TRACE("(%p)->(%s %s %s %s %s)\n", This, debugstr_w(uri), debugstr_w(localName),
1840 debugstr_w(QName), debugstr_w(type), debugstr_w(value));
1842 if ((!uri || !localName || !QName || !type || !value) && This->class_version != MSXML6)
1843 return E_INVALIDARG;
1845 /* ensure array is large enough */
1846 hr = mxattributes_grow(This);
1847 if (hr != S_OK) return hr;
1849 attr = &This->attr[This->length];
1851 attr->qname = SysAllocString(QName);
1852 attr->local = SysAllocString(localName);
1853 attr->uri = SysAllocString(uri);
1854 attr->type = SysAllocString(type ? type : emptyW);
1855 attr->value = SysAllocString(value);
1856 This->length++;
1858 return S_OK;
1861 static HRESULT WINAPI MXAttributes_addAttributeFromIndex(IMXAttributes *iface,
1862 VARIANT atts, int index)
1864 mxattributes *This = impl_from_IMXAttributes( iface );
1865 FIXME("(%p)->(%s %d): stub\n", This, debugstr_variant(&atts), index);
1866 return E_NOTIMPL;
1869 static HRESULT WINAPI MXAttributes_clear(IMXAttributes *iface)
1871 mxattributes *This = impl_from_IMXAttributes( iface );
1872 int i;
1874 TRACE("(%p)\n", This);
1876 for (i = 0; i < This->length; i++)
1878 SysFreeString(This->attr[i].qname);
1879 SysFreeString(This->attr[i].local);
1880 SysFreeString(This->attr[i].uri);
1881 SysFreeString(This->attr[i].type);
1882 SysFreeString(This->attr[i].value);
1883 memset(&This->attr[i], 0, sizeof(mxattribute));
1886 This->length = 0;
1888 return S_OK;
1891 static mxattribute *get_attribute_byindex(mxattributes *attrs, int index)
1893 if (index < 0 || index >= attrs->length) return NULL;
1894 return &attrs->attr[index];
1897 static HRESULT WINAPI MXAttributes_removeAttribute(IMXAttributes *iface, int index)
1899 mxattributes *This = impl_from_IMXAttributes( iface );
1900 mxattribute *dst;
1902 TRACE("(%p)->(%d)\n", This, index);
1904 if (!(dst = get_attribute_byindex(This, index))) return E_INVALIDARG;
1906 /* no need to remove last attribute, just make it inaccessible */
1907 if (index + 1 == This->length)
1909 This->length--;
1910 return S_OK;
1913 memmove(dst, dst + 1, (This->length-index-1)*sizeof(*dst));
1914 This->length--;
1916 return S_OK;
1919 static HRESULT WINAPI MXAttributes_setAttribute(IMXAttributes *iface, int index,
1920 BSTR uri, BSTR localName, BSTR QName, BSTR type, BSTR value)
1922 mxattributes *This = impl_from_IMXAttributes( iface );
1923 FIXME("(%p)->(%d %s %s %s %s %s): stub\n", This, index, debugstr_w(uri),
1924 debugstr_w(localName), debugstr_w(QName), debugstr_w(type), debugstr_w(value));
1925 return E_NOTIMPL;
1928 static HRESULT WINAPI MXAttributes_setAttributes(IMXAttributes *iface, VARIANT atts)
1930 mxattributes *This = impl_from_IMXAttributes( iface );
1931 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&atts));
1932 return E_NOTIMPL;
1935 static HRESULT WINAPI MXAttributes_setLocalName(IMXAttributes *iface, int index,
1936 BSTR localName)
1938 mxattributes *This = impl_from_IMXAttributes( iface );
1939 mxattribute *attr;
1941 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(localName));
1943 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
1945 SysFreeString(attr->local);
1946 attr->local = SysAllocString(localName);
1948 return S_OK;
1951 static HRESULT WINAPI MXAttributes_setQName(IMXAttributes *iface, int index, BSTR QName)
1953 mxattributes *This = impl_from_IMXAttributes( iface );
1954 mxattribute *attr;
1956 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(QName));
1958 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
1960 SysFreeString(attr->qname);
1961 attr->qname = SysAllocString(QName);
1963 return S_OK;
1966 static HRESULT WINAPI MXAttributes_setURI(IMXAttributes *iface, int index, BSTR uri)
1968 mxattributes *This = impl_from_IMXAttributes( iface );
1969 mxattribute *attr;
1971 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(uri));
1973 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
1975 SysFreeString(attr->uri);
1976 attr->uri = SysAllocString(uri);
1978 return S_OK;
1981 static HRESULT WINAPI MXAttributes_setValue(IMXAttributes *iface, int index, BSTR value)
1983 mxattributes *This = impl_from_IMXAttributes( iface );
1984 mxattribute *attr;
1986 TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(value));
1988 if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG;
1990 SysFreeString(attr->value);
1991 attr->value = SysAllocString(value);
1993 return S_OK;
1996 static const IMXAttributesVtbl MXAttributesVtbl = {
1997 MXAttributes_QueryInterface,
1998 MXAttributes_AddRef,
1999 MXAttributes_Release,
2000 MXAttributes_GetTypeInfoCount,
2001 MXAttributes_GetTypeInfo,
2002 MXAttributes_GetIDsOfNames,
2003 MXAttributes_Invoke,
2004 MXAttributes_addAttribute,
2005 MXAttributes_addAttributeFromIndex,
2006 MXAttributes_clear,
2007 MXAttributes_removeAttribute,
2008 MXAttributes_setAttribute,
2009 MXAttributes_setAttributes,
2010 MXAttributes_setLocalName,
2011 MXAttributes_setQName,
2012 MXAttributes_setURI,
2013 MXAttributes_setValue
2016 static HRESULT WINAPI SAXAttributes_QueryInterface(ISAXAttributes *iface, REFIID riid, void **ppObj)
2018 mxattributes *This = impl_from_ISAXAttributes( iface );
2019 return IMXAttributes_QueryInterface(&This->IMXAttributes_iface, riid, ppObj);
2022 static ULONG WINAPI SAXAttributes_AddRef(ISAXAttributes *iface)
2024 mxattributes *This = impl_from_ISAXAttributes( iface );
2025 return IMXAttributes_AddRef(&This->IMXAttributes_iface);
2028 static ULONG WINAPI SAXAttributes_Release(ISAXAttributes *iface)
2030 mxattributes *This = impl_from_ISAXAttributes( iface );
2031 return IMXAttributes_Release(&This->IMXAttributes_iface);
2034 static HRESULT WINAPI SAXAttributes_getLength(ISAXAttributes *iface, int *length)
2036 mxattributes *This = impl_from_ISAXAttributes( iface );
2037 TRACE("(%p)->(%p)\n", This, length);
2039 if (!length && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
2040 return E_POINTER;
2042 *length = This->length;
2044 return S_OK;
2047 static HRESULT WINAPI SAXAttributes_getURI(ISAXAttributes *iface, int index, const WCHAR **uri,
2048 int *len)
2050 mxattributes *This = impl_from_ISAXAttributes( iface );
2052 TRACE("(%p)->(%d %p %p)\n", This, index, uri, len);
2054 if (index >= This->length || index < 0) return E_INVALIDARG;
2055 if (!uri || !len) return E_POINTER;
2057 *len = SysStringLen(This->attr[index].uri);
2058 *uri = This->attr[index].uri;
2060 return S_OK;
2063 static HRESULT WINAPI SAXAttributes_getLocalName(ISAXAttributes *iface, int index, const WCHAR **name,
2064 int *len)
2066 mxattributes *This = impl_from_ISAXAttributes( iface );
2068 TRACE("(%p)->(%d %p %p)\n", This, index, name, len);
2070 if (index >= This->length || index < 0) return E_INVALIDARG;
2071 if (!name || !len) return E_POINTER;
2073 *len = SysStringLen(This->attr[index].local);
2074 *name = This->attr[index].local;
2076 return S_OK;
2079 static HRESULT WINAPI SAXAttributes_getQName(ISAXAttributes *iface, int index, const WCHAR **qname, int *length)
2081 mxattributes *This = impl_from_ISAXAttributes( iface );
2083 TRACE("(%p)->(%d %p %p)\n", This, index, qname, length);
2085 if (index >= This->length) return E_INVALIDARG;
2086 if (!qname || !length) return E_POINTER;
2088 *qname = This->attr[index].qname;
2089 *length = SysStringLen(This->attr[index].qname);
2091 return S_OK;
2094 static HRESULT WINAPI SAXAttributes_getName(ISAXAttributes *iface, int index, const WCHAR **uri, int *uri_len,
2095 const WCHAR **local, int *local_len, const WCHAR **qname, int *qname_len)
2097 mxattributes *This = impl_from_ISAXAttributes( iface );
2099 TRACE("(%p)->(%d %p %p %p %p %p %p)\n", This, index, uri, uri_len, local, local_len, qname, qname_len);
2101 if (index >= This->length || index < 0)
2102 return E_INVALIDARG;
2104 if (!uri || !uri_len || !local || !local_len || !qname || !qname_len)
2105 return E_POINTER;
2107 *uri_len = SysStringLen(This->attr[index].uri);
2108 *uri = This->attr[index].uri;
2110 *local_len = SysStringLen(This->attr[index].local);
2111 *local = This->attr[index].local;
2113 *qname_len = SysStringLen(This->attr[index].qname);
2114 *qname = This->attr[index].qname;
2116 TRACE("(%s, %s, %s)\n", debugstr_w(*uri), debugstr_w(*local), debugstr_w(*qname));
2118 return S_OK;
2121 static HRESULT WINAPI SAXAttributes_getIndexFromName(ISAXAttributes *iface, const WCHAR *uri, int uri_len,
2122 const WCHAR *name, int len, int *index)
2124 mxattributes *This = impl_from_ISAXAttributes( iface );
2125 int i;
2127 TRACE("(%p)->(%s:%d %s:%d %p)\n", This, debugstr_wn(uri, uri_len), uri_len,
2128 debugstr_wn(name, len), len, index);
2130 if (!index && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
2131 return E_POINTER;
2133 if (!uri || !name || !index) return E_INVALIDARG;
2135 for (i = 0; i < This->length; i++)
2137 if (uri_len != SysStringLen(This->attr[i].uri)) continue;
2138 if (strncmpW(uri, This->attr[i].uri, uri_len)) continue;
2140 if (len != SysStringLen(This->attr[i].local)) continue;
2141 if (strncmpW(name, This->attr[i].local, len)) continue;
2143 *index = i;
2144 return S_OK;
2147 return E_INVALIDARG;
2150 static HRESULT WINAPI SAXAttributes_getIndexFromQName(ISAXAttributes *iface, const WCHAR *qname,
2151 int len, int *index)
2153 mxattributes *This = impl_from_ISAXAttributes( iface );
2154 int i;
2156 TRACE("(%p)->(%s:%d %p)\n", This, debugstr_wn(qname, len), len, index);
2158 if (!index && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
2159 return E_POINTER;
2161 if (!qname || !index || !len) return E_INVALIDARG;
2163 for (i = 0; i < This->length; i++)
2165 if (len != SysStringLen(This->attr[i].qname)) continue;
2166 if (strncmpW(qname, This->attr[i].qname, len)) continue;
2168 *index = i;
2169 return S_OK;
2172 return E_INVALIDARG;
2175 static HRESULT WINAPI SAXAttributes_getType(ISAXAttributes *iface, int index, const WCHAR **type,
2176 int *len)
2178 mxattributes *This = impl_from_ISAXAttributes( iface );
2180 TRACE("(%p)->(%d %p %p)\n", This, index, type, len);
2182 if (index >= This->length) return E_INVALIDARG;
2184 if ((!type || !len) && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
2185 return E_POINTER;
2187 *type = This->attr[index].type;
2188 *len = SysStringLen(This->attr[index].type);
2190 return S_OK;
2193 static HRESULT WINAPI SAXAttributes_getTypeFromName(ISAXAttributes *iface, const WCHAR * pUri, int nUri,
2194 const WCHAR * pLocalName, int nLocalName, const WCHAR ** pType, int * nType)
2196 mxattributes *This = impl_from_ISAXAttributes( iface );
2197 FIXME("(%p)->(%s:%d %s:%d %p %p): stub\n", This, debugstr_wn(pUri, nUri), nUri,
2198 debugstr_wn(pLocalName, nLocalName), nLocalName, pType, nType);
2199 return E_NOTIMPL;
2202 static HRESULT WINAPI SAXAttributes_getTypeFromQName(ISAXAttributes *iface, const WCHAR * pQName,
2203 int nQName, const WCHAR ** pType, int * nType)
2205 mxattributes *This = impl_from_ISAXAttributes( iface );
2206 FIXME("(%p)->(%s:%d %p %p): stub\n", This, debugstr_wn(pQName, nQName), nQName, pType, nType);
2207 return E_NOTIMPL;
2210 static HRESULT WINAPI SAXAttributes_getValue(ISAXAttributes *iface, int index, const WCHAR **value,
2211 int *len)
2213 mxattributes *This = impl_from_ISAXAttributes( iface );
2215 TRACE("(%p)->(%d %p %p)\n", This, index, value, len);
2217 if (index >= This->length) return E_INVALIDARG;
2219 if ((!value || !len) && (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3))
2220 return E_POINTER;
2222 *value = This->attr[index].value;
2223 *len = SysStringLen(This->attr[index].value);
2225 return S_OK;
2228 static HRESULT WINAPI SAXAttributes_getValueFromName(ISAXAttributes *iface, const WCHAR *uri,
2229 int uri_len, const WCHAR *name, int name_len, const WCHAR **value, int *value_len)
2231 mxattributes *This = impl_from_ISAXAttributes( iface );
2232 HRESULT hr;
2233 int index;
2235 TRACE("(%p)->(%s:%d %s:%d %p %p)\n", This, debugstr_wn(uri, uri_len), uri_len,
2236 debugstr_wn(name, name_len), name_len, value, value_len);
2238 if (!uri || !name || !value || !value_len)
2239 return (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3) ? E_POINTER : E_INVALIDARG;
2241 hr = ISAXAttributes_getIndexFromName(iface, uri, uri_len, name, name_len, &index);
2242 if (hr == S_OK)
2243 hr = ISAXAttributes_getValue(iface, index, value, value_len);
2245 return hr;
2248 static HRESULT WINAPI SAXAttributes_getValueFromQName(ISAXAttributes *iface, const WCHAR *qname,
2249 int qname_len, const WCHAR **value, int *value_len)
2251 mxattributes *This = impl_from_ISAXAttributes( iface );
2252 HRESULT hr;
2253 int index;
2255 TRACE("(%p)->(%s:%d %p %p)\n", This, debugstr_wn(qname, qname_len), qname_len, value, value_len);
2257 if (!qname || !value || !value_len)
2258 return (This->class_version == MSXML_DEFAULT || This->class_version == MSXML3) ? E_POINTER : E_INVALIDARG;
2260 hr = ISAXAttributes_getIndexFromQName(iface, qname, qname_len, &index);
2261 if (hr == S_OK)
2262 hr = ISAXAttributes_getValue(iface, index, value, value_len);
2264 return hr;
2267 static const ISAXAttributesVtbl SAXAttributesVtbl = {
2268 SAXAttributes_QueryInterface,
2269 SAXAttributes_AddRef,
2270 SAXAttributes_Release,
2271 SAXAttributes_getLength,
2272 SAXAttributes_getURI,
2273 SAXAttributes_getLocalName,
2274 SAXAttributes_getQName,
2275 SAXAttributes_getName,
2276 SAXAttributes_getIndexFromName,
2277 SAXAttributes_getIndexFromQName,
2278 SAXAttributes_getType,
2279 SAXAttributes_getTypeFromName,
2280 SAXAttributes_getTypeFromQName,
2281 SAXAttributes_getValue,
2282 SAXAttributes_getValueFromName,
2283 SAXAttributes_getValueFromQName
2286 static HRESULT WINAPI VBSAXAttributes_QueryInterface(
2287 IVBSAXAttributes* iface,
2288 REFIID riid,
2289 void **ppvObject)
2291 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2292 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
2293 return ISAXAttributes_QueryInterface(&This->ISAXAttributes_iface, riid, ppvObject);
2296 static ULONG WINAPI VBSAXAttributes_AddRef(IVBSAXAttributes* iface)
2298 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2299 return ISAXAttributes_AddRef(&This->ISAXAttributes_iface);
2302 static ULONG WINAPI VBSAXAttributes_Release(IVBSAXAttributes* iface)
2304 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2305 return ISAXAttributes_Release(&This->ISAXAttributes_iface);
2308 static HRESULT WINAPI VBSAXAttributes_GetTypeInfoCount( IVBSAXAttributes *iface, UINT* pctinfo )
2310 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2312 TRACE("(%p)->(%p)\n", This, pctinfo);
2314 *pctinfo = 1;
2316 return S_OK;
2319 static HRESULT WINAPI VBSAXAttributes_GetTypeInfo(
2320 IVBSAXAttributes *iface,
2321 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
2323 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2324 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2325 return get_typeinfo(IVBSAXAttributes_tid, ppTInfo);
2328 static HRESULT WINAPI VBSAXAttributes_GetIDsOfNames(
2329 IVBSAXAttributes *iface,
2330 REFIID riid,
2331 LPOLESTR* rgszNames,
2332 UINT cNames,
2333 LCID lcid,
2334 DISPID* rgDispId)
2336 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2337 ITypeInfo *typeinfo;
2338 HRESULT hr;
2340 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
2341 lcid, rgDispId);
2343 if(!rgszNames || cNames == 0 || !rgDispId)
2344 return E_INVALIDARG;
2346 hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
2347 if(SUCCEEDED(hr))
2349 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2350 ITypeInfo_Release(typeinfo);
2353 return hr;
2356 static HRESULT WINAPI VBSAXAttributes_Invoke(
2357 IVBSAXAttributes *iface,
2358 DISPID dispIdMember,
2359 REFIID riid,
2360 LCID lcid,
2361 WORD wFlags,
2362 DISPPARAMS* pDispParams,
2363 VARIANT* pVarResult,
2364 EXCEPINFO* pExcepInfo,
2365 UINT* puArgErr)
2367 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2368 ITypeInfo *typeinfo;
2369 HRESULT hr;
2371 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2372 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2374 hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
2375 if(SUCCEEDED(hr))
2377 hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXAttributes_iface, dispIdMember, wFlags,
2378 pDispParams, pVarResult, pExcepInfo, puArgErr);
2379 ITypeInfo_Release(typeinfo);
2382 return hr;
2385 static HRESULT WINAPI VBSAXAttributes_get_length(IVBSAXAttributes* iface, int *len)
2387 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2388 return ISAXAttributes_getLength(&This->ISAXAttributes_iface, len);
2391 static HRESULT WINAPI VBSAXAttributes_getURI(IVBSAXAttributes* iface, int index, BSTR *uri)
2393 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2394 int len;
2396 return ISAXAttributes_getURI(&This->ISAXAttributes_iface, index, (const WCHAR**)uri, &len);
2399 static HRESULT WINAPI VBSAXAttributes_getLocalName(IVBSAXAttributes* iface, int index, BSTR *name)
2401 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2402 int len;
2404 return ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, index, (const WCHAR**)name, &len);
2407 static HRESULT WINAPI VBSAXAttributes_getQName(IVBSAXAttributes* iface, int index, BSTR *qname)
2409 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2410 int len;
2412 return ISAXAttributes_getQName(&This->ISAXAttributes_iface, index, (const WCHAR**)qname, &len);
2415 static HRESULT WINAPI VBSAXAttributes_getIndexFromName(IVBSAXAttributes* iface, BSTR uri, BSTR name, int *index)
2417 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2418 return ISAXAttributes_getIndexFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
2419 name, SysStringLen(name), index);
2422 static HRESULT WINAPI VBSAXAttributes_getIndexFromQName(IVBSAXAttributes* iface, BSTR qname, int *index)
2424 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2425 return ISAXAttributes_getIndexFromQName(&This->ISAXAttributes_iface, qname,
2426 SysStringLen(qname), index);
2429 static HRESULT WINAPI VBSAXAttributes_getType(IVBSAXAttributes* iface, int index,BSTR *type)
2431 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2432 int len;
2434 return ISAXAttributes_getType(&This->ISAXAttributes_iface, index, (const WCHAR**)type, &len);
2437 static HRESULT WINAPI VBSAXAttributes_getTypeFromName(IVBSAXAttributes* iface, BSTR uri,
2438 BSTR name, BSTR *type)
2440 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2441 int len;
2443 return ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
2444 name, SysStringLen(name), (const WCHAR**)type, &len);
2447 static HRESULT WINAPI VBSAXAttributes_getTypeFromQName(IVBSAXAttributes* iface, BSTR qname, BSTR *type)
2449 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2450 int len;
2452 return ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
2453 (const WCHAR**)type, &len);
2456 static HRESULT WINAPI VBSAXAttributes_getValue(IVBSAXAttributes* iface, int index, BSTR *value)
2458 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2459 int len;
2461 return ISAXAttributes_getValue(&This->ISAXAttributes_iface, index, (const WCHAR**)value, &len);
2464 static HRESULT WINAPI VBSAXAttributes_getValueFromName(IVBSAXAttributes* iface, BSTR uri, BSTR name,
2465 BSTR *value)
2467 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2468 int len;
2470 return ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
2471 name, SysStringLen(name), (const WCHAR**)value, &len);
2474 static HRESULT WINAPI VBSAXAttributes_getValueFromQName(IVBSAXAttributes* iface, BSTR qname, BSTR *value)
2476 mxattributes *This = impl_from_IVBSAXAttributes( iface );
2477 int len;
2479 return ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
2480 (const WCHAR**)value, &len);
2483 static const struct IVBSAXAttributesVtbl VBSAXAttributesVtbl =
2485 VBSAXAttributes_QueryInterface,
2486 VBSAXAttributes_AddRef,
2487 VBSAXAttributes_Release,
2488 VBSAXAttributes_GetTypeInfoCount,
2489 VBSAXAttributes_GetTypeInfo,
2490 VBSAXAttributes_GetIDsOfNames,
2491 VBSAXAttributes_Invoke,
2492 VBSAXAttributes_get_length,
2493 VBSAXAttributes_getURI,
2494 VBSAXAttributes_getLocalName,
2495 VBSAXAttributes_getQName,
2496 VBSAXAttributes_getIndexFromName,
2497 VBSAXAttributes_getIndexFromQName,
2498 VBSAXAttributes_getType,
2499 VBSAXAttributes_getTypeFromName,
2500 VBSAXAttributes_getTypeFromQName,
2501 VBSAXAttributes_getValue,
2502 VBSAXAttributes_getValueFromName,
2503 VBSAXAttributes_getValueFromQName
2506 static const tid_t mxattrs_iface_tids[] = {
2507 IMXAttributes_tid,
2511 static dispex_static_data_t mxattrs_dispex = {
2512 NULL,
2513 IMXAttributes_tid,
2514 NULL,
2515 mxattrs_iface_tids
2518 HRESULT SAXAttributes_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
2520 static const int default_count = 10;
2521 mxattributes *This;
2523 TRACE("(%p, %p)\n", outer, ppObj);
2525 This = heap_alloc( sizeof (*This) );
2526 if( !This )
2527 return E_OUTOFMEMORY;
2529 This->IMXAttributes_iface.lpVtbl = &MXAttributesVtbl;
2530 This->ISAXAttributes_iface.lpVtbl = &SAXAttributesVtbl;
2531 This->IVBSAXAttributes_iface.lpVtbl = &VBSAXAttributesVtbl;
2532 This->ref = 1;
2534 This->class_version = version;
2536 This->attr = heap_alloc(default_count*sizeof(mxattribute));
2537 This->length = 0;
2538 This->allocated = default_count;
2540 *ppObj = &This->IMXAttributes_iface;
2542 init_dispex(&This->dispex, (IUnknown*)&This->IMXAttributes_iface, &mxattrs_dispex);
2544 TRACE("returning iface %p\n", *ppObj);
2546 return S_OK;