msxml3/tests: Null-terminate a string before A->W conversion (Valgrind).
[wine/wine-gecko.git] / dlls / msxml3 / tests / saxreader.c
blob646984fa11d7ec894aa1fdd0f9f370d22352086d
1 /*
2 * SAXReader/MXWriter tests
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
6 * Copyright 2012 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define CONST_VTABLE
26 #include <stdio.h>
27 #include <assert.h>
29 #include "windows.h"
30 #include "ole2.h"
31 #include "msxml2.h"
32 #include "msxml2did.h"
33 #include "ocidl.h"
34 #include "dispex.h"
36 #include "wine/test.h"
38 static const WCHAR emptyW[] = {0};
40 #define EXPECT_HR(hr,hr_exp) \
41 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
43 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
44 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
46 ULONG rc = IUnknown_AddRef(obj);
47 IUnknown_Release(obj);
48 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
51 static LONG get_refcount(void *iface)
53 IUnknown *unk = iface;
54 LONG ref;
56 ref = IUnknown_AddRef(unk);
57 IUnknown_Release(unk);
58 return ref-1;
61 struct msxmlsupported_data_t
63 const GUID *clsid;
64 const char *name;
65 BOOL supported;
68 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
70 while (table->clsid)
72 if (table->clsid == clsid) return table->supported;
73 table++;
75 return FALSE;
78 static BSTR alloc_str_from_narrow(const char *str)
80 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
81 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
82 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
83 return ret;
86 static BSTR alloced_bstrs[512];
87 static int alloced_bstrs_count;
89 static BSTR _bstr_(const char *str)
91 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
92 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
93 return alloced_bstrs[alloced_bstrs_count++];
96 static void free_bstrs(void)
98 int i;
99 for (i = 0; i < alloced_bstrs_count; i++)
100 SysFreeString(alloced_bstrs[i]);
101 alloced_bstrs_count = 0;
104 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, BOOL todo, int *failcount)
106 int len, lenexp, cmp;
107 WCHAR buf[1024];
109 len = SysStringLen(str);
111 if (!expected) {
112 if (str && todo)
114 (*failcount)++;
115 todo_wine
116 ok_(file, line) (!str, "got %p, expected null str\n", str);
118 else
119 ok_(file, line) (!str, "got %p, expected null str\n", str);
121 if (len && todo)
123 (*failcount)++;
124 todo_wine
125 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
127 else
128 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
129 return;
132 lenexp = strlen(expected);
133 if (lenexp != len && todo)
135 (*failcount)++;
136 todo_wine
137 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
139 else
140 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
142 /* exit earlier on length mismatch */
143 if (lenexp != len) return;
145 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
147 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
148 if (cmp && todo)
150 (*failcount)++;
151 todo_wine
152 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
153 wine_dbgstr_wn(str, len), expected);
155 else
156 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
157 wine_dbgstr_wn(str, len), expected);
160 typedef enum _CH {
161 CH_ENDTEST,
162 CH_PUTDOCUMENTLOCATOR,
163 CH_STARTDOCUMENT,
164 CH_ENDDOCUMENT,
165 CH_STARTPREFIXMAPPING,
166 CH_ENDPREFIXMAPPING,
167 CH_STARTELEMENT,
168 CH_ENDELEMENT,
169 CH_CHARACTERS,
170 CH_IGNORABLEWHITESPACE,
171 CH_PROCESSINGINSTRUCTION,
172 CH_SKIPPEDENTITY,
173 LH_STARTCDATA,
174 LH_ENDCDATA,
175 EH_ERROR,
176 EH_FATALERROR,
177 EH_IGNORABLEWARNING,
178 EVENT_LAST
179 } CH;
181 static const char *event_names[EVENT_LAST] = {
182 "endtest",
183 "putDocumentLocator",
184 "startDocument",
185 "endDocument",
186 "startPrefixMapping",
187 "endPrefixMapping",
188 "startElement",
189 "endElement",
190 "characters",
191 "ignorableWhitespace",
192 "processingInstruction",
193 "skippedEntity",
194 "startCDATA",
195 "endCDATA",
196 "error",
197 "fatalError",
198 "ignorableWarning"
201 struct attribute_entry {
202 const char *uri;
203 const char *local;
204 const char *qname;
205 const char *value;
207 /* used for actual call data only, null for expected call data */
208 BSTR uriW;
209 BSTR localW;
210 BSTR qnameW;
211 BSTR valueW;
214 struct call_entry {
215 CH id;
216 int line;
217 int column;
218 HRESULT ret;
219 const char *arg1;
220 const char *arg2;
221 const char *arg3;
223 /* allocated once at startElement callback */
224 struct attribute_entry *attributes;
225 int attr_count;
227 /* used for actual call data only, null for expected call data */
228 BSTR arg1W;
229 BSTR arg2W;
230 BSTR arg3W;
233 struct call_sequence
235 int count;
236 int size;
237 struct call_entry *sequence;
240 #define CONTENT_HANDLER_INDEX 0
241 #define NUM_CALL_SEQUENCES 1
242 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
244 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
246 memset(call, 0, sizeof(*call));
247 ISAXLocator_getLineNumber(locator, &call->line);
248 ISAXLocator_getColumnNumber(locator, &call->column);
251 static void add_call(struct call_sequence **seq, int sequence_index,
252 const struct call_entry *call)
254 struct call_sequence *call_seq = seq[sequence_index];
256 if (!call_seq->sequence)
258 call_seq->size = 10;
259 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
260 call_seq->size * sizeof (struct call_entry));
263 if (call_seq->count == call_seq->size)
265 call_seq->size *= 2;
266 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
267 call_seq->sequence,
268 call_seq->size * sizeof (struct call_entry));
271 assert(call_seq->sequence);
273 call_seq->sequence[call_seq->count].id = call->id;
274 call_seq->sequence[call_seq->count].line = call->line;
275 call_seq->sequence[call_seq->count].column = call->column;
276 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
277 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
278 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
279 call_seq->sequence[call_seq->count].ret = call->ret;
280 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
281 call_seq->sequence[call_seq->count].attributes = call->attributes;
283 call_seq->count++;
286 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
288 int i;
290 struct call_sequence *call_seq = seg[sequence_index];
292 for (i = 0; i < call_seq->count; i++)
294 int j;
296 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
298 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
299 SysFreeString(call_seq->sequence[i].attributes[j].localW);
300 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
303 SysFreeString(call_seq->sequence[i].arg1W);
304 SysFreeString(call_seq->sequence[i].arg2W);
305 SysFreeString(call_seq->sequence[i].arg3W);
308 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
309 call_seq->sequence = NULL;
310 call_seq->count = call_seq->size = 0;
313 static inline void flush_sequences(struct call_sequence **seq, int n)
315 int i;
316 for (i = 0; i < n; i++)
317 flush_sequence(seq, i);
320 static const char *get_event_name(CH event)
322 return event_names[event];
325 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
326 BOOL todo, const char *file, int line, int *failcount)
328 int i, lenexp = 0;
330 /* attribute count is not stored for expected data */
331 if (expected->attributes)
333 struct attribute_entry *ptr = expected->attributes;
334 while (ptr->uri) { lenexp++; ptr++; };
337 /* check count first and exit earlier */
338 if (actual->attr_count != lenexp && todo)
340 (*failcount)++;
341 todo_wine
342 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
343 context, get_event_name(actual->id), lenexp, actual->attr_count);
345 else
346 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
347 context, get_event_name(actual->id), lenexp, actual->attr_count);
349 if (actual->attr_count != lenexp) return;
351 /* now compare all attributes strings */
352 for (i = 0; i < actual->attr_count; i++)
354 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
355 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
356 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
357 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
361 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
362 const struct call_entry *expected, const char *context, BOOL todo,
363 const char *file, int line)
365 struct call_sequence *call_seq = seq[sequence_index];
366 static const struct call_entry end_of_sequence = { CH_ENDTEST };
367 const struct call_entry *actual, *sequence;
368 int failcount = 0;
370 add_call(seq, sequence_index, &end_of_sequence);
372 sequence = call_seq->sequence;
373 actual = sequence;
375 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
377 if (expected->id == actual->id)
379 if (expected->line != -1)
381 /* always test position data */
382 if (expected->line != actual->line && todo)
384 todo_wine
386 failcount++;
387 ok_(file, line) (FALSE,
388 "%s: in event %s expecting line %d got %d\n",
389 context, get_event_name(actual->id), expected->line, actual->line);
392 else
394 ok_(file, line) (expected->line == actual->line,
395 "%s: in event %s expecting line %d got %d\n",
396 context, get_event_name(actual->id), expected->line, actual->line);
401 if (expected->column != -1)
403 if (expected->column != actual->column && todo)
405 todo_wine
407 failcount++;
408 ok_(file, line) (FALSE,
409 "%s: in event %s expecting column %d got %d\n",
410 context, get_event_name(actual->id), expected->column, actual->column);
413 else
415 ok_(file, line) (expected->column == actual->column,
416 "%s: in event %s expecting column %d got %d\n",
417 context, get_event_name(actual->id), expected->column, actual->column);
421 switch (actual->id)
423 case CH_PUTDOCUMENTLOCATOR:
424 case CH_STARTDOCUMENT:
425 case CH_ENDDOCUMENT:
426 case LH_STARTCDATA:
427 case LH_ENDCDATA:
428 break;
429 case CH_STARTPREFIXMAPPING:
430 /* prefix, uri */
431 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
432 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
433 break;
434 case CH_ENDPREFIXMAPPING:
435 /* prefix */
436 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
437 break;
438 case CH_STARTELEMENT:
439 /* compare attributes */
440 compare_attributes(actual, expected, context, todo, file, line, &failcount);
441 /* fallthrough */
442 case CH_ENDELEMENT:
443 /* uri, localname, qname */
444 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
445 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
446 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
447 break;
448 case CH_CHARACTERS:
449 case CH_IGNORABLEWHITESPACE:
450 /* char data */
451 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
452 break;
453 case CH_PROCESSINGINSTRUCTION:
454 /* target, data */
455 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
456 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
457 break;
458 case CH_SKIPPEDENTITY:
459 /* name */
460 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
461 break;
462 case EH_FATALERROR:
463 /* test return value only */
464 if (expected->ret != actual->ret && todo)
466 failcount++;
467 ok_(file, line) (FALSE,
468 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
469 context, get_event_name(actual->id), expected->ret, actual->ret);
471 else
472 ok_(file, line) (expected->ret == actual->ret,
473 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
474 context, get_event_name(actual->id), expected->ret, actual->ret);
475 break;
476 case EH_ERROR:
477 case EH_IGNORABLEWARNING:
478 default:
479 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
481 expected++;
482 actual++;
484 else if (todo)
486 failcount++;
487 todo_wine
489 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
490 context, get_event_name(expected->id), get_event_name(actual->id));
493 flush_sequence(seq, sequence_index);
494 return;
496 else
498 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
499 context, get_event_name(expected->id), get_event_name(actual->id));
500 expected++;
501 actual++;
505 if (todo)
507 todo_wine
509 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
511 failcount++;
512 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
513 context, get_event_name(expected->id), get_event_name(actual->id));
517 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
519 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
520 context, get_event_name(expected->id), get_event_name(actual->id));
523 if (todo && !failcount) /* succeeded yet marked todo */
525 todo_wine
527 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
531 flush_sequence(seq, sequence_index);
534 #define ok_sequence(seq, index, exp, contx, todo) \
535 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
537 static void init_call_sequences(struct call_sequence **seq, int n)
539 int i;
541 for (i = 0; i < n; i++)
542 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
545 static const WCHAR szSimpleXML[] = {
546 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
547 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
548 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
549 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
550 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
553 static const WCHAR carriage_ret_test[] = {
554 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
555 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
556 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
557 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
558 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
561 static const WCHAR szUtf16XML[] = {
562 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
563 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
564 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
567 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
569 static const CHAR szUtf8XML[] =
570 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
572 static const char utf8xml2[] =
573 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
575 static const char testXML[] =
576 "<?xml version=\"1.0\" ?>\n"
577 "<BankAccount>\n"
578 " <Number>1234</Number>\n"
579 " <Name>Captain Ahab</Name>\n"
580 "</BankAccount>\n";
582 static const char test_attributes[] =
583 "<?xml version=\"1.0\" ?>\n"
584 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
585 "<node1 xmlns:p=\"test\" />"
586 "</document>\n";
588 static const char test_cdata_xml[] =
589 "<?xml version=\"1.0\" ?>"
590 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
592 static const char test2_cdata_xml[] =
593 "<?xml version=\"1.0\" ?>"
594 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
596 static const char test3_cdata_xml[] =
597 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
599 static struct call_entry content_handler_test1[] = {
600 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
601 { CH_STARTDOCUMENT, 0, 0, S_OK },
602 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
603 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
604 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
605 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
606 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
607 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
608 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
609 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
610 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
611 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
612 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
613 { CH_ENDDOCUMENT, 0, 0, S_OK},
614 { CH_ENDTEST }
617 /* applies to versions 4 and 6 */
618 static struct call_entry content_handler_test1_alternate[] = {
619 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
620 { CH_STARTDOCUMENT, 1, 22, S_OK },
621 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
622 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
623 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
624 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
625 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
626 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
627 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
628 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
629 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
630 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
631 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
632 { CH_ENDDOCUMENT, 6, 0, S_OK },
633 { CH_ENDTEST }
636 static struct call_entry content_handler_test2[] = {
637 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
638 { CH_STARTDOCUMENT, 0, 0, S_OK },
639 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
640 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
641 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
642 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
643 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
644 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
645 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
646 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
647 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
648 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
649 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
650 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
651 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
652 { CH_ENDDOCUMENT, 0, 0, S_OK },
653 { CH_ENDTEST }
656 static struct call_entry content_handler_test2_alternate[] = {
657 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
658 { CH_STARTDOCUMENT, 1, 21, S_OK },
659 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
660 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
661 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
662 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
663 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
664 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
665 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
666 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
667 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
668 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
669 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
670 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
671 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
672 { CH_ENDDOCUMENT, 6, 0, S_OK },
673 { CH_ENDTEST }
676 static struct call_entry content_handler_testerror[] = {
677 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
678 { EH_FATALERROR, 0, 0, E_FAIL },
679 { CH_ENDTEST }
682 static struct call_entry content_handler_testerror_alternate[] = {
683 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
684 { EH_FATALERROR, 1, 0, E_FAIL },
685 { CH_ENDTEST }
688 static struct call_entry content_handler_test_callback_rets[] = {
689 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
690 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
691 { EH_FATALERROR, 0, 0, S_FALSE },
692 { CH_ENDTEST }
695 static struct call_entry content_handler_test_callback_rets_alt[] = {
696 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
697 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
698 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
699 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
700 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
701 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
702 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
703 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
704 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
705 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
706 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
707 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
708 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
709 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
710 { CH_ENDTEST }
713 static struct attribute_entry ch_attributes1[] = {
714 { "", "", "xmlns:test", "prefix_test" },
715 { "", "", "xmlns", "prefix" },
716 { "prefix_test", "arg1", "test:arg1", "arg1" },
717 { "", "arg2", "arg2", "arg2" },
718 { "prefix_test", "ar3", "test:ar3", "arg3" },
719 { NULL }
722 static struct attribute_entry ch_attributes2[] = {
723 { "", "", "xmlns:p", "test" },
724 { NULL }
727 static struct call_entry content_handler_test_attributes[] = {
728 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
729 { CH_STARTDOCUMENT, 0, 0, S_OK },
730 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
731 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
732 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
733 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
734 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
735 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
736 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
737 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
738 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
739 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
740 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
741 { CH_ENDDOCUMENT, 0, 0 },
742 { CH_ENDTEST }
745 static struct attribute_entry ch_attributes_alt_4[] = {
746 { "prefix_test", "arg1", "test:arg1", "arg1" },
747 { "", "arg2", "arg2", "arg2" },
748 { "prefix_test", "ar3", "test:ar3", "arg3" },
749 { "", "", "xmlns:test", "prefix_test" },
750 { "", "", "xmlns", "prefix" },
751 { NULL }
754 static struct call_entry content_handler_test_attributes_alternate_4[] = {
755 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
756 { CH_STARTDOCUMENT, 1, 22, S_OK },
757 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
758 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
759 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
760 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
761 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
762 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
763 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
764 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
765 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
766 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
767 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
768 { CH_ENDDOCUMENT, 4, 0, S_OK },
769 { CH_ENDTEST }
772 /* 'namespace' feature switched off */
773 static struct attribute_entry ch_attributes_alt_no_ns[] = {
774 { "", "", "xmlns:test", "prefix_test" },
775 { "", "", "xmlns", "prefix" },
776 { "", "", "test:arg1", "arg1" },
777 { "", "", "arg2", "arg2" },
778 { "", "", "test:ar3", "arg3" },
779 { NULL }
782 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
783 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
784 { CH_STARTDOCUMENT, 1, 22, S_OK },
785 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
786 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
787 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
788 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
789 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
790 { CH_ENDDOCUMENT, 4, 0, S_OK },
791 { CH_ENDTEST }
794 static struct attribute_entry ch_attributes_alt_6[] = {
795 { "prefix_test", "arg1", "test:arg1", "arg1" },
796 { "", "arg2", "arg2", "arg2" },
797 { "prefix_test", "ar3", "test:ar3", "arg3" },
798 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
799 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
800 { NULL }
803 static struct attribute_entry ch_attributes2_6[] = {
804 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
805 { NULL }
808 static struct call_entry content_handler_test_attributes_alternate_6[] = {
809 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
810 { CH_STARTDOCUMENT, 1, 22, S_OK },
811 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
812 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
813 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
814 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
815 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
816 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
817 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
818 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
819 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
820 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
821 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
822 { CH_ENDDOCUMENT, 4, 0, S_OK },
823 { CH_ENDTEST }
826 /* 'namespaces' is on, 'namespace-prefixes' if off */
827 static struct attribute_entry ch_attributes_no_prefix[] = {
828 { "prefix_test", "arg1", "test:arg1", "arg1" },
829 { "", "arg2", "arg2", "arg2" },
830 { "prefix_test", "ar3", "test:ar3", "arg3" },
831 { NULL }
834 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
835 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
836 { CH_STARTDOCUMENT, 1, 22, S_OK },
837 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
838 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
839 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
840 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
841 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
842 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
843 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
844 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
845 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
846 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
847 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
848 { CH_ENDDOCUMENT, 4, 0, S_OK },
849 { CH_ENDTEST }
852 static struct call_entry content_handler_test_attributes_no_prefix[] = {
853 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
854 { CH_STARTDOCUMENT, 0, 0, S_OK },
855 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
856 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
857 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
858 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
859 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
860 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
861 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
862 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
863 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
864 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
865 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
866 { CH_ENDDOCUMENT, 0, 0 },
867 { CH_ENDTEST }
870 static struct attribute_entry xmlspace_attrs[] = {
871 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
872 { NULL }
875 static struct call_entry xmlspaceattr_test[] = {
876 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
877 { CH_STARTDOCUMENT, 0, 0, S_OK },
878 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
879 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
880 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
881 { CH_ENDDOCUMENT, 0, 0, S_OK },
882 { CH_ENDTEST }
885 static struct call_entry xmlspaceattr_test_alternate[] = {
886 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
887 { CH_STARTDOCUMENT, 1, 39, S_OK },
888 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
889 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
890 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
891 { CH_ENDDOCUMENT, 1, 83, S_OK },
892 { CH_ENDTEST }
895 /* attribute value normalization test */
896 static const char attribute_normalize[] =
897 "<?xml version=\"1.0\" ?>\n"
898 "<a attr1=\" \r \n \tattr_value &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
900 static struct attribute_entry attribute_norm_attrs[] = {
901 { "", "attr1", "attr1", " attr_value A & & " },
902 { NULL }
905 static struct call_entry attribute_norm[] = {
906 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
907 { CH_STARTDOCUMENT, 0, 0, S_OK },
908 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
909 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
910 { CH_ENDDOCUMENT, 0, 0, S_OK },
911 { CH_ENDTEST }
914 static struct call_entry attribute_norm_alt[] = {
915 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
916 { CH_STARTDOCUMENT, 1, 22, S_OK },
917 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
918 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
919 { CH_ENDDOCUMENT, 9, 0, S_OK },
920 { CH_ENDTEST }
923 static struct call_entry cdata_test[] = {
924 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
925 { CH_STARTDOCUMENT, 0, 0, S_OK },
926 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
927 { LH_STARTCDATA, 1, 35, S_OK },
928 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
929 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
930 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
931 { LH_ENDCDATA, 1, 49, S_OK },
932 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
933 { CH_ENDDOCUMENT, 0, 0, S_OK },
934 { CH_ENDTEST }
937 static struct call_entry cdata_test2[] = {
938 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
939 { CH_STARTDOCUMENT, 0, 0, S_OK },
940 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
941 { LH_STARTCDATA, 1, 35, S_OK },
942 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
943 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
944 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
945 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
946 { LH_ENDCDATA, 1, 52, S_OK },
947 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
948 { CH_ENDDOCUMENT, 0, 0, S_OK },
949 { CH_ENDTEST }
952 static struct call_entry cdata_test3[] = {
953 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
954 { CH_STARTDOCUMENT, 0, 0, S_OK },
955 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
956 { LH_STARTCDATA, 1, 35, S_OK },
957 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
958 { LH_ENDCDATA, 1, 35, S_OK },
959 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
960 { CH_ENDDOCUMENT, 0, 0, S_OK },
961 { CH_ENDTEST }
964 /* this is what MSXML6 does */
965 static struct call_entry cdata_test_alt[] = {
966 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
967 { CH_STARTDOCUMENT, 1, 22, S_OK },
968 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
969 { LH_STARTCDATA, 1, 34, S_OK },
970 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
971 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
972 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
973 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
974 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
975 { LH_ENDCDATA, 6, 3, S_OK },
976 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
977 { CH_ENDDOCUMENT, 6, 7, S_OK },
978 { CH_ENDTEST }
981 static struct call_entry cdata_test2_alt[] = {
982 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
983 { CH_STARTDOCUMENT, 1, 22, S_OK },
984 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
985 { LH_STARTCDATA, 1, 34, S_OK },
986 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
987 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
988 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
989 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
990 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
991 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
992 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
993 { LH_ENDCDATA, 8, 3, S_OK },
994 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
995 { CH_ENDDOCUMENT, 8, 7, S_OK },
996 { CH_ENDTEST }
999 static struct call_entry cdata_test3_alt[] = {
1000 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
1001 { CH_STARTDOCUMENT, 1, 22, S_OK },
1002 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
1003 { LH_STARTCDATA, 1, 34, S_OK },
1004 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
1005 { LH_ENDCDATA, 1, 51, S_OK },
1006 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
1007 { CH_ENDDOCUMENT, 1, 55, S_OK },
1008 { CH_ENDTEST }
1011 static struct attribute_entry read_test_attrs[] = {
1012 { "", "attr", "attr", "val" },
1013 { NULL }
1016 static struct call_entry read_test_seq[] = {
1017 { CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK },
1018 { CH_STARTDOCUMENT, -1, -1, S_OK },
1019 { CH_STARTELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1020 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1021 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1022 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1023 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1024 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1025 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1026 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1027 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1028 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1029 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1030 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1031 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1032 { CH_ENDELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1033 { CH_ENDDOCUMENT, -1, -1, S_OK},
1034 { CH_ENDTEST }
1037 static const char xmlspace_attr[] =
1038 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1039 "<a xml:space=\"preserve\"> Some text data </a>";
1041 static struct call_entry *expectCall;
1042 static ISAXLocator *locator;
1043 static ISAXXMLReader *g_reader;
1044 int msxml_version;
1046 static void set_expected_seq(struct call_entry *expected)
1048 expectCall = expected;
1051 /* to be called once on each tested callback return */
1052 static HRESULT get_expected_ret(void)
1054 HRESULT hr = expectCall->ret;
1055 if (expectCall->id != CH_ENDTEST) expectCall++;
1056 return hr;
1059 static HRESULT WINAPI contentHandler_QueryInterface(
1060 ISAXContentHandler* iface,
1061 REFIID riid,
1062 void **ppvObject)
1064 *ppvObject = NULL;
1066 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1068 *ppvObject = iface;
1070 else
1072 return E_NOINTERFACE;
1075 return S_OK;
1078 static ULONG WINAPI contentHandler_AddRef(
1079 ISAXContentHandler* iface)
1081 return 2;
1084 static ULONG WINAPI contentHandler_Release(
1085 ISAXContentHandler* iface)
1087 return 1;
1090 static HRESULT WINAPI contentHandler_putDocumentLocator(
1091 ISAXContentHandler* iface,
1092 ISAXLocator *pLocator)
1094 struct call_entry call;
1095 IUnknown *unk;
1096 HRESULT hr;
1098 locator = pLocator;
1100 init_call_entry(locator, &call);
1101 call.id = CH_PUTDOCUMENTLOCATOR;
1102 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1104 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
1105 EXPECT_HR(hr, E_NOINTERFACE);
1107 if (msxml_version >= 6) {
1108 ISAXAttributes *attr, *attr1;
1109 IMXAttributes *mxattr;
1111 EXPECT_REF(pLocator, 1);
1112 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1113 EXPECT_HR(hr, S_OK);
1114 EXPECT_REF(pLocator, 2);
1115 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1116 EXPECT_HR(hr, S_OK);
1117 EXPECT_REF(pLocator, 3);
1118 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1120 hr = ISAXAttributes_QueryInterface(attr, &IID_IVBSAXAttributes, (void**)&unk);
1121 EXPECT_HR(hr, E_NOINTERFACE);
1123 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk);
1124 EXPECT_HR(hr, E_NOINTERFACE);
1126 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1127 EXPECT_HR(hr, E_NOINTERFACE);
1129 ISAXAttributes_Release(attr);
1130 ISAXAttributes_Release(attr1);
1133 return get_expected_ret();
1136 static ISAXAttributes *test_attr_ptr;
1137 static HRESULT WINAPI contentHandler_startDocument(
1138 ISAXContentHandler* iface)
1140 struct call_entry call;
1142 init_call_entry(locator, &call);
1143 call.id = CH_STARTDOCUMENT;
1144 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1146 test_attr_ptr = NULL;
1148 return get_expected_ret();
1151 static HRESULT WINAPI contentHandler_endDocument(
1152 ISAXContentHandler* iface)
1154 struct call_entry call;
1156 init_call_entry(locator, &call);
1157 call.id = CH_ENDDOCUMENT;
1158 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1160 return get_expected_ret();
1163 static HRESULT WINAPI contentHandler_startPrefixMapping(
1164 ISAXContentHandler* iface,
1165 const WCHAR *prefix, int prefix_len,
1166 const WCHAR *uri, int uri_len)
1168 struct call_entry call;
1170 init_call_entry(locator, &call);
1171 call.id = CH_STARTPREFIXMAPPING;
1172 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1173 call.arg2W = SysAllocStringLen(uri, uri_len);
1174 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1176 return get_expected_ret();
1179 static HRESULT WINAPI contentHandler_endPrefixMapping(
1180 ISAXContentHandler* iface,
1181 const WCHAR *prefix, int len)
1183 struct call_entry call;
1185 init_call_entry(locator, &call);
1186 call.id = CH_ENDPREFIXMAPPING;
1187 call.arg1W = SysAllocStringLen(prefix, len);
1188 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1190 return get_expected_ret();
1193 static HRESULT WINAPI contentHandler_startElement(
1194 ISAXContentHandler* iface,
1195 const WCHAR *uri, int uri_len,
1196 const WCHAR *localname, int local_len,
1197 const WCHAR *qname, int qname_len,
1198 ISAXAttributes *saxattr)
1200 struct call_entry call;
1201 IMXAttributes *mxattr;
1202 HRESULT hr;
1203 int len;
1205 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1206 EXPECT_HR(hr, E_NOINTERFACE);
1208 init_call_entry(locator, &call);
1209 call.id = CH_STARTELEMENT;
1210 call.arg1W = SysAllocStringLen(uri, uri_len);
1211 call.arg2W = SysAllocStringLen(localname, local_len);
1212 call.arg3W = SysAllocStringLen(qname, qname_len);
1214 if(!test_attr_ptr)
1215 test_attr_ptr = saxattr;
1216 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1218 /* store actual attributes */
1219 len = 0;
1220 hr = ISAXAttributes_getLength(saxattr, &len);
1221 EXPECT_HR(hr, S_OK);
1223 if (len)
1225 VARIANT_BOOL v;
1226 int i;
1228 struct attribute_entry *attr;
1229 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1231 v = VARIANT_TRUE;
1232 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1233 EXPECT_HR(hr, S_OK);
1235 for (i = 0; i < len; i++)
1237 const WCHAR *value;
1238 int value_len;
1240 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1241 &localname, &local_len, &qname, &qname_len);
1242 EXPECT_HR(hr, S_OK);
1244 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1245 EXPECT_HR(hr, S_OK);
1247 /* if 'namespaces' switched off uri and local name contains garbage */
1248 if (v == VARIANT_FALSE && msxml_version > 0)
1250 attr[i].uriW = SysAllocStringLen(NULL, 0);
1251 attr[i].localW = SysAllocStringLen(NULL, 0);
1253 else
1255 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1256 attr[i].localW = SysAllocStringLen(localname, local_len);
1259 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1260 attr[i].valueW = SysAllocStringLen(value, value_len);
1263 call.attributes = attr;
1264 call.attr_count = len;
1267 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1269 return get_expected_ret();
1272 static HRESULT WINAPI contentHandler_endElement(
1273 ISAXContentHandler* iface,
1274 const WCHAR *uri, int uri_len,
1275 const WCHAR *localname, int local_len,
1276 const WCHAR *qname, int qname_len)
1278 struct call_entry call;
1280 init_call_entry(locator, &call);
1281 call.id = CH_ENDELEMENT;
1282 call.arg1W = SysAllocStringLen(uri, uri_len);
1283 call.arg2W = SysAllocStringLen(localname, local_len);
1284 call.arg3W = SysAllocStringLen(qname, qname_len);
1285 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1287 return get_expected_ret();
1290 static HRESULT WINAPI contentHandler_characters(
1291 ISAXContentHandler* iface,
1292 const WCHAR *chars,
1293 int len)
1295 struct call_entry call;
1297 init_call_entry(locator, &call);
1298 call.id = CH_CHARACTERS;
1299 call.arg1W = SysAllocStringLen(chars, len);
1300 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1302 return get_expected_ret();
1305 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1306 ISAXContentHandler* iface,
1307 const WCHAR *chars, int len)
1309 struct call_entry call;
1311 init_call_entry(locator, &call);
1312 call.id = CH_IGNORABLEWHITESPACE;
1313 call.arg1W = SysAllocStringLen(chars, len);
1314 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1316 return get_expected_ret();
1319 static HRESULT WINAPI contentHandler_processingInstruction(
1320 ISAXContentHandler* iface,
1321 const WCHAR *target, int target_len,
1322 const WCHAR *data, int data_len)
1324 struct call_entry call;
1326 init_call_entry(locator, &call);
1327 call.id = CH_PROCESSINGINSTRUCTION;
1328 call.arg1W = SysAllocStringLen(target, target_len);
1329 call.arg2W = SysAllocStringLen(data, data_len);
1330 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1332 return get_expected_ret();
1335 static HRESULT WINAPI contentHandler_skippedEntity(
1336 ISAXContentHandler* iface,
1337 const WCHAR *name, int len)
1339 struct call_entry call;
1341 init_call_entry(locator, &call);
1342 call.id = CH_SKIPPEDENTITY;
1343 call.arg1W = SysAllocStringLen(name, len);
1344 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1346 return get_expected_ret();
1349 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1351 contentHandler_QueryInterface,
1352 contentHandler_AddRef,
1353 contentHandler_Release,
1354 contentHandler_putDocumentLocator,
1355 contentHandler_startDocument,
1356 contentHandler_endDocument,
1357 contentHandler_startPrefixMapping,
1358 contentHandler_endPrefixMapping,
1359 contentHandler_startElement,
1360 contentHandler_endElement,
1361 contentHandler_characters,
1362 contentHandler_ignorableWhitespace,
1363 contentHandler_processingInstruction,
1364 contentHandler_skippedEntity
1367 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1369 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1370 ISAXErrorHandler* iface,
1371 REFIID riid,
1372 void **ppvObject)
1374 *ppvObject = NULL;
1376 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1378 *ppvObject = iface;
1380 else
1382 return E_NOINTERFACE;
1385 return S_OK;
1388 static ULONG WINAPI isaxerrorHandler_AddRef(
1389 ISAXErrorHandler* iface)
1391 return 2;
1394 static ULONG WINAPI isaxerrorHandler_Release(
1395 ISAXErrorHandler* iface)
1397 return 1;
1400 static HRESULT WINAPI isaxerrorHandler_error(
1401 ISAXErrorHandler* iface,
1402 ISAXLocator *pLocator,
1403 const WCHAR *pErrorMessage,
1404 HRESULT hrErrorCode)
1406 ok(0, "unexpected call\n");
1407 return S_OK;
1410 static HRESULT WINAPI isaxerrorHandler_fatalError(
1411 ISAXErrorHandler* iface,
1412 ISAXLocator *pLocator,
1413 const WCHAR *message,
1414 HRESULT hr)
1416 struct call_entry call;
1418 init_call_entry(locator, &call);
1419 call.id = EH_FATALERROR;
1420 call.ret = hr;
1422 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1424 get_expected_ret();
1425 return S_OK;
1428 static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
1429 ISAXErrorHandler* iface,
1430 ISAXLocator *pLocator,
1431 const WCHAR *pErrorMessage,
1432 HRESULT hrErrorCode)
1434 ok(0, "unexpected call\n");
1435 return S_OK;
1438 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1440 isaxerrorHandler_QueryInterface,
1441 isaxerrorHandler_AddRef,
1442 isaxerrorHandler_Release,
1443 isaxerrorHandler_error,
1444 isaxerrorHandler_fatalError,
1445 isaxerrorHandler_ignorableWarning
1448 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1450 static HRESULT WINAPI isaxattributes_QueryInterface(
1451 ISAXAttributes* iface,
1452 REFIID riid,
1453 void **ppvObject)
1455 *ppvObject = NULL;
1457 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1459 *ppvObject = iface;
1461 else
1463 return E_NOINTERFACE;
1466 return S_OK;
1469 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1471 return 2;
1474 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1476 return 1;
1479 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1481 *length = 3;
1482 return S_OK;
1485 static HRESULT WINAPI isaxattributes_getURI(
1486 ISAXAttributes* iface,
1487 int nIndex,
1488 const WCHAR **pUrl,
1489 int *pUriSize)
1491 ok(0, "unexpected call\n");
1492 return E_NOTIMPL;
1495 static HRESULT WINAPI isaxattributes_getLocalName(
1496 ISAXAttributes* iface,
1497 int nIndex,
1498 const WCHAR **pLocalName,
1499 int *pLocalNameLength)
1501 ok(0, "unexpected call\n");
1502 return E_NOTIMPL;
1505 static HRESULT WINAPI isaxattributes_getQName(
1506 ISAXAttributes* iface,
1507 int index,
1508 const WCHAR **QName,
1509 int *QNameLength)
1511 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1512 {'a','t','t','r','2','j','u','n','k',0},
1513 {'a','t','t','r','3',0}};
1514 static const int attrqnamelen[] = {7, 5, 5};
1516 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1518 if (index >= 0 && index <= 2) {
1519 *QName = attrqnamesW[index];
1520 *QNameLength = attrqnamelen[index];
1521 } else {
1522 *QName = NULL;
1523 *QNameLength = 0;
1526 return S_OK;
1529 static HRESULT WINAPI isaxattributes_getName(
1530 ISAXAttributes* iface,
1531 int nIndex,
1532 const WCHAR **pUri,
1533 int * pUriLength,
1534 const WCHAR ** pLocalName,
1535 int * pLocalNameSize,
1536 const WCHAR ** pQName,
1537 int * pQNameLength)
1539 ok(0, "unexpected call\n");
1540 return E_NOTIMPL;
1543 static HRESULT WINAPI isaxattributes_getIndexFromName(
1544 ISAXAttributes* iface,
1545 const WCHAR * pUri,
1546 int cUriLength,
1547 const WCHAR * pLocalName,
1548 int cocalNameLength,
1549 int * index)
1551 ok(0, "unexpected call\n");
1552 return E_NOTIMPL;
1555 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1556 ISAXAttributes* iface,
1557 const WCHAR * pQName,
1558 int nQNameLength,
1559 int * index)
1561 ok(0, "unexpected call\n");
1562 return E_NOTIMPL;
1565 static HRESULT WINAPI isaxattributes_getType(
1566 ISAXAttributes* iface,
1567 int nIndex,
1568 const WCHAR ** pType,
1569 int * pTypeLength)
1571 ok(0, "unexpected call\n");
1572 return E_NOTIMPL;
1575 static HRESULT WINAPI isaxattributes_getTypeFromName(
1576 ISAXAttributes* iface,
1577 const WCHAR * pUri,
1578 int nUri,
1579 const WCHAR * pLocalName,
1580 int nLocalName,
1581 const WCHAR ** pType,
1582 int * nType)
1584 ok(0, "unexpected call\n");
1585 return E_NOTIMPL;
1588 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1589 ISAXAttributes* iface,
1590 const WCHAR * pQName,
1591 int nQName,
1592 const WCHAR ** pType,
1593 int * nType)
1595 ok(0, "unexpected call\n");
1596 return E_NOTIMPL;
1599 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1600 const WCHAR **value, int *nValue)
1602 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1603 {'a','2','j','u','n','k',0},
1604 {'<','&','"','>','\'',0}};
1605 static const int attrvalueslen[] = {2, 2, 5};
1607 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1609 if (index >= 0 && index <= 2) {
1610 *value = attrvaluesW[index];
1611 *nValue = attrvalueslen[index];
1612 } else {
1613 *value = NULL;
1614 *nValue = 0;
1617 return S_OK;
1620 static HRESULT WINAPI isaxattributes_getValueFromName(
1621 ISAXAttributes* iface,
1622 const WCHAR * pUri,
1623 int nUri,
1624 const WCHAR * pLocalName,
1625 int nLocalName,
1626 const WCHAR ** pValue,
1627 int * nValue)
1629 ok(0, "unexpected call\n");
1630 return E_NOTIMPL;
1633 static HRESULT WINAPI isaxattributes_getValueFromQName(
1634 ISAXAttributes* iface,
1635 const WCHAR * pQName,
1636 int nQName,
1637 const WCHAR ** pValue,
1638 int * nValue)
1640 ok(0, "unexpected call\n");
1641 return E_NOTIMPL;
1644 static const ISAXAttributesVtbl SAXAttributesVtbl =
1646 isaxattributes_QueryInterface,
1647 isaxattributes_AddRef,
1648 isaxattributes_Release,
1649 isaxattributes_getLength,
1650 isaxattributes_getURI,
1651 isaxattributes_getLocalName,
1652 isaxattributes_getQName,
1653 isaxattributes_getName,
1654 isaxattributes_getIndexFromName,
1655 isaxattributes_getIndexFromQName,
1656 isaxattributes_getType,
1657 isaxattributes_getTypeFromName,
1658 isaxattributes_getTypeFromQName,
1659 isaxattributes_getValue,
1660 isaxattributes_getValueFromName,
1661 isaxattributes_getValueFromQName
1664 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1666 struct saxlexicalhandler
1668 ISAXLexicalHandler ISAXLexicalHandler_iface;
1669 LONG ref;
1671 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1674 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1676 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1679 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1681 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1683 *out = NULL;
1685 if (IsEqualGUID(riid, &IID_IUnknown))
1687 *out = iface;
1688 ok(0, "got unexpected IID_IUnknown query\n");
1690 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1692 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1693 *out = iface;
1696 if (*out)
1697 ISAXLexicalHandler_AddRef(iface);
1698 else
1699 return E_NOINTERFACE;
1701 return S_OK;
1704 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1706 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1707 return InterlockedIncrement(&handler->ref);
1710 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1712 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1713 return InterlockedDecrement(&handler->ref);
1716 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1717 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1718 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1720 ok(0, "call not expected\n");
1721 return E_NOTIMPL;
1724 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1726 ok(0, "call not expected\n");
1727 return E_NOTIMPL;
1730 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1731 const WCHAR * pName, int nName)
1733 ok(0, "call not expected\n");
1734 return E_NOTIMPL;
1737 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1738 const WCHAR * pName, int nName)
1740 ok(0, "call not expected\n");
1741 return E_NOTIMPL;
1744 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1746 struct call_entry call;
1748 init_call_entry(locator, &call);
1749 call.id = LH_STARTCDATA;
1750 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1752 return get_expected_ret();
1755 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1757 struct call_entry call;
1759 init_call_entry(locator, &call);
1760 call.id = LH_ENDCDATA;
1761 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1763 return get_expected_ret();
1766 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1767 const WCHAR * pChars, int nChars)
1769 ok(0, "call not expected\n");
1770 return E_NOTIMPL;
1773 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1775 isaxlexical_QueryInterface,
1776 isaxlexical_AddRef,
1777 isaxlexical_Release,
1778 isaxlexical_startDTD,
1779 isaxlexical_endDTD,
1780 isaxlexical_startEntity,
1781 isaxlexical_endEntity,
1782 isaxlexical_startCDATA,
1783 isaxlexical_endCDATA,
1784 isaxlexical_comment
1787 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1789 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1790 handler->ref = 1;
1791 handler->qi_hr = hr;
1794 struct saxdeclhandler
1796 ISAXDeclHandler ISAXDeclHandler_iface;
1797 LONG ref;
1799 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1802 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1804 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1807 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1809 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1811 *out = NULL;
1813 if (IsEqualGUID(riid, &IID_IUnknown))
1815 *out = iface;
1816 ok(0, "got unexpected IID_IUnknown query\n");
1818 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1820 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1821 *out = iface;
1824 if (*out)
1825 ISAXDeclHandler_AddRef(iface);
1826 else
1827 return E_NOINTERFACE;
1829 return S_OK;
1832 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1834 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1835 return InterlockedIncrement(&handler->ref);
1838 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1840 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1841 return InterlockedDecrement(&handler->ref);
1844 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1845 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1847 ok(0, "call not expected\n");
1848 return E_NOTIMPL;
1851 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1852 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1853 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1854 int nValueDefault, const WCHAR * pValue, int nValue)
1856 ok(0, "call not expected\n");
1857 return E_NOTIMPL;
1860 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1861 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1863 ok(0, "call not expected\n");
1864 return E_NOTIMPL;
1867 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1868 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1869 const WCHAR * pSystemId, int nSystemId)
1871 ok(0, "call not expected\n");
1872 return E_NOTIMPL;
1875 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1877 isaxdecl_QueryInterface,
1878 isaxdecl_AddRef,
1879 isaxdecl_Release,
1880 isaxdecl_elementDecl,
1881 isaxdecl_attributeDecl,
1882 isaxdecl_internalEntityDecl,
1883 isaxdecl_externalEntityDecl
1886 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1888 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1889 handler->ref = 1;
1890 handler->qi_hr = hr;
1893 typedef struct mxwriter_write_test_t {
1894 BOOL last;
1895 const BYTE *data;
1896 DWORD cb;
1897 BOOL null_written;
1898 BOOL fail_write;
1899 } mxwriter_write_test;
1901 typedef struct mxwriter_stream_test_t {
1902 VARIANT_BOOL bom;
1903 const char *encoding;
1904 mxwriter_write_test expected_writes[4];
1905 } mxwriter_stream_test;
1907 static const mxwriter_write_test *current_write_test;
1908 static DWORD current_stream_test_index;
1910 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1912 *ppvObject = NULL;
1914 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1915 *ppvObject = iface;
1916 else
1917 return E_NOINTERFACE;
1919 return S_OK;
1922 static ULONG WINAPI istream_AddRef(IStream *iface)
1924 return 2;
1927 static ULONG WINAPI istream_Release(IStream *iface)
1929 return 1;
1932 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1934 ok(0, "unexpected call\n");
1935 return E_NOTIMPL;
1938 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1940 ok(0, "unexpected call\n");
1941 return E_NOTIMPL;
1944 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1945 ULARGE_INTEGER *plibNewPosition)
1947 ok(0, "unexpected call\n");
1948 return E_NOTIMPL;
1951 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1953 ok(0, "unexpected call\n");
1954 return E_NOTIMPL;
1957 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1958 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1960 ok(0, "unexpected call\n");
1961 return E_NOTIMPL;
1964 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1966 ok(0, "unexpected call\n");
1967 return E_NOTIMPL;
1970 static HRESULT WINAPI istream_Revert(IStream *iface)
1972 ok(0, "unexpected call\n");
1973 return E_NOTIMPL;
1976 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1977 ULARGE_INTEGER cb, DWORD dwLockType)
1979 ok(0, "unexpected call\n");
1980 return E_NOTIMPL;
1983 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1984 ULARGE_INTEGER cb, DWORD dwLockType)
1986 ok(0, "unexpected call\n");
1987 return E_NOTIMPL;
1990 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1992 ok(0, "unexpected call\n");
1993 return E_NOTIMPL;
1996 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1998 ok(0, "unexpected call\n");
1999 return E_NOTIMPL;
2002 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
2004 BOOL fail = FALSE;
2006 ok(pv != NULL, "pv == NULL\n");
2008 if(current_write_test->last) {
2009 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
2010 return E_FAIL;
2013 fail = current_write_test->fail_write;
2015 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
2016 current_write_test->cb, cb, current_stream_test_index);
2018 if(!pcbWritten)
2019 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
2020 else
2021 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
2023 ++current_write_test;
2025 if(pcbWritten)
2026 *pcbWritten = cb;
2028 return fail ? E_FAIL : S_OK;
2031 static const IStreamVtbl mxstreamVtbl = {
2032 istream_QueryInterface,
2033 istream_AddRef,
2034 istream_Release,
2035 istream_Read,
2036 mxstream_Write,
2037 istream_Seek,
2038 istream_SetSize,
2039 istream_CopyTo,
2040 istream_Commit,
2041 istream_Revert,
2042 istream_LockRegion,
2043 istream_UnlockRegion,
2044 istream_Stat,
2045 istream_Clone
2048 static IStream mxstream = { &mxstreamVtbl };
2050 static int read_cnt;
2052 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
2054 static const char *ret_str;
2056 if(!read_cnt)
2057 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
2058 else if(read_cnt < 5)
2059 ret_str = "<elem attr=\"val\">text</elem>";
2060 else if(read_cnt == 5)
2061 ret_str = "</rootelem>\n";
2062 else
2063 ret_str = "";
2065 read_cnt++;
2066 strcpy(pv, ret_str);
2067 *pcbRead = strlen(ret_str);
2068 return S_OK;
2071 static const IStreamVtbl instreamVtbl = {
2072 istream_QueryInterface,
2073 istream_AddRef,
2074 istream_Release,
2075 instream_Read,
2076 istream_Write,
2077 istream_Seek,
2078 istream_SetSize,
2079 istream_CopyTo,
2080 istream_Commit,
2081 istream_Revert,
2082 istream_LockRegion,
2083 istream_UnlockRegion,
2084 istream_Stat,
2085 istream_Clone
2088 static IStream instream = { &instreamVtbl };
2090 static struct msxmlsupported_data_t reader_support_data[] =
2092 { &CLSID_SAXXMLReader, "SAXReader" },
2093 { &CLSID_SAXXMLReader30, "SAXReader30" },
2094 { &CLSID_SAXXMLReader40, "SAXReader40" },
2095 { &CLSID_SAXXMLReader60, "SAXReader60" },
2096 { NULL }
2099 static struct saxlexicalhandler lexicalhandler;
2100 static struct saxdeclhandler declhandler;
2102 static IStream *create_test_stream(const char *data, int len)
2104 ULARGE_INTEGER size;
2105 LARGE_INTEGER pos;
2106 IStream *stream;
2107 ULONG written;
2109 if (len == -1) len = strlen(data);
2110 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2111 size.QuadPart = len;
2112 IStream_SetSize(stream, size);
2113 IStream_Write(stream, data, len, &written);
2114 pos.QuadPart = 0;
2115 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2117 return stream;
2120 static void test_saxreader(void)
2122 const struct msxmlsupported_data_t *table = reader_support_data;
2123 HRESULT hr;
2124 ISAXXMLReader *reader = NULL;
2125 VARIANT var;
2126 ISAXContentHandler *content;
2127 ISAXErrorHandler *lpErrorHandler;
2128 SAFEARRAY *sa;
2129 SAFEARRAYBOUND SADim[1];
2130 char *ptr = NULL;
2131 IStream *stream;
2132 ULONG written;
2133 HANDLE file;
2134 static const CHAR testXmlA[] = "test.xml";
2135 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2136 IXMLDOMDocument *doc;
2137 char seqname[50];
2138 VARIANT_BOOL v;
2140 while (table->clsid)
2142 struct call_entry *test_seq;
2143 ISAXEntityResolver *resolver;
2144 BSTR str;
2146 if (!is_clsid_supported(table->clsid, reader_support_data))
2148 table++;
2149 continue;
2152 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2153 EXPECT_HR(hr, S_OK);
2154 g_reader = reader;
2156 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2157 msxml_version = 4;
2158 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2159 msxml_version = 6;
2160 else
2161 msxml_version = 0;
2163 /* crashes on old versions */
2164 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2165 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2167 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2168 EXPECT_HR(hr, E_POINTER);
2170 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2171 EXPECT_HR(hr, E_POINTER);
2174 hr = ISAXXMLReader_getContentHandler(reader, &content);
2175 EXPECT_HR(hr, S_OK);
2176 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2178 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2179 EXPECT_HR(hr, S_OK);
2180 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2182 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2183 EXPECT_HR(hr, S_OK);
2185 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2186 EXPECT_HR(hr, S_OK);
2188 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2189 EXPECT_HR(hr, S_OK);
2191 hr = ISAXXMLReader_getContentHandler(reader, &content);
2192 EXPECT_HR(hr, S_OK);
2193 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2195 V_VT(&var) = VT_BSTR;
2196 V_BSTR(&var) = SysAllocString(szSimpleXML);
2198 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2199 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2200 test_seq = content_handler_test1_alternate;
2201 else
2202 test_seq = content_handler_test1;
2203 set_expected_seq(test_seq);
2204 hr = ISAXXMLReader_parse(reader, var);
2205 EXPECT_HR(hr, S_OK);
2206 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2208 VariantClear(&var);
2210 SADim[0].lLbound = 0;
2211 SADim[0].cElements = sizeof(testXML)-1;
2212 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2213 SafeArrayAccessData(sa, (void**)&ptr);
2214 memcpy(ptr, testXML, sizeof(testXML)-1);
2215 SafeArrayUnaccessData(sa);
2216 V_VT(&var) = VT_ARRAY|VT_UI1;
2217 V_ARRAY(&var) = sa;
2219 set_expected_seq(test_seq);
2220 hr = ISAXXMLReader_parse(reader, var);
2221 EXPECT_HR(hr, S_OK);
2222 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2224 SafeArrayDestroy(sa);
2226 stream = create_test_stream(testXML, -1);
2227 V_VT(&var) = VT_UNKNOWN;
2228 V_UNKNOWN(&var) = (IUnknown*)stream;
2230 set_expected_seq(test_seq);
2231 hr = ISAXXMLReader_parse(reader, var);
2232 EXPECT_HR(hr, S_OK);
2233 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2235 IStream_Release(stream);
2237 stream = create_test_stream(test_attributes, -1);
2238 V_VT(&var) = VT_UNKNOWN;
2239 V_UNKNOWN(&var) = (IUnknown*)stream;
2241 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2242 test_seq = content_handler_test_attributes_alternate_4;
2243 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2244 test_seq = content_handler_test_attributes_alternate_6;
2245 else
2246 test_seq = content_handler_test_attributes;
2248 set_expected_seq(test_seq);
2249 hr = ISAXXMLReader_parse(reader, var);
2250 EXPECT_HR(hr, S_OK);
2252 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2253 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2254 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2255 else
2256 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2258 IStream_Release(stream);
2260 V_VT(&var) = VT_UNKNOWN;
2261 V_UNKNOWN(&var) = (IUnknown*)&instream;
2263 test_seq = read_test_seq;
2264 read_cnt = 0;
2265 set_expected_seq(test_seq);
2266 hr = ISAXXMLReader_parse(reader, var);
2267 EXPECT_HR(hr, S_OK);
2268 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
2269 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
2271 V_VT(&var) = VT_BSTR;
2272 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2274 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2275 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2276 test_seq = content_handler_test2_alternate;
2277 else
2278 test_seq = content_handler_test2;
2280 set_expected_seq(test_seq);
2281 hr = ISAXXMLReader_parse(reader, var);
2282 EXPECT_HR(hr, S_OK);
2283 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2285 VariantClear(&var);
2287 /* from file url */
2288 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2289 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2290 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2291 CloseHandle(file);
2293 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2294 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2295 test_seq = content_handler_test1_alternate;
2296 else
2297 test_seq = content_handler_test1;
2298 set_expected_seq(test_seq);
2299 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2300 EXPECT_HR(hr, S_OK);
2301 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2303 /* error handler */
2304 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2305 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2306 test_seq = content_handler_testerror_alternate;
2307 else
2308 test_seq = content_handler_testerror;
2309 set_expected_seq(test_seq);
2310 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2311 EXPECT_HR(hr, E_FAIL);
2312 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2314 /* callback ret values */
2315 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2316 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2318 test_seq = content_handler_test_callback_rets_alt;
2319 set_expected_seq(test_seq);
2320 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2321 EXPECT_HR(hr, S_OK);
2323 else
2325 test_seq = content_handler_test_callback_rets;
2326 set_expected_seq(test_seq);
2327 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2328 EXPECT_HR(hr, S_FALSE);
2330 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2332 DeleteFileA(testXmlA);
2334 /* parse from IXMLDOMDocument */
2335 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2336 &IID_IXMLDOMDocument, (void**)&doc);
2337 EXPECT_HR(hr, S_OK);
2339 str = SysAllocString(szSimpleXML);
2340 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2341 EXPECT_HR(hr, S_OK);
2342 SysFreeString(str);
2344 V_VT(&var) = VT_UNKNOWN;
2345 V_UNKNOWN(&var) = (IUnknown*)doc;
2347 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2348 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2349 test_seq = content_handler_test2_alternate;
2350 else
2351 test_seq = content_handler_test2;
2353 set_expected_seq(test_seq);
2354 hr = ISAXXMLReader_parse(reader, var);
2355 EXPECT_HR(hr, S_OK);
2356 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2357 IXMLDOMDocument_Release(doc);
2359 /* xml:space test */
2360 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2361 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2363 test_seq = xmlspaceattr_test_alternate;
2365 else
2366 test_seq = xmlspaceattr_test;
2368 set_expected_seq(test_seq);
2369 V_VT(&var) = VT_BSTR;
2370 V_BSTR(&var) = _bstr_(xmlspace_attr);
2371 hr = ISAXXMLReader_parse(reader, var);
2372 EXPECT_HR(hr, S_OK);
2374 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2375 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2377 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2379 else
2380 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2382 /* switch off 'namespaces' feature */
2383 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2384 EXPECT_HR(hr, S_OK);
2386 stream = create_test_stream(test_attributes, -1);
2387 V_VT(&var) = VT_UNKNOWN;
2388 V_UNKNOWN(&var) = (IUnknown*)stream;
2390 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2391 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2393 test_seq = content_handler_test_attributes_alt_no_ns;
2395 else
2396 test_seq = content_handler_test_attributes;
2398 set_expected_seq(test_seq);
2399 hr = ISAXXMLReader_parse(reader, var);
2400 EXPECT_HR(hr, S_OK);
2401 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2402 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2403 EXPECT_HR(hr, S_OK);
2405 /* switch off 'namespace-prefixes' feature */
2406 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2407 EXPECT_HR(hr, S_OK);
2409 stream = create_test_stream(test_attributes, -1);
2410 V_VT(&var) = VT_UNKNOWN;
2411 V_UNKNOWN(&var) = (IUnknown*)stream;
2413 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2414 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2416 test_seq = content_handler_test_attributes_alt_no_prefix;
2418 else
2419 test_seq = content_handler_test_attributes_no_prefix;
2421 set_expected_seq(test_seq);
2422 hr = ISAXXMLReader_parse(reader, var);
2423 EXPECT_HR(hr, S_OK);
2424 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2426 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2427 EXPECT_HR(hr, S_OK);
2429 /* attribute normalization */
2430 stream = create_test_stream(attribute_normalize, -1);
2431 V_VT(&var) = VT_UNKNOWN;
2432 V_UNKNOWN(&var) = (IUnknown*)stream;
2434 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2435 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2437 test_seq = attribute_norm_alt;
2439 else
2440 test_seq = attribute_norm;
2442 set_expected_seq(test_seq);
2443 hr = ISAXXMLReader_parse(reader, var);
2444 EXPECT_HR(hr, S_OK);
2445 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2447 resolver = (void*)0xdeadbeef;
2448 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2449 ok(hr == S_OK, "got 0x%08x\n", hr);
2450 ok(resolver == NULL, "got %p\n", resolver);
2452 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2453 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2455 /* CDATA sections */
2456 init_saxlexicalhandler(&lexicalhandler, S_OK);
2458 V_VT(&var) = VT_UNKNOWN;
2459 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2460 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2461 ok(hr == S_OK, "got 0x%08x\n", hr);
2463 stream = create_test_stream(test_cdata_xml, -1);
2464 V_VT(&var) = VT_UNKNOWN;
2465 V_UNKNOWN(&var) = (IUnknown*)stream;
2467 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2468 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2469 test_seq = cdata_test_alt;
2470 else
2471 test_seq = cdata_test;
2473 set_expected_seq(test_seq);
2474 hr = ISAXXMLReader_parse(reader, var);
2475 ok(hr == S_OK, "got 0x%08x\n", hr);
2476 sprintf(seqname, "%s: cdata test", table->name);
2477 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2479 /* 2. CDATA sections */
2480 stream = create_test_stream(test2_cdata_xml, -1);
2481 V_VT(&var) = VT_UNKNOWN;
2482 V_UNKNOWN(&var) = (IUnknown*)stream;
2484 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2485 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2486 test_seq = cdata_test2_alt;
2487 else
2488 test_seq = cdata_test2;
2490 set_expected_seq(test_seq);
2491 hr = ISAXXMLReader_parse(reader, var);
2492 ok(hr == S_OK, "got 0x%08x\n", hr);
2493 sprintf(seqname, "%s: cdata test 2", table->name);
2494 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2496 IStream_Release(stream);
2498 /* 3. CDATA sections */
2499 stream = create_test_stream(test3_cdata_xml, -1);
2500 V_VT(&var) = VT_UNKNOWN;
2501 V_UNKNOWN(&var) = (IUnknown*)stream;
2503 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2504 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2505 test_seq = cdata_test3_alt;
2506 else
2507 test_seq = cdata_test3;
2509 set_expected_seq(test_seq);
2510 hr = ISAXXMLReader_parse(reader, var);
2511 ok(hr == S_OK, "got 0x%08x\n", hr);
2512 sprintf(seqname, "%s: cdata test 3", table->name);
2513 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2515 IStream_Release(stream);
2517 ISAXXMLReader_Release(reader);
2518 table++;
2521 free_bstrs();
2524 struct saxreader_props_test_t
2526 const char *prop_name;
2527 IUnknown *iface;
2530 static const struct saxreader_props_test_t props_test_data[] = {
2531 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2532 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2533 { 0 }
2536 static void test_saxreader_properties(void)
2538 const struct saxreader_props_test_t *ptr = props_test_data;
2539 ISAXXMLReader *reader;
2540 HRESULT hr;
2541 VARIANT v;
2542 BSTR str;
2544 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2545 &IID_ISAXXMLReader, (void**)&reader);
2546 EXPECT_HR(hr, S_OK);
2548 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2549 EXPECT_HR(hr, E_POINTER);
2551 while (ptr->prop_name)
2553 VARIANT varref;
2554 LONG ref;
2556 init_saxlexicalhandler(&lexicalhandler, S_OK);
2557 init_saxdeclhandler(&declhandler, S_OK);
2559 V_VT(&v) = VT_EMPTY;
2560 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2561 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2562 EXPECT_HR(hr, S_OK);
2563 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2564 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2566 /* VT_UNKNOWN */
2567 V_VT(&v) = VT_UNKNOWN;
2568 V_UNKNOWN(&v) = ptr->iface;
2569 ref = get_refcount(ptr->iface);
2570 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2571 EXPECT_HR(hr, S_OK);
2572 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2574 /* VT_DISPATCH */
2575 V_VT(&v) = VT_DISPATCH;
2576 V_UNKNOWN(&v) = ptr->iface;
2577 ref = get_refcount(ptr->iface);
2578 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2579 EXPECT_HR(hr, S_OK);
2580 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2582 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2583 V_VT(&varref) = VT_UNKNOWN;
2584 V_UNKNOWN(&varref) = ptr->iface;
2586 V_VT(&v) = VT_VARIANT|VT_BYREF;
2587 V_VARIANTREF(&v) = &varref;
2588 ref = get_refcount(ptr->iface);
2589 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2590 EXPECT_HR(hr, S_OK);
2591 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2593 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2594 V_VT(&varref) = VT_DISPATCH;
2595 V_UNKNOWN(&varref) = ptr->iface;
2597 V_VT(&v) = VT_VARIANT|VT_BYREF;
2598 V_VARIANTREF(&v) = &varref;
2599 ref = get_refcount(ptr->iface);
2600 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2601 EXPECT_HR(hr, S_OK);
2602 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2604 V_VT(&v) = VT_EMPTY;
2605 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2607 ref = get_refcount(ptr->iface);
2608 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2609 EXPECT_HR(hr, S_OK);
2610 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2611 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2612 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2613 VariantClear(&v);
2615 V_VT(&v) = VT_EMPTY;
2616 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2617 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2618 EXPECT_HR(hr, S_OK);
2620 V_VT(&v) = VT_EMPTY;
2621 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2622 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2623 EXPECT_HR(hr, S_OK);
2624 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2625 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2627 V_VT(&v) = VT_UNKNOWN;
2628 V_UNKNOWN(&v) = ptr->iface;
2629 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2630 EXPECT_HR(hr, S_OK);
2632 /* only VT_EMPTY seems to be valid to reset property */
2633 V_VT(&v) = VT_I4;
2634 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2635 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2636 EXPECT_HR(hr, E_INVALIDARG);
2638 V_VT(&v) = VT_EMPTY;
2639 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2640 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2641 EXPECT_HR(hr, S_OK);
2642 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2643 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2644 VariantClear(&v);
2646 V_VT(&v) = VT_UNKNOWN;
2647 V_UNKNOWN(&v) = NULL;
2648 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2649 EXPECT_HR(hr, S_OK);
2651 V_VT(&v) = VT_EMPTY;
2652 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2653 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2654 EXPECT_HR(hr, S_OK);
2655 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2656 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2658 /* block QueryInterface on handler riid */
2659 V_VT(&v) = VT_UNKNOWN;
2660 V_UNKNOWN(&v) = ptr->iface;
2661 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2662 EXPECT_HR(hr, S_OK);
2664 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2665 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2667 V_VT(&v) = VT_UNKNOWN;
2668 V_UNKNOWN(&v) = ptr->iface;
2669 EXPECT_REF(ptr->iface, 1);
2670 ref = get_refcount(ptr->iface);
2671 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2672 EXPECT_HR(hr, E_NOINTERFACE);
2673 EXPECT_REF(ptr->iface, 1);
2675 V_VT(&v) = VT_EMPTY;
2676 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2677 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2678 EXPECT_HR(hr, S_OK);
2679 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2680 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2682 ptr++;
2683 free_bstrs();
2686 ISAXXMLReader_Release(reader);
2688 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2689 return;
2691 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2692 &IID_ISAXXMLReader, (void**)&reader);
2693 EXPECT_HR(hr, S_OK);
2695 /* xmldecl-version property */
2696 V_VT(&v) = VT_EMPTY;
2697 V_BSTR(&v) = (void*)0xdeadbeef;
2698 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2699 EXPECT_HR(hr, S_OK);
2700 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2701 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2703 /* stream without declaration */
2704 V_VT(&v) = VT_BSTR;
2705 V_BSTR(&v) = _bstr_("<element></element>");
2706 hr = ISAXXMLReader_parse(reader, v);
2707 EXPECT_HR(hr, S_OK);
2709 V_VT(&v) = VT_EMPTY;
2710 V_BSTR(&v) = (void*)0xdeadbeef;
2711 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2712 EXPECT_HR(hr, S_OK);
2713 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2714 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2716 /* stream with declaration */
2717 V_VT(&v) = VT_BSTR;
2718 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2719 hr = ISAXXMLReader_parse(reader, v);
2720 EXPECT_HR(hr, S_OK);
2722 /* VT_BSTR|VT_BYREF input type */
2723 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2724 V_VT(&v) = VT_BSTR|VT_BYREF;
2725 V_BSTRREF(&v) = &str;
2726 hr = ISAXXMLReader_parse(reader, v);
2727 EXPECT_HR(hr, S_OK);
2729 V_VT(&v) = VT_EMPTY;
2730 V_BSTR(&v) = (void*)0xdeadbeef;
2731 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2732 EXPECT_HR(hr, S_OK);
2733 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2734 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2735 VariantClear(&v);
2737 ISAXXMLReader_Release(reader);
2738 free_bstrs();
2741 struct feature_ns_entry_t {
2742 const GUID *guid;
2743 const char *clsid;
2744 VARIANT_BOOL value;
2745 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2748 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2749 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2750 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2751 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2752 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2753 { 0 }
2756 static const char *feature_names[] = {
2757 "http://xml.org/sax/features/namespaces",
2758 "http://xml.org/sax/features/namespace-prefixes",
2762 static void test_saxreader_features(void)
2764 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2765 ISAXXMLReader *reader;
2767 while (entry->guid)
2769 VARIANT_BOOL value;
2770 const char **name;
2771 HRESULT hr;
2773 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2774 if (hr != S_OK)
2776 win_skip("can't create %s instance\n", entry->clsid);
2777 entry++;
2778 continue;
2781 name = feature_names;
2782 while (*name)
2784 value = 0xc;
2785 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2786 EXPECT_HR(hr, S_OK);
2787 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2789 value = 0xc;
2790 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2791 EXPECT_HR(hr, S_OK);
2793 value = 0xd;
2794 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2795 EXPECT_HR(hr, S_OK);
2796 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2798 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2799 EXPECT_HR(hr, S_OK);
2800 value = 0xd;
2801 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2802 EXPECT_HR(hr, S_OK);
2803 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2805 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2806 EXPECT_HR(hr, S_OK);
2807 value = 0xd;
2808 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2809 EXPECT_HR(hr, S_OK);
2810 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2812 name++;
2815 ISAXXMLReader_Release(reader);
2817 entry++;
2821 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2822 static const CHAR UTF8BOMTest[] =
2823 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2824 "<a></a>\n";
2826 struct enc_test_entry_t {
2827 const GUID *guid;
2828 const char *clsid;
2829 const char *data;
2830 HRESULT hr;
2831 BOOL todo;
2834 static const struct enc_test_entry_t encoding_test_data[] = {
2835 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE },
2836 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE },
2837 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE },
2838 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE },
2839 { 0 }
2842 static void test_saxreader_encoding(void)
2844 const struct enc_test_entry_t *entry = encoding_test_data;
2845 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2846 static const CHAR testXmlA[] = "test.xml";
2848 while (entry->guid)
2850 ISAXXMLReader *reader;
2851 VARIANT input;
2852 DWORD written;
2853 HANDLE file;
2854 HRESULT hr;
2856 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2857 if (hr != S_OK)
2859 win_skip("can't create %s instance\n", entry->clsid);
2860 entry++;
2861 continue;
2864 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2865 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2866 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2867 CloseHandle(file);
2869 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2870 if (entry->todo)
2871 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2872 else
2873 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2875 DeleteFileA(testXmlA);
2877 /* try BSTR input with no BOM or '<?xml' instruction */
2878 V_VT(&input) = VT_BSTR;
2879 V_BSTR(&input) = _bstr_("<element></element>");
2880 hr = ISAXXMLReader_parse(reader, input);
2881 EXPECT_HR(hr, S_OK);
2883 ISAXXMLReader_Release(reader);
2885 free_bstrs();
2886 entry++;
2890 static void test_mxwriter_handlers(void)
2892 IMXWriter *writer;
2893 HRESULT hr;
2894 int i;
2896 static const REFIID riids[] =
2898 &IID_ISAXContentHandler,
2899 &IID_ISAXLexicalHandler,
2900 &IID_ISAXDeclHandler,
2901 &IID_ISAXDTDHandler,
2902 &IID_ISAXErrorHandler,
2903 &IID_IVBSAXDeclHandler,
2904 &IID_IVBSAXLexicalHandler,
2905 &IID_IVBSAXContentHandler,
2906 &IID_IVBSAXDTDHandler,
2907 &IID_IVBSAXErrorHandler
2910 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2911 &IID_IMXWriter, (void**)&writer);
2912 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2914 EXPECT_REF(writer, 1);
2916 for (i = 0; i < sizeof(riids)/sizeof(REFIID); i++)
2918 IUnknown *handler;
2919 IMXWriter *writer2;
2921 /* handler from IMXWriter */
2922 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
2923 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2924 EXPECT_REF(writer, 2);
2925 EXPECT_REF(handler, 2);
2927 /* IMXWriter from a handler */
2928 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2929 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2930 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2931 EXPECT_REF(writer, 3);
2932 EXPECT_REF(writer2, 3);
2933 IMXWriter_Release(writer2);
2934 IUnknown_Release(handler);
2937 IMXWriter_Release(writer);
2940 static struct msxmlsupported_data_t mxwriter_support_data[] =
2942 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2943 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2944 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2945 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2946 { NULL }
2949 static struct msxmlsupported_data_t mxattributes_support_data[] =
2951 { &CLSID_SAXAttributes, "SAXAttributes" },
2952 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2953 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2954 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2955 { NULL }
2958 struct mxwriter_props_t
2960 const GUID *clsid;
2961 VARIANT_BOOL bom;
2962 VARIANT_BOOL disable_escape;
2963 VARIANT_BOOL indent;
2964 VARIANT_BOOL omitdecl;
2965 VARIANT_BOOL standalone;
2966 const char *encoding;
2969 static const struct mxwriter_props_t mxwriter_default_props[] =
2971 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2972 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2973 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2974 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2975 { NULL }
2978 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2980 int i = 0;
2982 while (table->clsid)
2984 IMXWriter *writer;
2985 VARIANT_BOOL b;
2986 BSTR encoding;
2987 HRESULT hr;
2989 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2991 table++;
2992 i++;
2993 continue;
2996 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2997 &IID_IMXWriter, (void**)&writer);
2998 EXPECT_HR(hr, S_OK);
3000 b = !table->bom;
3001 hr = IMXWriter_get_byteOrderMark(writer, &b);
3002 EXPECT_HR(hr, S_OK);
3003 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
3005 b = !table->disable_escape;
3006 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
3007 EXPECT_HR(hr, S_OK);
3008 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
3009 table->disable_escape);
3011 b = !table->indent;
3012 hr = IMXWriter_get_indent(writer, &b);
3013 EXPECT_HR(hr, S_OK);
3014 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
3016 b = !table->omitdecl;
3017 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
3018 EXPECT_HR(hr, S_OK);
3019 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
3021 b = !table->standalone;
3022 hr = IMXWriter_get_standalone(writer, &b);
3023 EXPECT_HR(hr, S_OK);
3024 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
3026 hr = IMXWriter_get_encoding(writer, &encoding);
3027 EXPECT_HR(hr, S_OK);
3028 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
3029 i, wine_dbgstr_w(encoding), table->encoding);
3030 SysFreeString(encoding);
3032 IMXWriter_Release(writer);
3034 table++;
3035 i++;
3039 static void test_mxwriter_properties(void)
3041 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
3042 static const WCHAR testW[] = {'t','e','s','t',0};
3043 ISAXContentHandler *content;
3044 IMXWriter *writer;
3045 VARIANT_BOOL b;
3046 HRESULT hr;
3047 BSTR str, str2;
3048 VARIANT dest;
3050 test_mxwriter_default_properties(mxwriter_default_props);
3052 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3053 &IID_IMXWriter, (void**)&writer);
3054 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3056 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
3057 ok(hr == E_POINTER, "got %08x\n", hr);
3059 hr = IMXWriter_get_byteOrderMark(writer, NULL);
3060 ok(hr == E_POINTER, "got %08x\n", hr);
3062 hr = IMXWriter_get_indent(writer, NULL);
3063 ok(hr == E_POINTER, "got %08x\n", hr);
3065 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
3066 ok(hr == E_POINTER, "got %08x\n", hr);
3068 hr = IMXWriter_get_standalone(writer, NULL);
3069 ok(hr == E_POINTER, "got %08x\n", hr);
3071 /* set and check */
3072 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
3073 ok(hr == S_OK, "got %08x\n", hr);
3075 b = VARIANT_FALSE;
3076 hr = IMXWriter_get_standalone(writer, &b);
3077 ok(hr == S_OK, "got %08x\n", hr);
3078 ok(b == VARIANT_TRUE, "got %d\n", b);
3080 hr = IMXWriter_get_encoding(writer, NULL);
3081 EXPECT_HR(hr, E_POINTER);
3083 /* UTF-16 is a default setting apparently */
3084 str = (void*)0xdeadbeef;
3085 hr = IMXWriter_get_encoding(writer, &str);
3086 EXPECT_HR(hr, S_OK);
3087 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
3089 str2 = (void*)0xdeadbeef;
3090 hr = IMXWriter_get_encoding(writer, &str2);
3091 ok(hr == S_OK, "got %08x\n", hr);
3092 ok(str != str2, "expected newly allocated, got same %p\n", str);
3094 SysFreeString(str2);
3095 SysFreeString(str);
3097 /* put empty string */
3098 str = SysAllocString(emptyW);
3099 hr = IMXWriter_put_encoding(writer, str);
3100 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3101 SysFreeString(str);
3103 str = (void*)0xdeadbeef;
3104 hr = IMXWriter_get_encoding(writer, &str);
3105 EXPECT_HR(hr, S_OK);
3106 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
3107 SysFreeString(str);
3109 /* invalid encoding name */
3110 str = SysAllocString(testW);
3111 hr = IMXWriter_put_encoding(writer, str);
3112 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3113 SysFreeString(str);
3115 /* test case sensivity */
3116 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
3117 EXPECT_HR(hr, S_OK);
3118 str = (void*)0xdeadbeef;
3119 hr = IMXWriter_get_encoding(writer, &str);
3120 EXPECT_HR(hr, S_OK);
3121 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
3122 SysFreeString(str);
3124 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
3125 EXPECT_HR(hr, S_OK);
3126 str = (void*)0xdeadbeef;
3127 hr = IMXWriter_get_encoding(writer, &str);
3128 EXPECT_HR(hr, S_OK);
3129 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
3130 SysFreeString(str);
3132 /* how it affects document creation */
3133 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3134 EXPECT_HR(hr, S_OK);
3136 hr = ISAXContentHandler_startDocument(content);
3137 EXPECT_HR(hr, S_OK);
3138 hr = ISAXContentHandler_endDocument(content);
3139 EXPECT_HR(hr, S_OK);
3141 V_VT(&dest) = VT_EMPTY;
3142 hr = IMXWriter_get_output(writer, &dest);
3143 EXPECT_HR(hr, S_OK);
3144 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3145 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
3146 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3147 VariantClear(&dest);
3148 ISAXContentHandler_Release(content);
3150 hr = IMXWriter_get_version(writer, NULL);
3151 ok(hr == E_POINTER, "got %08x\n", hr);
3152 /* default version is 'surprisingly' 1.0 */
3153 hr = IMXWriter_get_version(writer, &str);
3154 ok(hr == S_OK, "got %08x\n", hr);
3155 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3156 SysFreeString(str);
3158 /* store version string as is */
3159 hr = IMXWriter_put_version(writer, NULL);
3160 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3162 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3163 ok(hr == S_OK, "got %08x\n", hr);
3165 hr = IMXWriter_put_version(writer, _bstr_(""));
3166 ok(hr == S_OK, "got %08x\n", hr);
3167 hr = IMXWriter_get_version(writer, &str);
3168 ok(hr == S_OK, "got %08x\n", hr);
3169 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3170 SysFreeString(str);
3172 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3173 ok(hr == S_OK, "got %08x\n", hr);
3174 hr = IMXWriter_get_version(writer, &str);
3175 ok(hr == S_OK, "got %08x\n", hr);
3176 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3177 SysFreeString(str);
3179 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3180 ok(hr == S_OK, "got %08x\n", hr);
3181 hr = IMXWriter_get_version(writer, &str);
3182 ok(hr == S_OK, "got %08x\n", hr);
3183 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3184 SysFreeString(str);
3186 IMXWriter_Release(writer);
3187 free_bstrs();
3190 static void test_mxwriter_flush(void)
3192 ISAXContentHandler *content;
3193 IMXWriter *writer;
3194 LARGE_INTEGER pos;
3195 ULARGE_INTEGER pos2;
3196 IStream *stream;
3197 VARIANT dest;
3198 HRESULT hr;
3199 char *buff;
3200 LONG ref;
3201 int len;
3203 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3204 &IID_IMXWriter, (void**)&writer);
3205 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3207 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3208 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3209 EXPECT_REF(stream, 1);
3211 /* detach when nothing was attached */
3212 V_VT(&dest) = VT_EMPTY;
3213 hr = IMXWriter_put_output(writer, dest);
3214 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3216 /* attach stream */
3217 V_VT(&dest) = VT_UNKNOWN;
3218 V_UNKNOWN(&dest) = (IUnknown*)stream;
3219 hr = IMXWriter_put_output(writer, dest);
3220 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3221 todo_wine EXPECT_REF(stream, 3);
3223 /* detach setting VT_EMPTY destination */
3224 V_VT(&dest) = VT_EMPTY;
3225 hr = IMXWriter_put_output(writer, dest);
3226 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3227 EXPECT_REF(stream, 1);
3229 V_VT(&dest) = VT_UNKNOWN;
3230 V_UNKNOWN(&dest) = (IUnknown*)stream;
3231 hr = IMXWriter_put_output(writer, dest);
3232 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3234 /* flush() doesn't detach a stream */
3235 hr = IMXWriter_flush(writer);
3236 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3237 todo_wine EXPECT_REF(stream, 3);
3239 pos.QuadPart = 0;
3240 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3241 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3242 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3244 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3245 ok(hr == S_OK, "got %08x\n", hr);
3247 hr = ISAXContentHandler_startDocument(content);
3248 ok(hr == S_OK, "got %08x\n", hr);
3250 pos.QuadPart = 0;
3251 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3252 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3253 ok(pos2.QuadPart != 0, "expected stream beginning\n");
3255 /* already started */
3256 hr = ISAXContentHandler_startDocument(content);
3257 ok(hr == S_OK, "got %08x\n", hr);
3259 hr = ISAXContentHandler_endDocument(content);
3260 ok(hr == S_OK, "got %08x\n", hr);
3262 /* flushed on endDocument() */
3263 pos.QuadPart = 0;
3264 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3265 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3266 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3268 IStream_Release(stream);
3270 /* auto-flush feature */
3271 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3272 EXPECT_HR(hr, S_OK);
3273 EXPECT_REF(stream, 1);
3275 V_VT(&dest) = VT_UNKNOWN;
3276 V_UNKNOWN(&dest) = (IUnknown*)stream;
3277 hr = IMXWriter_put_output(writer, dest);
3278 EXPECT_HR(hr, S_OK);
3280 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
3281 EXPECT_HR(hr, S_OK);
3283 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3284 EXPECT_HR(hr, S_OK);
3286 hr = ISAXContentHandler_startDocument(content);
3287 EXPECT_HR(hr, S_OK);
3289 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3290 EXPECT_HR(hr, S_OK);
3292 /* internal buffer is flushed automatically on certain threshold */
3293 pos.QuadPart = 0;
3294 pos2.QuadPart = 1;
3295 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3296 EXPECT_HR(hr, S_OK);
3297 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3299 len = 2048;
3300 buff = HeapAlloc(GetProcessHeap(), 0, len+1);
3301 memset(buff, 'A', len);
3302 buff[len] = 0;
3303 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3304 EXPECT_HR(hr, S_OK);
3306 pos.QuadPart = 0;
3307 pos2.QuadPart = 0;
3308 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3309 EXPECT_HR(hr, S_OK);
3310 todo_wine
3311 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
3313 hr = IMXWriter_get_output(writer, NULL);
3314 EXPECT_HR(hr, E_POINTER);
3316 ref = get_refcount(stream);
3317 V_VT(&dest) = VT_EMPTY;
3318 hr = IMXWriter_get_output(writer, &dest);
3319 EXPECT_HR(hr, S_OK);
3320 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3321 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3322 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3323 VariantClear(&dest);
3325 hr = ISAXContentHandler_endDocument(content);
3326 EXPECT_HR(hr, S_OK);
3328 IStream_Release(stream);
3330 /* test char count lower than threshold */
3331 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3332 EXPECT_HR(hr, S_OK);
3333 EXPECT_REF(stream, 1);
3335 hr = ISAXContentHandler_startDocument(content);
3336 EXPECT_HR(hr, S_OK);
3338 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3339 EXPECT_HR(hr, S_OK);
3341 pos.QuadPart = 0;
3342 pos2.QuadPart = 1;
3343 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3344 EXPECT_HR(hr, S_OK);
3345 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3347 memset(buff, 'A', len);
3348 buff[len] = 0;
3349 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3350 EXPECT_HR(hr, S_OK);
3352 pos.QuadPart = 0;
3353 pos2.QuadPart = 1;
3354 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3355 EXPECT_HR(hr, S_OK);
3356 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3358 hr = ISAXContentHandler_endDocument(content);
3359 EXPECT_HR(hr, S_OK);
3361 /* test auto-flush function when stream is not set */
3362 V_VT(&dest) = VT_EMPTY;
3363 hr = IMXWriter_put_output(writer, dest);
3364 EXPECT_HR(hr, S_OK);
3366 hr = ISAXContentHandler_startDocument(content);
3367 EXPECT_HR(hr, S_OK);
3369 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3370 EXPECT_HR(hr, S_OK);
3372 memset(buff, 'A', len);
3373 buff[len] = 0;
3374 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3375 EXPECT_HR(hr, S_OK);
3377 V_VT(&dest) = VT_EMPTY;
3378 hr = IMXWriter_get_output(writer, &dest);
3379 EXPECT_HR(hr, S_OK);
3380 len += strlen("<a>");
3381 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3382 VariantClear(&dest);
3384 HeapFree(GetProcessHeap(), 0, buff);
3385 ISAXContentHandler_Release(content);
3386 IStream_Release(stream);
3387 IMXWriter_Release(writer);
3388 free_bstrs();
3391 static void test_mxwriter_startenddocument(void)
3393 ISAXContentHandler *content;
3394 IMXWriter *writer;
3395 VARIANT dest;
3396 HRESULT hr;
3398 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3399 &IID_IMXWriter, (void**)&writer);
3400 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3402 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3403 ok(hr == S_OK, "got %08x\n", hr);
3405 hr = ISAXContentHandler_startDocument(content);
3406 ok(hr == S_OK, "got %08x\n", hr);
3408 hr = ISAXContentHandler_endDocument(content);
3409 ok(hr == S_OK, "got %08x\n", hr);
3411 V_VT(&dest) = VT_EMPTY;
3412 hr = IMXWriter_get_output(writer, &dest);
3413 ok(hr == S_OK, "got %08x\n", hr);
3414 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3415 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3416 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3417 VariantClear(&dest);
3419 /* now try another startDocument */
3420 hr = ISAXContentHandler_startDocument(content);
3421 ok(hr == S_OK, "got %08x\n", hr);
3422 /* and get duplicated prolog */
3423 V_VT(&dest) = VT_EMPTY;
3424 hr = IMXWriter_get_output(writer, &dest);
3425 ok(hr == S_OK, "got %08x\n", hr);
3426 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3427 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3428 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3429 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3430 VariantClear(&dest);
3432 ISAXContentHandler_Release(content);
3433 IMXWriter_Release(writer);
3435 /* now with omitted declaration */
3436 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3437 &IID_IMXWriter, (void**)&writer);
3438 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3440 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3441 ok(hr == S_OK, "got %08x\n", hr);
3443 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3444 ok(hr == S_OK, "got %08x\n", hr);
3446 hr = ISAXContentHandler_startDocument(content);
3447 ok(hr == S_OK, "got %08x\n", hr);
3449 hr = ISAXContentHandler_endDocument(content);
3450 ok(hr == S_OK, "got %08x\n", hr);
3452 V_VT(&dest) = VT_EMPTY;
3453 hr = IMXWriter_get_output(writer, &dest);
3454 ok(hr == S_OK, "got %08x\n", hr);
3455 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3456 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3457 VariantClear(&dest);
3459 ISAXContentHandler_Release(content);
3460 IMXWriter_Release(writer);
3462 free_bstrs();
3465 enum startendtype
3467 StartElement = 0x001,
3468 EndElement = 0x010,
3469 StartEndElement = 0x011,
3470 DisableEscaping = 0x100
3473 struct writer_startendelement_t {
3474 const GUID *clsid;
3475 enum startendtype type;
3476 const char *uri;
3477 const char *local_name;
3478 const char *qname;
3479 const char *output;
3480 HRESULT hr;
3481 ISAXAttributes *attr;
3484 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\">";
3485 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\"/>";
3486 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\'\"/>";
3488 static const struct writer_startendelement_t writer_startendelement[] = {
3489 /* 0 */
3490 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3491 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3492 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3493 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3494 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3495 /* 5 */
3496 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3497 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3498 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3499 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3500 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3501 /* 10 */
3502 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3503 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3504 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3505 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3506 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3507 /* 15 */
3508 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3509 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3510 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3511 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3512 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3513 /* 20 */
3514 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3515 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3516 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3517 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3518 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3519 /* 25 */
3520 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3521 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3522 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3523 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3524 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3525 /* 30 */
3526 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3527 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3528 /* endElement tests */
3529 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3530 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3531 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3532 /* 35 */
3533 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3534 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3535 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3536 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3537 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3538 /* 40 */
3539 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3540 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3541 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3542 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3543 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3544 /* 45 */
3545 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3546 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3547 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3548 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3549 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3550 /* 50 */
3551 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3552 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3553 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3554 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3555 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3556 /* 55 */
3557 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3558 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3559 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3560 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3561 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3562 /* 60 */
3563 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3564 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3565 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3566 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3568 /* with attributes */
3569 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3570 /* 65 */
3571 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3572 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3573 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3574 /* empty elements */
3575 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3576 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3577 /* 70 */
3578 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3579 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3580 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3581 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3582 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3583 /* 75 */
3584 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3586 /* with disabled output escaping */
3587 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3588 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3589 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3590 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3592 { NULL }
3595 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3597 while (table->clsid)
3599 IUnknown *unk;
3600 HRESULT hr;
3602 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3603 if (hr == S_OK) IUnknown_Release(unk);
3605 table->supported = hr == S_OK;
3606 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3608 table++;
3612 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3614 int i = 0;
3616 while (table->clsid)
3618 ISAXContentHandler *content;
3619 IMXWriter *writer;
3620 HRESULT hr;
3622 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3624 table++;
3625 i++;
3626 continue;
3629 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3630 &IID_IMXWriter, (void**)&writer);
3631 EXPECT_HR(hr, S_OK);
3633 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3634 EXPECT_HR(hr, S_OK);
3636 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3637 EXPECT_HR(hr, S_OK);
3639 hr = ISAXContentHandler_startDocument(content);
3640 EXPECT_HR(hr, S_OK);
3642 if (table->type & DisableEscaping)
3644 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3645 EXPECT_HR(hr, S_OK);
3648 if (table->type & StartElement)
3650 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3651 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3652 table->qname ? strlen(table->qname) : 0, table->attr);
3653 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3656 if (table->type & EndElement)
3658 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3659 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3660 table->qname ? strlen(table->qname) : 0);
3661 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3664 /* test output */
3665 if (hr == S_OK)
3667 VARIANT dest;
3669 V_VT(&dest) = VT_EMPTY;
3670 hr = IMXWriter_get_output(writer, &dest);
3671 EXPECT_HR(hr, S_OK);
3672 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3673 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3674 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3675 VariantClear(&dest);
3678 ISAXContentHandler_Release(content);
3679 IMXWriter_Release(writer);
3681 table++;
3682 i++;
3685 free_bstrs();
3688 /* point of these test is to start/end element with different names and name lengths */
3689 struct writer_startendelement2_t {
3690 const GUID *clsid;
3691 const char *qnamestart;
3692 int qnamestart_len;
3693 const char *qnameend;
3694 int qnameend_len;
3695 const char *output;
3696 HRESULT hr;
3699 static const struct writer_startendelement2_t writer_startendelement2[] = {
3700 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3701 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3702 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3703 /* -1 length is not allowed for version 6 */
3704 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3706 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3707 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3708 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3709 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3710 { NULL }
3713 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3715 int i = 0;
3717 while (table->clsid)
3719 ISAXContentHandler *content;
3720 IMXWriter *writer;
3721 HRESULT hr;
3723 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3725 table++;
3726 i++;
3727 continue;
3730 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3731 &IID_IMXWriter, (void**)&writer);
3732 EXPECT_HR(hr, S_OK);
3734 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3735 EXPECT_HR(hr, S_OK);
3737 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3738 EXPECT_HR(hr, S_OK);
3740 hr = ISAXContentHandler_startDocument(content);
3741 EXPECT_HR(hr, S_OK);
3743 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3744 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3745 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3747 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3748 _bstr_(table->qnameend), table->qnameend_len);
3749 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3751 /* test output */
3752 if (hr == S_OK)
3754 VARIANT dest;
3756 V_VT(&dest) = VT_EMPTY;
3757 hr = IMXWriter_get_output(writer, &dest);
3758 EXPECT_HR(hr, S_OK);
3759 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3760 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3761 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3762 VariantClear(&dest);
3765 ISAXContentHandler_Release(content);
3766 IMXWriter_Release(writer);
3768 table++;
3769 i++;
3771 free_bstrs();
3776 static void test_mxwriter_startendelement(void)
3778 ISAXContentHandler *content;
3779 IMXWriter *writer;
3780 VARIANT dest;
3781 HRESULT hr;
3783 test_mxwriter_startendelement_batch(writer_startendelement);
3784 test_mxwriter_startendelement_batch2(writer_startendelement2);
3786 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3787 &IID_IMXWriter, (void**)&writer);
3788 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3790 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3791 ok(hr == S_OK, "got %08x\n", hr);
3793 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3794 ok(hr == S_OK, "got %08x\n", hr);
3796 hr = ISAXContentHandler_startDocument(content);
3797 ok(hr == S_OK, "got %08x\n", hr);
3799 /* all string pointers should be not null */
3800 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3801 ok(hr == S_OK, "got %08x\n", hr);
3803 V_VT(&dest) = VT_EMPTY;
3804 hr = IMXWriter_get_output(writer, &dest);
3805 ok(hr == S_OK, "got %08x\n", hr);
3806 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3807 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3808 VariantClear(&dest);
3810 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3811 ok(hr == S_OK, "got %08x\n", hr);
3813 V_VT(&dest) = VT_EMPTY;
3814 hr = IMXWriter_get_output(writer, &dest);
3815 ok(hr == S_OK, "got %08x\n", hr);
3816 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3817 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3818 VariantClear(&dest);
3820 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3821 EXPECT_HR(hr, E_INVALIDARG);
3823 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3824 EXPECT_HR(hr, E_INVALIDARG);
3826 /* only local name is an error too */
3827 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3828 EXPECT_HR(hr, E_INVALIDARG);
3830 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3831 EXPECT_HR(hr, S_OK);
3833 V_VT(&dest) = VT_EMPTY;
3834 hr = IMXWriter_get_output(writer, &dest);
3835 EXPECT_HR(hr, S_OK);
3836 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3837 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3838 VariantClear(&dest);
3840 hr = ISAXContentHandler_endDocument(content);
3841 EXPECT_HR(hr, S_OK);
3843 V_VT(&dest) = VT_EMPTY;
3844 hr = IMXWriter_put_output(writer, dest);
3845 EXPECT_HR(hr, S_OK);
3847 V_VT(&dest) = VT_EMPTY;
3848 hr = IMXWriter_get_output(writer, &dest);
3849 EXPECT_HR(hr, S_OK);
3850 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3851 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3852 VariantClear(&dest);
3854 hr = ISAXContentHandler_startDocument(content);
3855 EXPECT_HR(hr, S_OK);
3857 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3858 EXPECT_HR(hr, S_OK);
3860 V_VT(&dest) = VT_EMPTY;
3861 hr = IMXWriter_get_output(writer, &dest);
3862 EXPECT_HR(hr, S_OK);
3863 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3864 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3865 VariantClear(&dest);
3867 hr = ISAXContentHandler_endDocument(content);
3868 EXPECT_HR(hr, S_OK);
3869 IMXWriter_flush(writer);
3871 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3872 EXPECT_HR(hr, S_OK);
3873 V_VT(&dest) = VT_EMPTY;
3874 hr = IMXWriter_get_output(writer, &dest);
3875 EXPECT_HR(hr, S_OK);
3876 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3877 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3878 VariantClear(&dest);
3880 V_VT(&dest) = VT_EMPTY;
3881 hr = IMXWriter_put_output(writer, dest);
3882 EXPECT_HR(hr, S_OK);
3884 /* length -1 */
3885 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3886 EXPECT_HR(hr, S_OK);
3887 V_VT(&dest) = VT_EMPTY;
3888 hr = IMXWriter_get_output(writer, &dest);
3889 EXPECT_HR(hr, S_OK);
3890 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3891 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3892 VariantClear(&dest);
3894 ISAXContentHandler_Release(content);
3895 IMXWriter_Release(writer);
3896 free_bstrs();
3899 struct writer_characters_t {
3900 const GUID *clsid;
3901 const char *data;
3902 const char *output;
3905 static const struct writer_characters_t writer_characters[] = {
3906 { &CLSID_MXXMLWriter, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3907 { &CLSID_MXXMLWriter30, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3908 { &CLSID_MXXMLWriter40, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3909 { &CLSID_MXXMLWriter60, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3910 { NULL }
3913 static void test_mxwriter_characters(void)
3915 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3916 const struct writer_characters_t *table = writer_characters;
3917 ISAXContentHandler *content;
3918 IMXWriter *writer;
3919 VARIANT dest;
3920 HRESULT hr;
3921 int i = 0;
3923 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3924 &IID_IMXWriter, (void**)&writer);
3925 EXPECT_HR(hr, S_OK);
3927 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3928 EXPECT_HR(hr, S_OK);
3930 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3931 EXPECT_HR(hr, S_OK);
3933 hr = ISAXContentHandler_startDocument(content);
3934 EXPECT_HR(hr, S_OK);
3936 hr = ISAXContentHandler_characters(content, NULL, 0);
3937 EXPECT_HR(hr, E_INVALIDARG);
3939 hr = ISAXContentHandler_characters(content, chardataW, 0);
3940 EXPECT_HR(hr, S_OK);
3942 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3943 EXPECT_HR(hr, S_OK);
3945 V_VT(&dest) = VT_EMPTY;
3946 hr = IMXWriter_get_output(writer, &dest);
3947 EXPECT_HR(hr, S_OK);
3948 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3949 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3950 VariantClear(&dest);
3952 hr = ISAXContentHandler_endDocument(content);
3953 EXPECT_HR(hr, S_OK);
3955 ISAXContentHandler_Release(content);
3956 IMXWriter_Release(writer);
3958 /* try empty characters data to see if element is closed */
3959 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3960 &IID_IMXWriter, (void**)&writer);
3961 EXPECT_HR(hr, S_OK);
3963 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3964 EXPECT_HR(hr, S_OK);
3966 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3967 EXPECT_HR(hr, S_OK);
3969 hr = ISAXContentHandler_startDocument(content);
3970 EXPECT_HR(hr, S_OK);
3972 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3973 EXPECT_HR(hr, S_OK);
3975 hr = ISAXContentHandler_characters(content, chardataW, 0);
3976 EXPECT_HR(hr, S_OK);
3978 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3979 EXPECT_HR(hr, S_OK);
3981 V_VT(&dest) = VT_EMPTY;
3982 hr = IMXWriter_get_output(writer, &dest);
3983 EXPECT_HR(hr, S_OK);
3984 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3985 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3986 VariantClear(&dest);
3988 ISAXContentHandler_Release(content);
3989 IMXWriter_Release(writer);
3991 /* batch tests */
3992 while (table->clsid)
3994 ISAXContentHandler *content;
3995 IMXWriter *writer;
3996 VARIANT dest;
3997 HRESULT hr;
3999 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
4001 table++;
4002 i++;
4003 continue;
4006 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4007 &IID_IMXWriter, (void**)&writer);
4008 EXPECT_HR(hr, S_OK);
4010 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4011 EXPECT_HR(hr, S_OK);
4013 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4014 EXPECT_HR(hr, S_OK);
4016 hr = ISAXContentHandler_startDocument(content);
4017 EXPECT_HR(hr, S_OK);
4019 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4020 EXPECT_HR(hr, S_OK);
4022 /* test output */
4023 if (hr == S_OK)
4025 V_VT(&dest) = VT_EMPTY;
4026 hr = IMXWriter_get_output(writer, &dest);
4027 EXPECT_HR(hr, S_OK);
4028 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4029 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
4030 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
4031 VariantClear(&dest);
4034 /* with disabled escaping */
4035 V_VT(&dest) = VT_EMPTY;
4036 hr = IMXWriter_put_output(writer, dest);
4037 EXPECT_HR(hr, S_OK);
4039 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
4040 EXPECT_HR(hr, S_OK);
4042 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4043 EXPECT_HR(hr, S_OK);
4045 /* test output */
4046 if (hr == S_OK)
4048 V_VT(&dest) = VT_EMPTY;
4049 hr = IMXWriter_get_output(writer, &dest);
4050 EXPECT_HR(hr, S_OK);
4051 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4052 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
4053 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
4054 VariantClear(&dest);
4057 ISAXContentHandler_Release(content);
4058 IMXWriter_Release(writer);
4060 table++;
4061 i++;
4064 free_bstrs();
4067 static const mxwriter_stream_test mxwriter_stream_tests[] = {
4069 VARIANT_TRUE,"UTF-16",
4071 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4072 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4073 {TRUE}
4077 VARIANT_FALSE,"UTF-16",
4079 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4080 {TRUE}
4084 VARIANT_TRUE,"UTF-8",
4086 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
4087 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4088 * and the writer is released.
4090 {FALSE,NULL,0},
4091 {TRUE}
4095 VARIANT_TRUE,"utf-8",
4097 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
4098 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4099 * and the writer is released.
4101 {FALSE,NULL,0},
4102 {TRUE}
4106 VARIANT_TRUE,"UTF-16",
4108 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4109 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4110 {TRUE}
4114 VARIANT_TRUE,"UTF-16",
4116 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
4117 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4118 {TRUE}
4123 static void test_mxwriter_stream(void)
4125 IMXWriter *writer;
4126 ISAXContentHandler *content;
4127 HRESULT hr;
4128 VARIANT dest;
4129 IStream *stream;
4130 LARGE_INTEGER pos;
4131 ULARGE_INTEGER pos2;
4132 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
4134 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
4135 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
4137 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4138 &IID_IMXWriter, (void**)&writer);
4139 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4141 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4142 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4144 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
4145 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
4147 V_VT(&dest) = VT_UNKNOWN;
4148 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
4149 hr = IMXWriter_put_output(writer, dest);
4150 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
4151 VariantClear(&dest);
4153 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
4154 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
4156 current_write_test = test->expected_writes;
4158 hr = ISAXContentHandler_startDocument(content);
4159 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4161 hr = ISAXContentHandler_endDocument(content);
4162 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4164 ISAXContentHandler_Release(content);
4165 IMXWriter_Release(writer);
4167 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
4168 (int)(current_write_test-test->expected_writes), current_stream_test_index);
4171 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4172 &IID_IMXWriter, (void**)&writer);
4173 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4175 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4176 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
4178 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4179 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4181 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4182 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
4184 V_VT(&dest) = VT_UNKNOWN;
4185 V_UNKNOWN(&dest) = (IUnknown*)stream;
4186 hr = IMXWriter_put_output(writer, dest);
4187 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4189 hr = ISAXContentHandler_startDocument(content);
4190 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4192 /* Setting output of the mxwriter causes the current output to be flushed,
4193 * and the writer to start over.
4195 V_VT(&dest) = VT_EMPTY;
4196 hr = IMXWriter_put_output(writer, dest);
4197 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4199 pos.QuadPart = 0;
4200 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4201 ok(hr == S_OK, "Seek failed: %08x\n", hr);
4202 ok(pos2.QuadPart != 0, "expected stream position moved\n");
4204 hr = ISAXContentHandler_startDocument(content);
4205 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4207 hr = ISAXContentHandler_endDocument(content);
4208 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
4210 V_VT(&dest) = VT_EMPTY;
4211 hr = IMXWriter_get_output(writer, &dest);
4212 ok(hr == S_OK, "get_output failed: %08x\n", hr);
4213 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4214 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4215 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4216 VariantClear(&dest);
4218 /* test when BOM is written to output stream */
4219 V_VT(&dest) = VT_EMPTY;
4220 hr = IMXWriter_put_output(writer, dest);
4221 EXPECT_HR(hr, S_OK);
4223 pos.QuadPart = 0;
4224 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
4225 EXPECT_HR(hr, S_OK);
4227 V_VT(&dest) = VT_UNKNOWN;
4228 V_UNKNOWN(&dest) = (IUnknown*)stream;
4229 hr = IMXWriter_put_output(writer, dest);
4230 EXPECT_HR(hr, S_OK);
4232 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
4233 EXPECT_HR(hr, S_OK);
4235 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4236 EXPECT_HR(hr, S_OK);
4238 hr = ISAXContentHandler_startDocument(content);
4239 EXPECT_HR(hr, S_OK);
4241 pos.QuadPart = 0;
4242 pos2.QuadPart = 0;
4243 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4244 EXPECT_HR(hr, S_OK);
4245 ok(pos2.QuadPart == 2, "got wrong position\n");
4247 ISAXContentHandler_Release(content);
4248 IMXWriter_Release(writer);
4250 free_bstrs();
4253 static const char *encoding_names[] = {
4254 "iso-8859-1",
4255 "iso-8859-2",
4256 "iso-8859-3",
4257 "iso-8859-4",
4258 "iso-8859-5",
4259 "iso-8859-7",
4260 "iso-8859-9",
4261 "iso-8859-13",
4262 "iso-8859-15",
4263 NULL
4266 static void test_mxwriter_encoding(void)
4268 ISAXContentHandler *content;
4269 IMXWriter *writer;
4270 IStream *stream;
4271 const char *enc;
4272 VARIANT dest;
4273 HRESULT hr;
4274 HGLOBAL g;
4275 char *ptr;
4276 BSTR s;
4277 int i;
4279 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4280 &IID_IMXWriter, (void**)&writer);
4281 EXPECT_HR(hr, S_OK);
4283 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4284 EXPECT_HR(hr, S_OK);
4286 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4287 EXPECT_HR(hr, S_OK);
4289 hr = ISAXContentHandler_startDocument(content);
4290 EXPECT_HR(hr, S_OK);
4292 hr = ISAXContentHandler_endDocument(content);
4293 EXPECT_HR(hr, S_OK);
4295 /* The content is always re-encoded to UTF-16 when the output is
4296 * retrieved as a BSTR.
4298 V_VT(&dest) = VT_EMPTY;
4299 hr = IMXWriter_get_output(writer, &dest);
4300 EXPECT_HR(hr, S_OK);
4301 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4302 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4303 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4304 VariantClear(&dest);
4306 /* switch encoding when something is written already */
4307 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4308 EXPECT_HR(hr, S_OK);
4310 V_VT(&dest) = VT_UNKNOWN;
4311 V_UNKNOWN(&dest) = (IUnknown*)stream;
4312 hr = IMXWriter_put_output(writer, dest);
4313 EXPECT_HR(hr, S_OK);
4315 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4316 EXPECT_HR(hr, S_OK);
4318 /* write empty element */
4319 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
4320 EXPECT_HR(hr, S_OK);
4322 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
4323 EXPECT_HR(hr, S_OK);
4325 /* switch */
4326 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4327 EXPECT_HR(hr, S_OK);
4329 hr = IMXWriter_flush(writer);
4330 EXPECT_HR(hr, S_OK);
4332 hr = GetHGlobalFromStream(stream, &g);
4333 EXPECT_HR(hr, S_OK);
4335 ptr = GlobalLock(g);
4336 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4337 GlobalUnlock(g);
4339 /* so output is unaffected, encoding name is stored however */
4340 hr = IMXWriter_get_encoding(writer, &s);
4341 EXPECT_HR(hr, S_OK);
4342 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4343 SysFreeString(s);
4345 IStream_Release(stream);
4347 i = 0;
4348 enc = encoding_names[i];
4349 while (enc)
4351 char expectedA[200];
4353 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4354 EXPECT_HR(hr, S_OK);
4356 V_VT(&dest) = VT_UNKNOWN;
4357 V_UNKNOWN(&dest) = (IUnknown*)stream;
4358 hr = IMXWriter_put_output(writer, dest);
4359 EXPECT_HR(hr, S_OK);
4361 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4362 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4363 "%s: encoding not accepted\n", enc);
4364 if (hr != S_OK)
4366 enc = encoding_names[++i];
4367 IStream_Release(stream);
4368 continue;
4371 hr = ISAXContentHandler_startDocument(content);
4372 EXPECT_HR(hr, S_OK);
4374 hr = ISAXContentHandler_endDocument(content);
4375 EXPECT_HR(hr, S_OK);
4377 hr = IMXWriter_flush(writer);
4378 EXPECT_HR(hr, S_OK);
4380 /* prepare expected string */
4381 *expectedA = 0;
4382 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4383 strcat(expectedA, enc);
4384 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4386 hr = GetHGlobalFromStream(stream, &g);
4387 EXPECT_HR(hr, S_OK);
4389 ptr = GlobalLock(g);
4390 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4391 GlobalUnlock(g);
4393 V_VT(&dest) = VT_EMPTY;
4394 hr = IMXWriter_put_output(writer, dest);
4395 EXPECT_HR(hr, S_OK);
4397 IStream_Release(stream);
4399 enc = encoding_names[++i];
4402 ISAXContentHandler_Release(content);
4403 IMXWriter_Release(writer);
4405 free_bstrs();
4408 static void test_obj_dispex(IUnknown *obj)
4410 static const WCHAR testW[] = {'t','e','s','t','p','r','o','p',0};
4411 static const WCHAR starW[] = {'*',0};
4412 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4413 IDispatchEx *dispex;
4414 IUnknown *unk;
4415 DWORD props;
4416 UINT ticnt;
4417 HRESULT hr;
4418 BSTR name;
4419 DISPID did;
4421 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4422 EXPECT_HR(hr, S_OK);
4423 if (FAILED(hr)) return;
4425 ticnt = 0;
4426 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4427 EXPECT_HR(hr, S_OK);
4428 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4430 name = SysAllocString(starW);
4431 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4432 EXPECT_HR(hr, E_NOTIMPL);
4433 SysFreeString(name);
4435 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4436 EXPECT_HR(hr, E_NOTIMPL);
4438 props = 0;
4439 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4440 EXPECT_HR(hr, E_NOTIMPL);
4441 ok(props == 0, "expected 0 got %d\n", props);
4443 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4444 EXPECT_HR(hr, E_NOTIMPL);
4445 if (SUCCEEDED(hr)) SysFreeString(name);
4447 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4448 EXPECT_HR(hr, E_NOTIMPL);
4450 unk = (IUnknown*)0xdeadbeef;
4451 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4452 EXPECT_HR(hr, E_NOTIMPL);
4453 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk);
4455 name = SysAllocString(testW);
4456 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did);
4457 ok(hr == DISP_E_UNKNOWNNAME, "got 0x%08x\n", hr);
4458 SysFreeString(name);
4460 IDispatchEx_Release(dispex);
4463 static void test_saxreader_dispex(void)
4465 IVBSAXXMLReader *vbreader;
4466 ISAXXMLReader *reader;
4467 DISPPARAMS dispparams;
4468 DISPID dispid;
4469 IUnknown *unk;
4470 VARIANT arg;
4471 HRESULT hr;
4473 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4474 &IID_ISAXXMLReader, (void**)&reader);
4475 EXPECT_HR(hr, S_OK);
4477 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4478 EXPECT_HR(hr, S_OK);
4479 test_obj_dispex(unk);
4480 IUnknown_Release(unk);
4482 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4483 EXPECT_HR(hr, S_OK);
4484 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4485 EXPECT_HR(hr, S_OK);
4486 test_obj_dispex(unk);
4487 IUnknown_Release(unk);
4489 dispid = DISPID_PROPERTYPUT;
4490 dispparams.cArgs = 1;
4491 dispparams.cNamedArgs = 1;
4492 dispparams.rgdispidNamedArgs = &dispid;
4493 dispparams.rgvarg = &arg;
4495 V_VT(&arg) = VT_DISPATCH;
4496 V_DISPATCH(&arg) = NULL;
4498 /* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */
4499 hr = IVBSAXXMLReader_Invoke(vbreader,
4500 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4501 &IID_NULL,
4503 DISPATCH_PROPERTYPUT,
4504 &dispparams,
4505 NULL,
4506 NULL,
4507 NULL);
4508 ok(hr == S_OK, "got 0x%08x\n", hr);
4510 hr = IVBSAXXMLReader_Invoke(vbreader,
4511 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4512 &IID_NULL,
4514 DISPATCH_PROPERTYPUTREF,
4515 &dispparams,
4516 NULL,
4517 NULL,
4518 NULL);
4519 ok(hr == S_OK, "got 0x%08x\n", hr);
4521 IVBSAXXMLReader_Release(vbreader);
4522 ISAXXMLReader_Release(reader);
4524 if (is_clsid_supported(&CLSID_SAXXMLReader60, reader_support_data))
4526 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4527 ok(hr == S_OK, "got 0x%08x\n", hr);
4528 test_obj_dispex(unk);
4529 IUnknown_Release(unk);
4533 static void test_mxwriter_dispex(void)
4535 IDispatchEx *dispex;
4536 IMXWriter *writer;
4537 IUnknown *unk;
4538 HRESULT hr;
4540 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4541 &IID_IMXWriter, (void**)&writer);
4542 EXPECT_HR(hr, S_OK);
4544 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4545 EXPECT_HR(hr, S_OK);
4546 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4547 test_obj_dispex(unk);
4548 IUnknown_Release(unk);
4549 IDispatchEx_Release(dispex);
4550 IMXWriter_Release(writer);
4552 if (is_clsid_supported(&CLSID_MXXMLWriter60, mxwriter_support_data))
4554 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4555 ok(hr == S_OK, "got 0x%08x\n", hr);
4556 test_obj_dispex(unk);
4557 IUnknown_Release(unk);
4561 static void test_mxwriter_comment(void)
4563 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4564 IVBSAXLexicalHandler *vblexical;
4565 ISAXContentHandler *content;
4566 ISAXLexicalHandler *lexical;
4567 IMXWriter *writer;
4568 VARIANT dest;
4569 HRESULT hr;
4571 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4572 &IID_IMXWriter, (void**)&writer);
4573 EXPECT_HR(hr, S_OK);
4575 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4576 EXPECT_HR(hr, S_OK);
4578 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4579 EXPECT_HR(hr, S_OK);
4581 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4582 EXPECT_HR(hr, S_OK);
4584 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4585 EXPECT_HR(hr, S_OK);
4587 hr = ISAXContentHandler_startDocument(content);
4588 EXPECT_HR(hr, S_OK);
4590 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4591 EXPECT_HR(hr, E_INVALIDARG);
4593 hr = IVBSAXLexicalHandler_comment(vblexical, NULL);
4594 EXPECT_HR(hr, E_POINTER);
4596 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4597 EXPECT_HR(hr, S_OK);
4599 V_VT(&dest) = VT_EMPTY;
4600 hr = IMXWriter_get_output(writer, &dest);
4601 EXPECT_HR(hr, S_OK);
4602 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4603 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4604 VariantClear(&dest);
4606 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4607 EXPECT_HR(hr, S_OK);
4609 V_VT(&dest) = VT_EMPTY;
4610 hr = IMXWriter_get_output(writer, &dest);
4611 EXPECT_HR(hr, S_OK);
4612 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4613 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4614 VariantClear(&dest);
4616 ISAXContentHandler_Release(content);
4617 ISAXLexicalHandler_Release(lexical);
4618 IVBSAXLexicalHandler_Release(vblexical);
4619 IMXWriter_Release(writer);
4620 free_bstrs();
4623 static void test_mxwriter_cdata(void)
4625 IVBSAXLexicalHandler *vblexical;
4626 ISAXContentHandler *content;
4627 ISAXLexicalHandler *lexical;
4628 IMXWriter *writer;
4629 VARIANT dest;
4630 HRESULT hr;
4632 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4633 &IID_IMXWriter, (void**)&writer);
4634 EXPECT_HR(hr, S_OK);
4636 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4637 EXPECT_HR(hr, S_OK);
4639 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4640 EXPECT_HR(hr, S_OK);
4642 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4643 EXPECT_HR(hr, S_OK);
4645 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4646 EXPECT_HR(hr, S_OK);
4648 hr = ISAXContentHandler_startDocument(content);
4649 EXPECT_HR(hr, S_OK);
4651 hr = ISAXLexicalHandler_startCDATA(lexical);
4652 EXPECT_HR(hr, S_OK);
4654 V_VT(&dest) = VT_EMPTY;
4655 hr = IMXWriter_get_output(writer, &dest);
4656 EXPECT_HR(hr, S_OK);
4657 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4658 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4659 VariantClear(&dest);
4661 hr = IVBSAXLexicalHandler_startCDATA(vblexical);
4662 EXPECT_HR(hr, S_OK);
4664 /* all these are escaped for text nodes */
4665 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4666 EXPECT_HR(hr, S_OK);
4668 hr = ISAXLexicalHandler_endCDATA(lexical);
4669 EXPECT_HR(hr, S_OK);
4671 V_VT(&dest) = VT_EMPTY;
4672 hr = IMXWriter_get_output(writer, &dest);
4673 EXPECT_HR(hr, S_OK);
4674 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4675 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4676 VariantClear(&dest);
4678 ISAXContentHandler_Release(content);
4679 ISAXLexicalHandler_Release(lexical);
4680 IVBSAXLexicalHandler_Release(vblexical);
4681 IMXWriter_Release(writer);
4682 free_bstrs();
4685 static void test_mxwriter_pi(void)
4687 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4688 static const WCHAR dataW[] = {'d','a','t','a',0};
4689 ISAXContentHandler *content;
4690 IMXWriter *writer;
4691 VARIANT dest;
4692 HRESULT hr;
4694 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4695 &IID_IMXWriter, (void**)&writer);
4696 EXPECT_HR(hr, S_OK);
4698 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4699 EXPECT_HR(hr, S_OK);
4701 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4702 EXPECT_HR(hr, E_INVALIDARG);
4704 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4705 EXPECT_HR(hr, S_OK);
4707 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4708 EXPECT_HR(hr, S_OK);
4710 V_VT(&dest) = VT_EMPTY;
4711 hr = IMXWriter_get_output(writer, &dest);
4712 EXPECT_HR(hr, S_OK);
4713 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4714 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4715 VariantClear(&dest);
4717 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4718 EXPECT_HR(hr, S_OK);
4720 V_VT(&dest) = VT_EMPTY;
4721 hr = IMXWriter_get_output(writer, &dest);
4722 EXPECT_HR(hr, S_OK);
4723 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4724 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n<?targ data?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4725 VariantClear(&dest);
4727 V_VT(&dest) = VT_EMPTY;
4728 hr = IMXWriter_put_output(writer, dest);
4729 EXPECT_HR(hr, S_OK);
4731 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4732 EXPECT_HR(hr, S_OK);
4734 V_VT(&dest) = VT_EMPTY;
4735 hr = IMXWriter_get_output(writer, &dest);
4736 EXPECT_HR(hr, S_OK);
4737 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4738 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4739 VariantClear(&dest);
4742 ISAXContentHandler_Release(content);
4743 IMXWriter_Release(writer);
4746 static void test_mxwriter_ignorablespaces(void)
4748 static const WCHAR dataW[] = {'d','a','t','a',0};
4749 ISAXContentHandler *content;
4750 IMXWriter *writer;
4751 VARIANT dest;
4752 HRESULT hr;
4754 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4755 &IID_IMXWriter, (void**)&writer);
4756 EXPECT_HR(hr, S_OK);
4758 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4759 EXPECT_HR(hr, S_OK);
4761 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4762 EXPECT_HR(hr, E_INVALIDARG);
4764 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4765 EXPECT_HR(hr, S_OK);
4767 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4768 EXPECT_HR(hr, S_OK);
4770 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4771 EXPECT_HR(hr, S_OK);
4773 V_VT(&dest) = VT_EMPTY;
4774 hr = IMXWriter_get_output(writer, &dest);
4775 EXPECT_HR(hr, S_OK);
4776 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4777 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4778 VariantClear(&dest);
4780 ISAXContentHandler_Release(content);
4781 IMXWriter_Release(writer);
4784 static void test_mxwriter_dtd(void)
4786 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4787 static const WCHAR nameW[] = {'n','a','m','e'};
4788 static const WCHAR pubW[] = {'p','u','b'};
4789 static const WCHAR sysW[] = {'s','y','s'};
4790 IVBSAXLexicalHandler *vblexical;
4791 ISAXContentHandler *content;
4792 ISAXLexicalHandler *lexical;
4793 IVBSAXDeclHandler *vbdecl;
4794 ISAXDeclHandler *decl;
4795 IMXWriter *writer;
4796 VARIANT dest;
4797 HRESULT hr;
4799 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4800 &IID_IMXWriter, (void**)&writer);
4801 EXPECT_HR(hr, S_OK);
4803 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4804 EXPECT_HR(hr, S_OK);
4806 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4807 EXPECT_HR(hr, S_OK);
4809 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4810 EXPECT_HR(hr, S_OK);
4812 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl);
4813 EXPECT_HR(hr, S_OK);
4815 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4816 EXPECT_HR(hr, S_OK);
4818 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4819 EXPECT_HR(hr, S_OK);
4821 hr = ISAXContentHandler_startDocument(content);
4822 EXPECT_HR(hr, S_OK);
4824 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4825 EXPECT_HR(hr, E_INVALIDARG);
4827 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL);
4828 EXPECT_HR(hr, E_POINTER);
4830 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4831 EXPECT_HR(hr, E_INVALIDARG);
4833 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4834 EXPECT_HR(hr, E_INVALIDARG);
4836 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4837 EXPECT_HR(hr, E_INVALIDARG);
4839 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4840 EXPECT_HR(hr, S_OK);
4842 V_VT(&dest) = VT_EMPTY;
4843 hr = IMXWriter_get_output(writer, &dest);
4844 EXPECT_HR(hr, S_OK);
4845 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4846 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4847 VariantClear(&dest);
4849 /* system id is required if public is present */
4850 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4851 EXPECT_HR(hr, E_INVALIDARG);
4853 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4854 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4855 EXPECT_HR(hr, S_OK);
4857 V_VT(&dest) = VT_EMPTY;
4858 hr = IMXWriter_get_output(writer, &dest);
4859 EXPECT_HR(hr, S_OK);
4860 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4861 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4862 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4863 VariantClear(&dest);
4865 hr = ISAXLexicalHandler_endDTD(lexical);
4866 EXPECT_HR(hr, S_OK);
4868 hr = IVBSAXLexicalHandler_endDTD(vblexical);
4869 EXPECT_HR(hr, S_OK);
4871 V_VT(&dest) = VT_EMPTY;
4872 hr = IMXWriter_get_output(writer, &dest);
4873 EXPECT_HR(hr, S_OK);
4874 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4875 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4876 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4877 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4878 VariantClear(&dest);
4880 /* element declaration */
4881 V_VT(&dest) = VT_EMPTY;
4882 hr = IMXWriter_put_output(writer, dest);
4883 EXPECT_HR(hr, S_OK);
4885 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4886 EXPECT_HR(hr, E_INVALIDARG);
4888 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL);
4889 EXPECT_HR(hr, E_POINTER);
4891 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4892 EXPECT_HR(hr, E_INVALIDARG);
4894 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4895 EXPECT_HR(hr, S_OK);
4897 V_VT(&dest) = VT_EMPTY;
4898 hr = IMXWriter_get_output(writer, &dest);
4899 EXPECT_HR(hr, S_OK);
4900 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4901 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4902 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4903 VariantClear(&dest);
4905 V_VT(&dest) = VT_EMPTY;
4906 hr = IMXWriter_put_output(writer, dest);
4907 EXPECT_HR(hr, S_OK);
4909 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4910 EXPECT_HR(hr, S_OK);
4912 V_VT(&dest) = VT_EMPTY;
4913 hr = IMXWriter_get_output(writer, &dest);
4914 EXPECT_HR(hr, S_OK);
4915 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4916 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4917 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4918 VariantClear(&dest);
4920 /* attribute declaration */
4921 V_VT(&dest) = VT_EMPTY;
4922 hr = IMXWriter_put_output(writer, dest);
4923 EXPECT_HR(hr, S_OK);
4925 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4926 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4927 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4928 EXPECT_HR(hr, S_OK);
4930 V_VT(&dest) = VT_EMPTY;
4931 hr = IMXWriter_get_output(writer, &dest);
4932 EXPECT_HR(hr, S_OK);
4933 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4934 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4935 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4936 VariantClear(&dest);
4938 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4939 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4940 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4941 EXPECT_HR(hr, S_OK);
4943 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4944 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4945 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4946 EXPECT_HR(hr, S_OK);
4948 V_VT(&dest) = VT_EMPTY;
4949 hr = IMXWriter_get_output(writer, &dest);
4950 EXPECT_HR(hr, S_OK);
4951 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4952 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4953 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4954 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4955 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4956 VariantClear(&dest);
4958 /* internal entities */
4959 V_VT(&dest) = VT_EMPTY;
4960 hr = IMXWriter_put_output(writer, dest);
4961 EXPECT_HR(hr, S_OK);
4963 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4964 EXPECT_HR(hr, E_INVALIDARG);
4966 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL);
4967 EXPECT_HR(hr, E_POINTER);
4969 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4970 EXPECT_HR(hr, E_INVALIDARG);
4972 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4973 EXPECT_HR(hr, S_OK);
4975 V_VT(&dest) = VT_EMPTY;
4976 hr = IMXWriter_get_output(writer, &dest);
4977 EXPECT_HR(hr, S_OK);
4978 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4979 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4980 VariantClear(&dest);
4982 /* external entities */
4983 V_VT(&dest) = VT_EMPTY;
4984 hr = IMXWriter_put_output(writer, dest);
4985 ok(hr == S_OK, "got 0x%08x\n", hr);
4987 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0);
4988 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4990 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL);
4991 ok(hr == E_POINTER, "got 0x%08x\n", hr);
4993 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0);
4994 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4996 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"),
4997 _bstr_("sysid"), strlen("sysid"));
4998 ok(hr == S_OK, "got 0x%08x\n", hr);
5000 V_VT(&dest) = VT_EMPTY;
5001 hr = IMXWriter_get_output(writer, &dest);
5002 ok(hr == S_OK, "got 0x%08x\n", hr);
5003 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5004 ok(!lstrcmpW(_bstr_("<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5005 VariantClear(&dest);
5007 ISAXContentHandler_Release(content);
5008 ISAXLexicalHandler_Release(lexical);
5009 IVBSAXLexicalHandler_Release(vblexical);
5010 IVBSAXDeclHandler_Release(vbdecl);
5011 ISAXDeclHandler_Release(decl);
5012 IMXWriter_Release(writer);
5013 free_bstrs();
5016 typedef struct {
5017 const CLSID *clsid;
5018 const char *uri;
5019 const char *local;
5020 const char *qname;
5021 const char *type;
5022 const char *value;
5023 HRESULT hr;
5024 } addattribute_test_t;
5026 static const addattribute_test_t addattribute_data[] = {
5027 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5028 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5029 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5030 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
5032 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5033 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5034 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5035 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
5037 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5038 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5039 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5040 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
5042 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
5043 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
5044 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
5045 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
5047 { NULL }
5050 static void test_mxattr_addAttribute(void)
5052 const addattribute_test_t *table = addattribute_data;
5053 int i = 0;
5055 while (table->clsid)
5057 ISAXAttributes *saxattr;
5058 IMXAttributes *mxattr;
5059 const WCHAR *value;
5060 int len, index;
5061 HRESULT hr;
5063 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5065 table++;
5066 i++;
5067 continue;
5070 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5071 &IID_IMXAttributes, (void**)&mxattr);
5072 EXPECT_HR(hr, S_OK);
5074 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5075 EXPECT_HR(hr, S_OK);
5077 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5078 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5079 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5081 hr = ISAXAttributes_getLength(saxattr, NULL);
5082 EXPECT_HR(hr, E_POINTER);
5085 len = -1;
5086 hr = ISAXAttributes_getLength(saxattr, &len);
5087 EXPECT_HR(hr, S_OK);
5088 ok(len == 0, "got %d\n", len);
5090 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5091 EXPECT_HR(hr, E_INVALIDARG);
5093 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5094 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5096 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5097 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5099 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5100 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5102 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5103 EXPECT_HR(hr, E_INVALIDARG);
5105 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5106 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5108 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5109 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5111 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5112 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5114 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
5115 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
5116 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
5118 if (hr == S_OK)
5120 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5121 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5122 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5124 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5125 EXPECT_HR(hr, E_POINTER);
5127 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5128 EXPECT_HR(hr, E_POINTER);
5130 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5131 EXPECT_HR(hr, E_POINTER);
5133 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5134 EXPECT_HR(hr, E_POINTER);
5136 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5137 EXPECT_HR(hr, E_POINTER);
5139 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5140 EXPECT_HR(hr, E_POINTER);
5143 len = -1;
5144 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5145 EXPECT_HR(hr, S_OK);
5146 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5147 table->value);
5148 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5150 len = -1;
5151 value = (void*)0xdeadbeef;
5152 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5153 EXPECT_HR(hr, S_OK);
5155 if (table->type)
5157 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5158 table->type);
5159 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
5161 else
5163 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
5164 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
5167 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
5168 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5169 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5171 EXPECT_HR(hr, E_POINTER);
5173 else
5174 EXPECT_HR(hr, E_INVALIDARG);
5176 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
5177 EXPECT_HR(hr, E_INVALIDARG);
5179 index = -1;
5180 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
5181 EXPECT_HR(hr, E_INVALIDARG);
5182 ok(index == -1, "%d: got wrong index %d\n", i, index);
5184 index = -1;
5185 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
5186 EXPECT_HR(hr, E_INVALIDARG);
5187 ok(index == -1, "%d: got wrong index %d\n", i, index);
5189 index = -1;
5190 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
5191 EXPECT_HR(hr, S_OK);
5192 ok(index == 0, "%d: got wrong index %d\n", i, index);
5194 index = -1;
5195 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
5196 EXPECT_HR(hr, E_INVALIDARG);
5197 ok(index == -1, "%d: got wrong index %d\n", i, index);
5199 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
5200 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
5202 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5203 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5205 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5206 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5208 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5209 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5211 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5212 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5214 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5215 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5217 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5218 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5220 else
5222 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5223 EXPECT_HR(hr, E_POINTER);
5225 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5226 EXPECT_HR(hr, E_POINTER);
5228 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5229 EXPECT_HR(hr, E_POINTER);
5231 /* versions 4 and 6 crash */
5232 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
5233 EXPECT_HR(hr, E_POINTER);
5235 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
5236 EXPECT_HR(hr, E_POINTER);
5238 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5239 EXPECT_HR(hr, E_POINTER);
5241 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5242 EXPECT_HR(hr, E_POINTER);
5244 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5245 EXPECT_HR(hr, E_POINTER);
5247 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
5248 EXPECT_HR(hr, E_POINTER);
5250 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
5251 EXPECT_HR(hr, E_POINTER);
5253 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
5254 strlen(table->local), NULL, NULL);
5255 EXPECT_HR(hr, E_POINTER);
5258 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
5259 EXPECT_HR(hr, S_OK);
5260 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5261 table->value);
5262 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5264 if (table->uri) {
5265 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
5266 _bstr_(table->local), strlen(table->local), &value, &len);
5267 EXPECT_HR(hr, S_OK);
5268 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5269 table->value);
5270 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5274 len = -1;
5275 hr = ISAXAttributes_getLength(saxattr, &len);
5276 EXPECT_HR(hr, S_OK);
5277 if (table->hr == S_OK)
5278 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
5279 else
5280 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
5282 ISAXAttributes_Release(saxattr);
5283 IMXAttributes_Release(mxattr);
5285 table++;
5286 i++;
5289 free_bstrs();
5292 static void test_mxattr_clear(void)
5294 ISAXAttributes *saxattr;
5295 IMXAttributes *mxattr;
5296 const WCHAR *ptr;
5297 HRESULT hr;
5298 int len;
5300 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5301 &IID_IMXAttributes, (void**)&mxattr);
5302 EXPECT_HR(hr, S_OK);
5304 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5305 EXPECT_HR(hr, S_OK);
5307 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
5308 EXPECT_HR(hr, E_INVALIDARG);
5310 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5311 EXPECT_HR(hr, E_INVALIDARG);
5313 hr = IMXAttributes_clear(mxattr);
5314 EXPECT_HR(hr, S_OK);
5316 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
5317 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
5318 EXPECT_HR(hr, S_OK);
5320 len = -1;
5321 hr = ISAXAttributes_getLength(saxattr, &len);
5322 EXPECT_HR(hr, S_OK);
5323 ok(len == 1, "got %d\n", len);
5325 len = -1;
5326 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
5327 EXPECT_HR(hr, E_POINTER);
5328 ok(len == -1, "got %d\n", len);
5330 ptr = (void*)0xdeadbeef;
5331 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
5332 EXPECT_HR(hr, E_POINTER);
5333 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5335 len = 0;
5336 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5337 EXPECT_HR(hr, S_OK);
5338 ok(len == 5, "got %d\n", len);
5339 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
5341 hr = IMXAttributes_clear(mxattr);
5342 EXPECT_HR(hr, S_OK);
5344 len = -1;
5345 hr = ISAXAttributes_getLength(saxattr, &len);
5346 EXPECT_HR(hr, S_OK);
5347 ok(len == 0, "got %d\n", len);
5349 len = -1;
5350 ptr = (void*)0xdeadbeef;
5351 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5352 EXPECT_HR(hr, E_INVALIDARG);
5353 ok(len == -1, "got %d\n", len);
5354 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5356 IMXAttributes_Release(mxattr);
5357 ISAXAttributes_Release(saxattr);
5358 free_bstrs();
5361 static void test_mxattr_dispex(void)
5363 IMXAttributes *mxattr;
5364 IDispatchEx *dispex;
5365 IUnknown *unk;
5366 HRESULT hr;
5368 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5369 &IID_IMXAttributes, (void**)&mxattr);
5370 EXPECT_HR(hr, S_OK);
5372 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
5373 EXPECT_HR(hr, S_OK);
5374 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
5375 test_obj_dispex(unk);
5376 IUnknown_Release(unk);
5377 IDispatchEx_Release(dispex);
5379 IMXAttributes_Release(mxattr);
5382 static void test_mxattr_qi(void)
5384 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
5385 ISAXAttributes *saxattr;
5386 IMXAttributes *mxattr;
5387 HRESULT hr;
5389 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5390 &IID_IMXAttributes, (void**)&mxattr);
5391 EXPECT_HR(hr, S_OK);
5393 EXPECT_REF(mxattr, 1);
5394 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5395 EXPECT_HR(hr, S_OK);
5397 EXPECT_REF(mxattr, 2);
5398 EXPECT_REF(saxattr, 2);
5400 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
5401 EXPECT_HR(hr, S_OK);
5403 EXPECT_REF(vbsaxattr, 3);
5404 EXPECT_REF(mxattr, 3);
5405 EXPECT_REF(saxattr, 3);
5407 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
5408 EXPECT_HR(hr, S_OK);
5410 EXPECT_REF(vbsaxattr, 4);
5411 EXPECT_REF(mxattr, 4);
5412 EXPECT_REF(saxattr, 4);
5414 IMXAttributes_Release(mxattr);
5415 ISAXAttributes_Release(saxattr);
5416 IVBSAXAttributes_Release(vbsaxattr);
5417 IVBSAXAttributes_Release(vbsaxattr2);
5420 static struct msxmlsupported_data_t saxattr_support_data[] =
5422 { &CLSID_SAXAttributes, "SAXAttributes" },
5423 { &CLSID_SAXAttributes30, "SAXAttributes30" },
5424 { &CLSID_SAXAttributes40, "SAXAttributes40" },
5425 { &CLSID_SAXAttributes60, "SAXAttributes60" },
5426 { NULL }
5429 static void test_mxattr_localname(void)
5431 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
5432 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
5433 static const WCHAR uri1W[] = {'u','r','i','1',0};
5434 static const WCHAR uriW[] = {'u','r','i',0};
5436 const struct msxmlsupported_data_t *table = saxattr_support_data;
5438 while (table->clsid)
5440 ISAXAttributes *saxattr;
5441 IMXAttributes *mxattr;
5442 HRESULT hr;
5443 int index;
5445 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5447 table++;
5448 continue;
5451 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5452 &IID_IMXAttributes, (void**)&mxattr);
5453 EXPECT_HR(hr, S_OK);
5455 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5456 EXPECT_HR(hr, S_OK);
5458 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5459 EXPECT_HR(hr, E_INVALIDARG);
5461 /* add some ambiguos attribute names */
5462 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5463 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5464 EXPECT_HR(hr, S_OK);
5465 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5466 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5467 EXPECT_HR(hr, S_OK);
5469 index = -1;
5470 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5471 EXPECT_HR(hr, S_OK);
5472 ok(index == 0, "%s: got index %d\n", table->name, index);
5474 index = -1;
5475 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5476 EXPECT_HR(hr, E_INVALIDARG);
5477 ok(index == -1, "%s: got index %d\n", table->name, index);
5479 index = -1;
5480 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5481 EXPECT_HR(hr, E_INVALIDARG);
5482 ok(index == -1, "%s: got index %d\n", table->name, index);
5484 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5485 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5487 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5488 EXPECT_HR(hr, E_POINTER);
5490 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5491 EXPECT_HR(hr, E_POINTER);
5493 else
5495 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5496 EXPECT_HR(hr, E_INVALIDARG);
5498 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5499 EXPECT_HR(hr, E_INVALIDARG);
5502 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5503 EXPECT_HR(hr, E_INVALIDARG);
5505 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5506 EXPECT_HR(hr, E_INVALIDARG);
5508 table++;
5510 ISAXAttributes_Release(saxattr);
5511 IMXAttributes_Release(mxattr);
5515 static void test_mxwriter_indent(void)
5517 ISAXContentHandler *content;
5518 IMXWriter *writer;
5519 VARIANT dest;
5520 HRESULT hr;
5522 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer);
5523 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5525 hr = IMXWriter_put_indent(writer, VARIANT_TRUE);
5526 ok(hr == S_OK, "got %08x\n", hr);
5528 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
5529 ok(hr == S_OK, "got %08x\n", hr);
5531 hr = ISAXContentHandler_startDocument(content);
5532 ok(hr == S_OK, "got %08x\n", hr);
5534 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
5535 ok(hr == S_OK, "got %08x\n", hr);
5537 hr = ISAXContentHandler_characters(content, _bstr_(""), 0);
5538 ok(hr == S_OK, "got %08x\n", hr);
5540 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL);
5541 ok(hr == S_OK, "got %08x\n", hr);
5543 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL);
5544 ok(hr == S_OK, "got %08x\n", hr);
5546 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1);
5547 ok(hr == S_OK, "got %08x\n", hr);
5549 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1);
5550 ok(hr == S_OK, "got %08x\n", hr);
5552 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1);
5553 ok(hr == S_OK, "got %08x\n", hr);
5555 hr = ISAXContentHandler_endDocument(content);
5556 ok(hr == S_OK, "got %08x\n", hr);
5558 V_VT(&dest) = VT_EMPTY;
5559 hr = IMXWriter_get_output(writer, &dest);
5560 ok(hr == S_OK, "got %08x\n", hr);
5561 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5562 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n<a><b>\r\n\t\t<c/>\r\n\t</b>\r\n</a>"), V_BSTR(&dest)),
5563 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5564 VariantClear(&dest);
5566 ISAXContentHandler_Release(content);
5567 IMXWriter_Release(writer);
5569 free_bstrs();
5572 START_TEST(saxreader)
5574 ISAXXMLReader *reader;
5575 HRESULT hr;
5577 hr = CoInitialize(NULL);
5578 ok(hr == S_OK, "failed to init com\n");
5580 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5581 &IID_ISAXXMLReader, (void**)&reader);
5583 if(FAILED(hr))
5585 skip("Failed to create SAXXMLReader instance\n");
5586 CoUninitialize();
5587 return;
5589 ISAXXMLReader_Release(reader);
5591 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5593 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5595 test_saxreader();
5596 test_saxreader_properties();
5597 test_saxreader_features();
5598 test_saxreader_encoding();
5599 test_saxreader_dispex();
5601 /* MXXMLWriter tests */
5602 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5603 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5605 test_mxwriter_handlers();
5606 test_mxwriter_startenddocument();
5607 test_mxwriter_startendelement();
5608 test_mxwriter_characters();
5609 test_mxwriter_comment();
5610 test_mxwriter_cdata();
5611 test_mxwriter_pi();
5612 test_mxwriter_ignorablespaces();
5613 test_mxwriter_dtd();
5614 test_mxwriter_properties();
5615 test_mxwriter_flush();
5616 test_mxwriter_stream();
5617 test_mxwriter_encoding();
5618 test_mxwriter_dispex();
5619 test_mxwriter_indent();
5621 else
5622 win_skip("MXXMLWriter not supported\n");
5624 /* SAXAttributes tests */
5625 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5626 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5628 test_mxattr_qi();
5629 test_mxattr_addAttribute();
5630 test_mxattr_clear();
5631 test_mxattr_localname();
5632 test_mxattr_dispex();
5634 else
5635 skip("SAXAttributes not supported\n");
5637 CoUninitialize();