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
32 #include "msxml2did.h"
36 #include "wine/test.h"
38 #define EXPECT_HR(hr,hr_exp) \
39 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
41 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
42 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
44 ULONG rc = IUnknown_AddRef(obj);
45 IUnknown_Release(obj);
46 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
49 static LONG get_refcount(void *iface)
51 IUnknown *unk = iface;
54 ref = IUnknown_AddRef(unk);
55 IUnknown_Release(unk);
59 struct msxmlsupported_data_t
66 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
70 if (table->clsid == clsid) return table->supported;
76 static BSTR alloc_str_from_narrow(const char *str)
78 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
79 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
80 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
84 static BSTR alloced_bstrs[512];
85 static int alloced_bstrs_count;
87 static BSTR _bstr_(const char *str)
89 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
90 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
91 return alloced_bstrs[alloced_bstrs_count++];
94 static void free_bstrs(void)
97 for (i = 0; i < alloced_bstrs_count; i++)
98 SysFreeString(alloced_bstrs[i]);
99 alloced_bstrs_count = 0;
102 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, int todo, int *failcount)
104 int len, lenexp, cmp;
107 len = SysStringLen(str);
114 ok_(file, line) (!str, "got %p, expected null str\n", str);
117 ok_(file, line) (!str, "got %p, expected null str\n", str);
123 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
126 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
130 lenexp = strlen(expected);
131 if (lenexp != len && todo)
135 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
138 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
140 /* exit earlier on length mismatch */
141 if (lenexp != len) return;
143 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
145 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
150 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
151 wine_dbgstr_wn(str, len), expected);
154 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
155 wine_dbgstr_wn(str, len), expected);
160 CH_PUTDOCUMENTLOCATOR,
163 CH_STARTPREFIXMAPPING,
168 CH_IGNORABLEWHITESPACE,
169 CH_PROCESSINGINSTRUCTION,
179 static const char *event_names[EVENT_LAST] = {
181 "putDocumentLocator",
184 "startPrefixMapping",
189 "ignorableWhitespace",
190 "processingInstruction",
199 struct attribute_entry {
205 /* used for actual call data only, null for expected call data */
221 /* allocated once at startElement callback */
222 struct attribute_entry *attributes;
225 /* used for actual call data only, null for expected call data */
235 struct call_entry *sequence;
238 #define CONTENT_HANDLER_INDEX 0
239 #define NUM_CALL_SEQUENCES 1
240 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
242 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
244 memset(call, 0, sizeof(*call));
245 ISAXLocator_getLineNumber(locator, &call->line);
246 ISAXLocator_getColumnNumber(locator, &call->column);
249 static void add_call(struct call_sequence **seq, int sequence_index,
250 const struct call_entry *call)
252 struct call_sequence *call_seq = seq[sequence_index];
254 if (!call_seq->sequence)
257 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
258 call_seq->size * sizeof (struct call_entry));
261 if (call_seq->count == call_seq->size)
264 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
266 call_seq->size * sizeof (struct call_entry));
269 assert(call_seq->sequence);
271 call_seq->sequence[call_seq->count].id = call->id;
272 call_seq->sequence[call_seq->count].line = call->line;
273 call_seq->sequence[call_seq->count].column = call->column;
274 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
275 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
276 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
277 call_seq->sequence[call_seq->count].ret = call->ret;
278 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
279 call_seq->sequence[call_seq->count].attributes = call->attributes;
284 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
288 struct call_sequence *call_seq = seg[sequence_index];
290 for (i = 0; i < call_seq->count; i++)
294 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
296 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
297 SysFreeString(call_seq->sequence[i].attributes[j].localW);
298 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
301 SysFreeString(call_seq->sequence[i].arg1W);
302 SysFreeString(call_seq->sequence[i].arg2W);
303 SysFreeString(call_seq->sequence[i].arg3W);
306 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
307 call_seq->sequence = NULL;
308 call_seq->count = call_seq->size = 0;
311 static inline void flush_sequences(struct call_sequence **seq, int n)
314 for (i = 0; i < n; i++)
315 flush_sequence(seq, i);
318 static const char *get_event_name(CH event)
320 return event_names[event];
323 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
324 int todo, const char *file, int line, int *failcount)
328 /* attribute count is not stored for expected data */
329 if (expected->attributes)
331 struct attribute_entry *ptr = expected->attributes;
332 while (ptr->uri) { lenexp++; ptr++; };
335 /* check count first and exit earlier */
336 if (actual->attr_count != lenexp && todo)
340 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
341 context, get_event_name(actual->id), lenexp, actual->attr_count);
344 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
345 context, get_event_name(actual->id), lenexp, actual->attr_count);
347 if (actual->attr_count != lenexp) return;
349 /* now compare all attributes strings */
350 for (i = 0; i < actual->attr_count; i++)
352 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
353 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
354 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
355 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
359 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
360 const struct call_entry *expected, const char *context, int todo,
361 const char *file, int line)
363 struct call_sequence *call_seq = seq[sequence_index];
364 static const struct call_entry end_of_sequence = { CH_ENDTEST };
365 const struct call_entry *actual, *sequence;
368 add_call(seq, sequence_index, &end_of_sequence);
370 sequence = call_seq->sequence;
373 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
375 if (expected->id == actual->id)
377 /* always test position data */
378 if (expected->line != actual->line && todo)
383 ok_(file, line) (FALSE,
384 "%s: in event %s expecting line %d got %d\n",
385 context, get_event_name(actual->id), expected->line, actual->line);
390 ok_(file, line) (expected->line == actual->line,
391 "%s: in event %s expecting line %d got %d\n",
392 context, get_event_name(actual->id), expected->line, actual->line);
395 if (expected->column != actual->column && todo)
400 ok_(file, line) (FALSE,
401 "%s: in event %s expecting column %d got %d\n",
402 context, get_event_name(actual->id), expected->column, actual->column);
407 ok_(file, line) (expected->column == actual->column,
408 "%s: in event %s expecting column %d got %d\n",
409 context, get_event_name(actual->id), expected->column, actual->column);
414 case CH_PUTDOCUMENTLOCATOR:
415 case CH_STARTDOCUMENT:
420 case CH_STARTPREFIXMAPPING:
422 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
423 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
425 case CH_ENDPREFIXMAPPING:
427 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
429 case CH_STARTELEMENT:
430 /* compare attributes */
431 compare_attributes(actual, expected, context, todo, file, line, &failcount);
434 /* uri, localname, qname */
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
436 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
437 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
440 case CH_IGNORABLEWHITESPACE:
442 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
444 case CH_PROCESSINGINSTRUCTION:
446 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
447 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
449 case CH_SKIPPEDENTITY:
451 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
454 /* test return value only */
455 if (expected->ret != actual->ret && todo)
458 ok_(file, line) (FALSE,
459 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
460 context, get_event_name(actual->id), expected->ret, actual->ret);
463 ok_(file, line) (expected->ret == actual->ret,
464 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
465 context, get_event_name(actual->id), expected->ret, actual->ret);
468 case EH_IGNORABLEWARNING:
470 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
480 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
481 context, get_event_name(expected->id), get_event_name(actual->id));
484 flush_sequence(seq, sequence_index);
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));
500 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
503 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
504 context, get_event_name(expected->id), get_event_name(actual->id));
508 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
510 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
511 context, get_event_name(expected->id), get_event_name(actual->id));
514 if (todo && !failcount) /* succeeded yet marked todo */
518 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
522 flush_sequence(seq, sequence_index);
525 #define ok_sequence(seq, index, exp, contx, todo) \
526 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
528 static void init_call_sequences(struct call_sequence **seq, int n)
532 for (i = 0; i < n; i++)
533 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
536 static const WCHAR szSimpleXML[] = {
537 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
538 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
539 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
540 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
541 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
544 static const WCHAR carriage_ret_test[] = {
545 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
546 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
547 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
548 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
549 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
552 static const WCHAR szUtf16XML[] = {
553 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
554 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
555 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
558 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
560 static const CHAR szUtf8XML[] =
561 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
563 static const char utf8xml2[] =
564 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
566 static const char testXML[] =
567 "<?xml version=\"1.0\" ?>\n"
569 " <Number>1234</Number>\n"
570 " <Name>Captain Ahab</Name>\n"
573 static const char test_attributes[] =
574 "<?xml version=\"1.0\" ?>\n"
575 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
576 "<node1 xmlns:p=\"test\" />"
579 static const char test_cdata_xml[] =
580 "<?xml version=\"1.0\" ?>"
581 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
583 static const char test2_cdata_xml[] =
584 "<?xml version=\"1.0\" ?>"
585 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
587 static const char test3_cdata_xml[] =
588 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
590 static struct call_entry content_handler_test1[] = {
591 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
592 { CH_STARTDOCUMENT, 0, 0, S_OK },
593 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
594 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
595 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
596 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
597 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
598 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
599 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
600 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
601 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
602 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
603 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
604 { CH_ENDDOCUMENT, 0, 0, S_OK},
608 /* applies to versions 4 and 6 */
609 static struct call_entry content_handler_test1_alternate[] = {
610 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
611 { CH_STARTDOCUMENT, 1, 22, S_OK },
612 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
613 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
614 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
615 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
616 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
617 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
618 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
619 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
620 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
621 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
622 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
623 { CH_ENDDOCUMENT, 6, 0, S_OK },
627 static struct call_entry content_handler_test2[] = {
628 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
629 { CH_STARTDOCUMENT, 0, 0, S_OK },
630 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
631 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
632 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
633 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
634 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
635 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
636 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
637 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
638 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
639 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
640 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
641 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
642 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
643 { CH_ENDDOCUMENT, 0, 0, S_OK },
647 static struct call_entry content_handler_test2_alternate[] = {
648 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
649 { CH_STARTDOCUMENT, 1, 21, S_OK },
650 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
651 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
652 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
653 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
654 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
655 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
656 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
657 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
658 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
659 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
660 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
661 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
662 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
663 { CH_ENDDOCUMENT, 6, 0, S_OK },
667 static struct call_entry content_handler_testerror[] = {
668 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
669 { EH_FATALERROR, 0, 0, E_FAIL },
673 static struct call_entry content_handler_testerror_alternate[] = {
674 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
675 { EH_FATALERROR, 1, 0, E_FAIL },
679 static struct call_entry content_handler_test_callback_rets[] = {
680 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
681 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
682 { EH_FATALERROR, 0, 0, S_FALSE },
686 static struct call_entry content_handler_test_callback_rets_alt[] = {
687 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
688 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
689 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
690 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
691 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
692 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
693 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
694 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
695 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
696 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
697 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
698 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
699 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
700 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
704 static struct attribute_entry ch_attributes1[] = {
705 { "", "", "xmlns:test", "prefix_test" },
706 { "", "", "xmlns", "prefix" },
707 { "prefix_test", "arg1", "test:arg1", "arg1" },
708 { "", "arg2", "arg2", "arg2" },
709 { "prefix_test", "ar3", "test:ar3", "arg3" },
713 static struct attribute_entry ch_attributes2[] = {
714 { "", "", "xmlns:p", "test" },
718 static struct call_entry content_handler_test_attributes[] = {
719 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
720 { CH_STARTDOCUMENT, 0, 0, S_OK },
721 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
722 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
723 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
724 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
725 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
726 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
727 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
728 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
729 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
730 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
731 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
732 { CH_ENDDOCUMENT, 0, 0 },
736 static struct attribute_entry ch_attributes_alt_4[] = {
737 { "prefix_test", "arg1", "test:arg1", "arg1" },
738 { "", "arg2", "arg2", "arg2" },
739 { "prefix_test", "ar3", "test:ar3", "arg3" },
740 { "", "", "xmlns:test", "prefix_test" },
741 { "", "", "xmlns", "prefix" },
745 static struct call_entry content_handler_test_attributes_alternate_4[] = {
746 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
747 { CH_STARTDOCUMENT, 1, 22, S_OK },
748 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
749 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
750 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
751 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
752 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
753 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
754 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
755 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
756 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
757 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
758 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
759 { CH_ENDDOCUMENT, 4, 0, S_OK },
763 /* 'namespace' feature switched off */
764 static struct attribute_entry ch_attributes_alt_no_ns[] = {
765 { "", "", "xmlns:test", "prefix_test" },
766 { "", "", "xmlns", "prefix" },
767 { "", "", "test:arg1", "arg1" },
768 { "", "", "arg2", "arg2" },
769 { "", "", "test:ar3", "arg3" },
773 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
774 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
775 { CH_STARTDOCUMENT, 1, 22, S_OK },
776 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
777 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
778 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
779 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
780 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
781 { CH_ENDDOCUMENT, 4, 0, S_OK },
785 static struct attribute_entry ch_attributes_alt_6[] = {
786 { "prefix_test", "arg1", "test:arg1", "arg1" },
787 { "", "arg2", "arg2", "arg2" },
788 { "prefix_test", "ar3", "test:ar3", "arg3" },
789 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
790 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
794 static struct attribute_entry ch_attributes2_6[] = {
795 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
799 static struct call_entry content_handler_test_attributes_alternate_6[] = {
800 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
801 { CH_STARTDOCUMENT, 1, 22, S_OK },
802 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
803 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
804 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
805 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
806 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
807 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
808 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
809 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
810 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
811 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
812 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
813 { CH_ENDDOCUMENT, 4, 0, S_OK },
817 /* 'namespaces' is on, 'namespace-prefixes' if off */
818 static struct attribute_entry ch_attributes_no_prefix[] = {
819 { "prefix_test", "arg1", "test:arg1", "arg1" },
820 { "", "arg2", "arg2", "arg2" },
821 { "prefix_test", "ar3", "test:ar3", "arg3" },
825 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
826 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
827 { CH_STARTDOCUMENT, 1, 22, S_OK },
828 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
829 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
830 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
831 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
832 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
833 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
834 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
835 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
836 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
837 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
838 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
839 { CH_ENDDOCUMENT, 4, 0, S_OK },
843 static struct call_entry content_handler_test_attributes_no_prefix[] = {
844 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
845 { CH_STARTDOCUMENT, 0, 0, S_OK },
846 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
847 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
848 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
849 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
850 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
851 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
852 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
853 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
854 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
855 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
856 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
857 { CH_ENDDOCUMENT, 0, 0 },
861 static struct attribute_entry xmlspace_attrs[] = {
862 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
866 static struct call_entry xmlspaceattr_test[] = {
867 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
868 { CH_STARTDOCUMENT, 0, 0, S_OK },
869 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
870 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
871 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
872 { CH_ENDDOCUMENT, 0, 0, S_OK },
876 static struct call_entry xmlspaceattr_test_alternate[] = {
877 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
878 { CH_STARTDOCUMENT, 1, 39, S_OK },
879 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
880 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
881 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
882 { CH_ENDDOCUMENT, 1, 83, S_OK },
886 /* attribute value normalization test */
887 static const char attribute_normalize[] =
888 "<?xml version=\"1.0\" ?>\n"
889 "<a attr1=\" \r \n \tattr_value A \t \r \n\r\n \n\"/>\n";
891 static struct attribute_entry attribute_norm_attrs[] = {
892 { "", "attr1", "attr1", " attr_value A " },
896 static struct call_entry attribute_norm[] = {
897 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
898 { CH_STARTDOCUMENT, 0, 0, S_OK },
899 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
900 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
901 { CH_ENDDOCUMENT, 0, 0, S_OK },
905 static struct call_entry attribute_norm_alt[] = {
906 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
907 { CH_STARTDOCUMENT, 1, 22, S_OK },
908 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
909 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
910 { CH_ENDDOCUMENT, 9, 0, S_OK },
914 static struct call_entry cdata_test[] = {
915 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
916 { CH_STARTDOCUMENT, 0, 0, S_OK },
917 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
918 { LH_STARTCDATA, 1, 35, S_OK },
919 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
920 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
921 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
922 { LH_ENDCDATA, 1, 49, S_OK },
923 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
924 { CH_ENDDOCUMENT, 0, 0, S_OK },
928 static struct call_entry cdata_test2[] = {
929 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
930 { CH_STARTDOCUMENT, 0, 0, S_OK },
931 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
932 { LH_STARTCDATA, 1, 35, S_OK },
933 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
934 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
935 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
936 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
937 { LH_ENDCDATA, 1, 52, S_OK },
938 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
939 { CH_ENDDOCUMENT, 0, 0, S_OK },
943 static struct call_entry cdata_test3[] = {
944 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
945 { CH_STARTDOCUMENT, 0, 0, S_OK },
946 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
947 { LH_STARTCDATA, 1, 35, S_OK },
948 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
949 { LH_ENDCDATA, 1, 35, S_OK },
950 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
951 { CH_ENDDOCUMENT, 0, 0, S_OK },
955 /* this is what MSXML6 does */
956 static struct call_entry cdata_test_alt[] = {
957 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
958 { CH_STARTDOCUMENT, 1, 22, S_OK },
959 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
960 { LH_STARTCDATA, 1, 34, S_OK },
961 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
962 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
963 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
964 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
965 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
966 { LH_ENDCDATA, 6, 3, S_OK },
967 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
968 { CH_ENDDOCUMENT, 6, 7, S_OK },
972 static struct call_entry cdata_test2_alt[] = {
973 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
974 { CH_STARTDOCUMENT, 1, 22, S_OK },
975 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
976 { LH_STARTCDATA, 1, 34, S_OK },
977 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
978 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
979 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
980 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
981 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
982 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
983 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
984 { LH_ENDCDATA, 8, 3, S_OK },
985 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
986 { CH_ENDDOCUMENT, 8, 7, S_OK },
990 static struct call_entry cdata_test3_alt[] = {
991 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
992 { CH_STARTDOCUMENT, 1, 22, S_OK },
993 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
994 { LH_STARTCDATA, 1, 34, S_OK },
995 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
996 { LH_ENDCDATA, 1, 51, S_OK },
997 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
998 { CH_ENDDOCUMENT, 1, 55, S_OK },
1002 static const char xmlspace_attr[] =
1003 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1004 "<a xml:space=\"preserve\"> Some text data </a>";
1006 static struct call_entry *expectCall;
1007 static ISAXLocator *locator;
1008 static ISAXXMLReader *g_reader;
1011 static void set_expected_seq(struct call_entry *expected)
1013 expectCall = expected;
1016 /* to be called once on each tested callback return */
1017 static HRESULT get_expected_ret(void)
1019 HRESULT hr = expectCall->ret;
1020 if (expectCall->id != CH_ENDTEST) expectCall++;
1024 static HRESULT WINAPI contentHandler_QueryInterface(
1025 ISAXContentHandler* iface,
1031 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1037 return E_NOINTERFACE;
1043 static ULONG WINAPI contentHandler_AddRef(
1044 ISAXContentHandler* iface)
1049 static ULONG WINAPI contentHandler_Release(
1050 ISAXContentHandler* iface)
1055 static HRESULT WINAPI contentHandler_putDocumentLocator(
1056 ISAXContentHandler* iface,
1057 ISAXLocator *pLocator)
1059 struct call_entry call;
1064 init_call_entry(locator, &call);
1065 call.id = CH_PUTDOCUMENTLOCATOR;
1066 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1068 if (msxml_version >= 6) {
1069 ISAXAttributes *attr, *attr1;
1070 IMXAttributes *mxattr;
1072 EXPECT_REF(pLocator, 1);
1073 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1074 EXPECT_HR(hr, S_OK);
1075 EXPECT_REF(pLocator, 2);
1076 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1077 EXPECT_HR(hr, S_OK);
1078 EXPECT_REF(pLocator, 3);
1079 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1081 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1082 EXPECT_HR(hr, E_NOINTERFACE);
1084 ISAXAttributes_Release(attr);
1085 ISAXAttributes_Release(attr1);
1088 return get_expected_ret();
1091 static ISAXAttributes *test_attr_ptr;
1092 static HRESULT WINAPI contentHandler_startDocument(
1093 ISAXContentHandler* iface)
1095 struct call_entry call;
1097 init_call_entry(locator, &call);
1098 call.id = CH_STARTDOCUMENT;
1099 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1101 test_attr_ptr = NULL;
1103 return get_expected_ret();
1106 static HRESULT WINAPI contentHandler_endDocument(
1107 ISAXContentHandler* iface)
1109 struct call_entry call;
1111 init_call_entry(locator, &call);
1112 call.id = CH_ENDDOCUMENT;
1113 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1115 return get_expected_ret();
1118 static HRESULT WINAPI contentHandler_startPrefixMapping(
1119 ISAXContentHandler* iface,
1120 const WCHAR *prefix, int prefix_len,
1121 const WCHAR *uri, int uri_len)
1123 struct call_entry call;
1125 init_call_entry(locator, &call);
1126 call.id = CH_STARTPREFIXMAPPING;
1127 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1128 call.arg2W = SysAllocStringLen(uri, uri_len);
1129 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1131 return get_expected_ret();
1134 static HRESULT WINAPI contentHandler_endPrefixMapping(
1135 ISAXContentHandler* iface,
1136 const WCHAR *prefix, int len)
1138 struct call_entry call;
1140 init_call_entry(locator, &call);
1141 call.id = CH_ENDPREFIXMAPPING;
1142 call.arg1W = SysAllocStringLen(prefix, len);
1143 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1145 return get_expected_ret();
1148 static HRESULT WINAPI contentHandler_startElement(
1149 ISAXContentHandler* iface,
1150 const WCHAR *uri, int uri_len,
1151 const WCHAR *localname, int local_len,
1152 const WCHAR *qname, int qname_len,
1153 ISAXAttributes *saxattr)
1155 struct call_entry call;
1156 IMXAttributes *mxattr;
1160 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1161 EXPECT_HR(hr, E_NOINTERFACE);
1163 init_call_entry(locator, &call);
1164 call.id = CH_STARTELEMENT;
1165 call.arg1W = SysAllocStringLen(uri, uri_len);
1166 call.arg2W = SysAllocStringLen(localname, local_len);
1167 call.arg3W = SysAllocStringLen(qname, qname_len);
1170 test_attr_ptr = saxattr;
1171 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1173 /* store actual attributes */
1175 hr = ISAXAttributes_getLength(saxattr, &len);
1176 EXPECT_HR(hr, S_OK);
1183 struct attribute_entry *attr;
1184 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1187 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1188 EXPECT_HR(hr, S_OK);
1190 for (i = 0; i < len; i++)
1195 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1196 &localname, &local_len, &qname, &qname_len);
1197 EXPECT_HR(hr, S_OK);
1199 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1200 EXPECT_HR(hr, S_OK);
1202 /* if 'namespaces' switched off uri and local name contains garbage */
1203 if (v == VARIANT_FALSE && msxml_version > 0)
1205 attr[i].uriW = SysAllocStringLen(NULL, 0);
1206 attr[i].localW = SysAllocStringLen(NULL, 0);
1210 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1211 attr[i].localW = SysAllocStringLen(localname, local_len);
1214 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1215 attr[i].valueW = SysAllocStringLen(value, value_len);
1218 call.attributes = attr;
1219 call.attr_count = len;
1222 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1224 return get_expected_ret();
1227 static HRESULT WINAPI contentHandler_endElement(
1228 ISAXContentHandler* iface,
1229 const WCHAR *uri, int uri_len,
1230 const WCHAR *localname, int local_len,
1231 const WCHAR *qname, int qname_len)
1233 struct call_entry call;
1235 init_call_entry(locator, &call);
1236 call.id = CH_ENDELEMENT;
1237 call.arg1W = SysAllocStringLen(uri, uri_len);
1238 call.arg2W = SysAllocStringLen(localname, local_len);
1239 call.arg3W = SysAllocStringLen(qname, qname_len);
1240 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1242 return get_expected_ret();
1245 static HRESULT WINAPI contentHandler_characters(
1246 ISAXContentHandler* iface,
1250 struct call_entry call;
1252 init_call_entry(locator, &call);
1253 call.id = CH_CHARACTERS;
1254 call.arg1W = SysAllocStringLen(chars, len);
1255 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1257 return get_expected_ret();
1260 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1261 ISAXContentHandler* iface,
1262 const WCHAR *chars, int len)
1264 struct call_entry call;
1266 init_call_entry(locator, &call);
1267 call.id = CH_IGNORABLEWHITESPACE;
1268 call.arg1W = SysAllocStringLen(chars, len);
1269 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1271 return get_expected_ret();
1274 static HRESULT WINAPI contentHandler_processingInstruction(
1275 ISAXContentHandler* iface,
1276 const WCHAR *target, int target_len,
1277 const WCHAR *data, int data_len)
1279 struct call_entry call;
1281 init_call_entry(locator, &call);
1282 call.id = CH_PROCESSINGINSTRUCTION;
1283 call.arg1W = SysAllocStringLen(target, target_len);
1284 call.arg2W = SysAllocStringLen(data, data_len);
1285 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1287 return get_expected_ret();
1290 static HRESULT WINAPI contentHandler_skippedEntity(
1291 ISAXContentHandler* iface,
1292 const WCHAR *name, int len)
1294 struct call_entry call;
1296 init_call_entry(locator, &call);
1297 call.id = CH_SKIPPEDENTITY;
1298 call.arg1W = SysAllocStringLen(name, len);
1299 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1301 return get_expected_ret();
1304 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1306 contentHandler_QueryInterface,
1307 contentHandler_AddRef,
1308 contentHandler_Release,
1309 contentHandler_putDocumentLocator,
1310 contentHandler_startDocument,
1311 contentHandler_endDocument,
1312 contentHandler_startPrefixMapping,
1313 contentHandler_endPrefixMapping,
1314 contentHandler_startElement,
1315 contentHandler_endElement,
1316 contentHandler_characters,
1317 contentHandler_ignorableWhitespace,
1318 contentHandler_processingInstruction,
1319 contentHandler_skippedEntity
1322 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1324 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1325 ISAXErrorHandler* iface,
1331 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1337 return E_NOINTERFACE;
1343 static ULONG WINAPI isaxerrorHandler_AddRef(
1344 ISAXErrorHandler* iface)
1349 static ULONG WINAPI isaxerrorHandler_Release(
1350 ISAXErrorHandler* iface)
1355 static HRESULT WINAPI isaxerrorHandler_error(
1356 ISAXErrorHandler* iface,
1357 ISAXLocator *pLocator,
1358 const WCHAR *pErrorMessage,
1359 HRESULT hrErrorCode)
1361 ok(0, "unexpected call\n");
1365 static HRESULT WINAPI isaxerrorHandler_fatalError(
1366 ISAXErrorHandler* iface,
1367 ISAXLocator *pLocator,
1368 const WCHAR *message,
1371 struct call_entry call;
1373 init_call_entry(locator, &call);
1374 call.id = EH_FATALERROR;
1377 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1383 static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
1384 ISAXErrorHandler* iface,
1385 ISAXLocator *pLocator,
1386 const WCHAR *pErrorMessage,
1387 HRESULT hrErrorCode)
1389 ok(0, "unexpected call\n");
1393 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1395 isaxerrorHandler_QueryInterface,
1396 isaxerrorHandler_AddRef,
1397 isaxerrorHandler_Release,
1398 isaxerrorHandler_error,
1399 isaxerrorHandler_fatalError,
1400 isaxerrorHandler_ignorableWarning
1403 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1405 static HRESULT WINAPI isaxattributes_QueryInterface(
1406 ISAXAttributes* iface,
1412 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1418 return E_NOINTERFACE;
1424 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1429 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1434 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1440 static HRESULT WINAPI isaxattributes_getURI(
1441 ISAXAttributes* iface,
1446 ok(0, "unexpected call\n");
1450 static HRESULT WINAPI isaxattributes_getLocalName(
1451 ISAXAttributes* iface,
1453 const WCHAR **pLocalName,
1454 int *pLocalNameLength)
1456 ok(0, "unexpected call\n");
1460 static HRESULT WINAPI isaxattributes_getQName(
1461 ISAXAttributes* iface,
1463 const WCHAR **QName,
1466 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1467 {'a','t','t','r','2','j','u','n','k',0},
1468 {'a','t','t','r','3',0}};
1469 static const int attrqnamelen[] = {7, 5, 5};
1471 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1473 *QName = attrqnamesW[index];
1474 *QNameLength = attrqnamelen[index];
1479 static HRESULT WINAPI isaxattributes_getName(
1480 ISAXAttributes* iface,
1484 const WCHAR ** pLocalName,
1485 int * pLocalNameSize,
1486 const WCHAR ** pQName,
1489 ok(0, "unexpected call\n");
1493 static HRESULT WINAPI isaxattributes_getIndexFromName(
1494 ISAXAttributes* iface,
1497 const WCHAR * pLocalName,
1498 int cocalNameLength,
1501 ok(0, "unexpected call\n");
1505 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1506 ISAXAttributes* iface,
1507 const WCHAR * pQName,
1511 ok(0, "unexpected call\n");
1515 static HRESULT WINAPI isaxattributes_getType(
1516 ISAXAttributes* iface,
1518 const WCHAR ** pType,
1521 ok(0, "unexpected call\n");
1525 static HRESULT WINAPI isaxattributes_getTypeFromName(
1526 ISAXAttributes* iface,
1529 const WCHAR * pLocalName,
1531 const WCHAR ** pType,
1534 ok(0, "unexpected call\n");
1538 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1539 ISAXAttributes* iface,
1540 const WCHAR * pQName,
1542 const WCHAR ** pType,
1545 ok(0, "unexpected call\n");
1549 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1550 const WCHAR **value, int *nValue)
1552 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1553 {'a','2','j','u','n','k',0},
1554 {'<','&','"','>',0}};
1555 static const int attrvalueslen[] = {2, 2, 4};
1557 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1559 *value = attrvaluesW[index];
1560 *nValue = attrvalueslen[index];
1565 static HRESULT WINAPI isaxattributes_getValueFromName(
1566 ISAXAttributes* iface,
1569 const WCHAR * pLocalName,
1571 const WCHAR ** pValue,
1574 ok(0, "unexpected call\n");
1578 static HRESULT WINAPI isaxattributes_getValueFromQName(
1579 ISAXAttributes* iface,
1580 const WCHAR * pQName,
1582 const WCHAR ** pValue,
1585 ok(0, "unexpected call\n");
1589 static const ISAXAttributesVtbl SAXAttributesVtbl =
1591 isaxattributes_QueryInterface,
1592 isaxattributes_AddRef,
1593 isaxattributes_Release,
1594 isaxattributes_getLength,
1595 isaxattributes_getURI,
1596 isaxattributes_getLocalName,
1597 isaxattributes_getQName,
1598 isaxattributes_getName,
1599 isaxattributes_getIndexFromName,
1600 isaxattributes_getIndexFromQName,
1601 isaxattributes_getType,
1602 isaxattributes_getTypeFromName,
1603 isaxattributes_getTypeFromQName,
1604 isaxattributes_getValue,
1605 isaxattributes_getValueFromName,
1606 isaxattributes_getValueFromQName
1609 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1611 struct saxlexicalhandler
1613 ISAXLexicalHandler ISAXLexicalHandler_iface;
1616 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1619 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1621 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1624 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1626 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1630 if (IsEqualGUID(riid, &IID_IUnknown))
1633 ok(0, "got unexpected IID_IUnknown query\n");
1635 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1637 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1642 ISAXLexicalHandler_AddRef(iface);
1644 return E_NOINTERFACE;
1649 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1651 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1652 return InterlockedIncrement(&handler->ref);
1655 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1657 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1658 return InterlockedDecrement(&handler->ref);
1661 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1662 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1663 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1665 ok(0, "call not expected\n");
1669 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1671 ok(0, "call not expected\n");
1675 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1676 const WCHAR * pName, int nName)
1678 ok(0, "call not expected\n");
1682 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1683 const WCHAR * pName, int nName)
1685 ok(0, "call not expected\n");
1689 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1691 struct call_entry call;
1693 init_call_entry(locator, &call);
1694 call.id = LH_STARTCDATA;
1695 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1697 return get_expected_ret();
1700 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1702 struct call_entry call;
1704 init_call_entry(locator, &call);
1705 call.id = LH_ENDCDATA;
1706 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1708 return get_expected_ret();
1711 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1712 const WCHAR * pChars, int nChars)
1714 ok(0, "call not expected\n");
1718 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1720 isaxlexical_QueryInterface,
1722 isaxlexical_Release,
1723 isaxlexical_startDTD,
1725 isaxlexical_startEntity,
1726 isaxlexical_endEntity,
1727 isaxlexical_startCDATA,
1728 isaxlexical_endCDATA,
1732 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1734 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1736 handler->qi_hr = hr;
1739 struct saxdeclhandler
1741 ISAXDeclHandler ISAXDeclHandler_iface;
1744 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1747 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1749 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1752 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1754 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1758 if (IsEqualGUID(riid, &IID_IUnknown))
1761 ok(0, "got unexpected IID_IUnknown query\n");
1763 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1765 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1770 ISAXDeclHandler_AddRef(iface);
1772 return E_NOINTERFACE;
1777 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1779 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1780 return InterlockedIncrement(&handler->ref);
1783 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1785 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1786 return InterlockedDecrement(&handler->ref);
1789 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1790 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1792 ok(0, "call not expected\n");
1796 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1797 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1798 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1799 int nValueDefault, const WCHAR * pValue, int nValue)
1801 ok(0, "call not expected\n");
1805 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1806 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1808 ok(0, "call not expected\n");
1812 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1813 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1814 const WCHAR * pSystemId, int nSystemId)
1816 ok(0, "call not expected\n");
1820 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1822 isaxdecl_QueryInterface,
1825 isaxdecl_elementDecl,
1826 isaxdecl_attributeDecl,
1827 isaxdecl_internalEntityDecl,
1828 isaxdecl_externalEntityDecl
1831 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1833 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1835 handler->qi_hr = hr;
1838 typedef struct mxwriter_write_test_t {
1844 } mxwriter_write_test;
1846 typedef struct mxwriter_stream_test_t {
1848 const char *encoding;
1849 mxwriter_write_test expected_writes[4];
1850 } mxwriter_stream_test;
1852 static const mxwriter_write_test *current_write_test;
1853 static DWORD current_stream_test_index;
1855 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1859 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1862 return E_NOINTERFACE;
1867 static ULONG WINAPI istream_AddRef(IStream *iface)
1872 static ULONG WINAPI istream_Release(IStream *iface)
1877 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1879 ok(0, "unexpected call\n");
1883 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1887 ok(pv != NULL, "pv == NULL\n");
1889 if(current_write_test->last) {
1890 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1894 fail = current_write_test->fail_write;
1896 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1897 current_write_test->cb, cb, current_stream_test_index);
1900 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1902 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1904 ++current_write_test;
1909 return fail ? E_FAIL : S_OK;
1912 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1913 ULARGE_INTEGER *plibNewPosition)
1915 ok(0, "unexpected call\n");
1919 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1921 ok(0, "unexpected call\n");
1925 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1926 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1928 ok(0, "unexpected call\n");
1932 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1934 ok(0, "unexpected call\n");
1938 static HRESULT WINAPI istream_Revert(IStream *iface)
1940 ok(0, "unexpected call\n");
1944 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1945 ULARGE_INTEGER cb, DWORD dwLockType)
1947 ok(0, "unexpected call\n");
1951 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1952 ULARGE_INTEGER cb, DWORD dwLockType)
1954 ok(0, "unexpected call\n");
1958 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1960 ok(0, "unexpected call\n");
1964 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1966 ok(0, "unexpected call\n");
1970 static const IStreamVtbl StreamVtbl = {
1971 istream_QueryInterface,
1982 istream_UnlockRegion,
1987 static IStream mxstream = { &StreamVtbl };
1989 static struct msxmlsupported_data_t reader_support_data[] =
1991 { &CLSID_SAXXMLReader, "SAXReader" },
1992 { &CLSID_SAXXMLReader30, "SAXReader30" },
1993 { &CLSID_SAXXMLReader40, "SAXReader40" },
1994 { &CLSID_SAXXMLReader60, "SAXReader60" },
1998 static struct saxlexicalhandler lexicalhandler;
1999 static struct saxdeclhandler declhandler;
2001 static IStream *create_test_stream(const char *data, int len)
2003 ULARGE_INTEGER size;
2008 if (len == -1) len = strlen(data);
2009 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2010 size.QuadPart = len;
2011 IStream_SetSize(stream, size);
2012 IStream_Write(stream, data, len, &written);
2014 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2019 static void test_saxreader(void)
2021 const struct msxmlsupported_data_t *table = reader_support_data;
2023 ISAXXMLReader *reader = NULL;
2025 ISAXContentHandler *content;
2026 ISAXErrorHandler *lpErrorHandler;
2028 SAFEARRAYBOUND SADim[1];
2033 static const CHAR testXmlA[] = "test.xml";
2034 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2035 IXMLDOMDocument *doc;
2038 while (table->clsid)
2040 struct call_entry *test_seq;
2041 ISAXEntityResolver *resolver;
2044 if (!is_clsid_supported(table->clsid, reader_support_data))
2050 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2051 EXPECT_HR(hr, S_OK);
2054 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2056 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2061 /* crashes on old versions */
2062 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2063 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2065 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2066 EXPECT_HR(hr, E_POINTER);
2068 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2069 EXPECT_HR(hr, E_POINTER);
2072 hr = ISAXXMLReader_getContentHandler(reader, &content);
2073 EXPECT_HR(hr, S_OK);
2074 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2076 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2077 EXPECT_HR(hr, S_OK);
2078 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2080 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2081 EXPECT_HR(hr, S_OK);
2083 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2084 EXPECT_HR(hr, S_OK);
2086 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2087 EXPECT_HR(hr, S_OK);
2089 hr = ISAXXMLReader_getContentHandler(reader, &content);
2090 EXPECT_HR(hr, S_OK);
2091 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2093 V_VT(&var) = VT_BSTR;
2094 V_BSTR(&var) = SysAllocString(szSimpleXML);
2096 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2097 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2098 test_seq = content_handler_test1_alternate;
2100 test_seq = content_handler_test1;
2101 set_expected_seq(test_seq);
2102 hr = ISAXXMLReader_parse(reader, var);
2103 EXPECT_HR(hr, S_OK);
2104 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2108 SADim[0].lLbound = 0;
2109 SADim[0].cElements = sizeof(testXML)-1;
2110 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2111 SafeArrayAccessData(sa, (void**)&ptr);
2112 memcpy(ptr, testXML, sizeof(testXML)-1);
2113 SafeArrayUnaccessData(sa);
2114 V_VT(&var) = VT_ARRAY|VT_UI1;
2117 set_expected_seq(test_seq);
2118 hr = ISAXXMLReader_parse(reader, var);
2119 EXPECT_HR(hr, S_OK);
2120 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2122 SafeArrayDestroy(sa);
2124 stream = create_test_stream(testXML, -1);
2125 V_VT(&var) = VT_UNKNOWN;
2126 V_UNKNOWN(&var) = (IUnknown*)stream;
2128 set_expected_seq(test_seq);
2129 hr = ISAXXMLReader_parse(reader, var);
2130 EXPECT_HR(hr, S_OK);
2131 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2133 IStream_Release(stream);
2135 stream = create_test_stream(test_attributes, -1);
2136 V_VT(&var) = VT_UNKNOWN;
2137 V_UNKNOWN(&var) = (IUnknown*)stream;
2139 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2140 test_seq = content_handler_test_attributes_alternate_4;
2141 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2142 test_seq = content_handler_test_attributes_alternate_6;
2144 test_seq = content_handler_test_attributes;
2146 set_expected_seq(test_seq);
2147 hr = ISAXXMLReader_parse(reader, var);
2148 EXPECT_HR(hr, S_OK);
2150 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2151 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2152 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2154 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2156 IStream_Release(stream);
2158 V_VT(&var) = VT_BSTR;
2159 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2161 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2162 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2163 test_seq = content_handler_test2_alternate;
2165 test_seq = content_handler_test2;
2167 set_expected_seq(test_seq);
2168 hr = ISAXXMLReader_parse(reader, var);
2169 EXPECT_HR(hr, S_OK);
2170 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2175 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2176 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2177 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2180 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2181 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2182 test_seq = content_handler_test1_alternate;
2184 test_seq = content_handler_test1;
2185 set_expected_seq(test_seq);
2186 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2187 EXPECT_HR(hr, S_OK);
2188 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2191 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2192 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2193 test_seq = content_handler_testerror_alternate;
2195 test_seq = content_handler_testerror;
2196 set_expected_seq(test_seq);
2197 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2198 EXPECT_HR(hr, E_FAIL);
2199 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2201 /* callback ret values */
2202 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2203 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2205 test_seq = content_handler_test_callback_rets_alt;
2206 set_expected_seq(test_seq);
2207 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2208 EXPECT_HR(hr, S_OK);
2212 test_seq = content_handler_test_callback_rets;
2213 set_expected_seq(test_seq);
2214 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2215 EXPECT_HR(hr, S_FALSE);
2217 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2219 DeleteFileA(testXmlA);
2221 /* parse from IXMLDOMDocument */
2222 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2223 &IID_IXMLDOMDocument, (void**)&doc);
2224 EXPECT_HR(hr, S_OK);
2226 str = SysAllocString(szSimpleXML);
2227 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2228 EXPECT_HR(hr, S_OK);
2231 V_VT(&var) = VT_UNKNOWN;
2232 V_UNKNOWN(&var) = (IUnknown*)doc;
2234 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2235 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2236 test_seq = content_handler_test2_alternate;
2238 test_seq = content_handler_test2;
2240 set_expected_seq(test_seq);
2241 hr = ISAXXMLReader_parse(reader, var);
2242 EXPECT_HR(hr, S_OK);
2243 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2244 IXMLDOMDocument_Release(doc);
2246 /* xml:space test */
2247 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2248 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2250 test_seq = xmlspaceattr_test_alternate;
2253 test_seq = xmlspaceattr_test;
2255 set_expected_seq(test_seq);
2256 V_VT(&var) = VT_BSTR;
2257 V_BSTR(&var) = _bstr_(xmlspace_attr);
2258 hr = ISAXXMLReader_parse(reader, var);
2259 EXPECT_HR(hr, S_OK);
2261 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2262 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2264 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2267 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2269 /* switch off 'namespaces' feature */
2270 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2271 EXPECT_HR(hr, S_OK);
2273 stream = create_test_stream(test_attributes, -1);
2274 V_VT(&var) = VT_UNKNOWN;
2275 V_UNKNOWN(&var) = (IUnknown*)stream;
2277 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2278 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2280 test_seq = content_handler_test_attributes_alt_no_ns;
2283 test_seq = content_handler_test_attributes;
2285 set_expected_seq(test_seq);
2286 hr = ISAXXMLReader_parse(reader, var);
2287 EXPECT_HR(hr, S_OK);
2288 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2289 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2290 EXPECT_HR(hr, S_OK);
2292 /* switch off 'namespace-prefixes' feature */
2293 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2294 EXPECT_HR(hr, S_OK);
2296 stream = create_test_stream(test_attributes, -1);
2297 V_VT(&var) = VT_UNKNOWN;
2298 V_UNKNOWN(&var) = (IUnknown*)stream;
2300 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2301 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2303 test_seq = content_handler_test_attributes_alt_no_prefix;
2306 test_seq = content_handler_test_attributes_no_prefix;
2308 set_expected_seq(test_seq);
2309 hr = ISAXXMLReader_parse(reader, var);
2310 EXPECT_HR(hr, S_OK);
2311 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2313 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2314 EXPECT_HR(hr, S_OK);
2316 /* attribute normalization */
2317 stream = create_test_stream(attribute_normalize, -1);
2318 V_VT(&var) = VT_UNKNOWN;
2319 V_UNKNOWN(&var) = (IUnknown*)stream;
2321 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2322 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2324 test_seq = attribute_norm_alt;
2327 test_seq = attribute_norm;
2329 set_expected_seq(test_seq);
2330 hr = ISAXXMLReader_parse(reader, var);
2331 EXPECT_HR(hr, S_OK);
2332 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2334 resolver = (void*)0xdeadbeef;
2335 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2336 ok(hr == S_OK, "got 0x%08x\n", hr);
2337 ok(resolver == NULL, "got %p\n", resolver);
2339 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2340 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2342 /* CDATA sections */
2343 init_saxlexicalhandler(&lexicalhandler, S_OK);
2345 V_VT(&var) = VT_UNKNOWN;
2346 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2347 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2348 ok(hr == S_OK, "got 0x%08x\n", hr);
2350 stream = create_test_stream(test_cdata_xml, -1);
2351 V_VT(&var) = VT_UNKNOWN;
2352 V_UNKNOWN(&var) = (IUnknown*)stream;
2354 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2355 test_seq = cdata_test_alt;
2357 test_seq = cdata_test;
2359 set_expected_seq(test_seq);
2360 hr = ISAXXMLReader_parse(reader, var);
2361 ok(hr == S_OK, "got 0x%08x\n", hr);
2362 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test", TRUE);
2364 /* 2. CDATA sections */
2365 stream = create_test_stream(test2_cdata_xml, -1);
2366 V_VT(&var) = VT_UNKNOWN;
2367 V_UNKNOWN(&var) = (IUnknown*)stream;
2369 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2370 test_seq = cdata_test2_alt;
2372 test_seq = cdata_test2;
2374 set_expected_seq(test_seq);
2375 hr = ISAXXMLReader_parse(reader, var);
2376 ok(hr == S_OK, "got 0x%08x\n", hr);
2377 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test 2", TRUE);
2379 IStream_Release(stream);
2381 /* 3. CDATA sections */
2382 stream = create_test_stream(test3_cdata_xml, -1);
2383 V_VT(&var) = VT_UNKNOWN;
2384 V_UNKNOWN(&var) = (IUnknown*)stream;
2386 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2387 test_seq = cdata_test3_alt;
2389 test_seq = cdata_test3;
2391 set_expected_seq(test_seq);
2392 hr = ISAXXMLReader_parse(reader, var);
2393 ok(hr == S_OK, "got 0x%08x\n", hr);
2394 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test 3", TRUE);
2396 IStream_Release(stream);
2398 ISAXXMLReader_Release(reader);
2405 struct saxreader_props_test_t
2407 const char *prop_name;
2411 static const struct saxreader_props_test_t props_test_data[] = {
2412 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2413 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2417 static void test_saxreader_properties(void)
2419 const struct saxreader_props_test_t *ptr = props_test_data;
2420 ISAXXMLReader *reader;
2424 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2425 &IID_ISAXXMLReader, (void**)&reader);
2426 EXPECT_HR(hr, S_OK);
2428 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2429 EXPECT_HR(hr, E_POINTER);
2431 while (ptr->prop_name)
2435 init_saxlexicalhandler(&lexicalhandler, S_OK);
2436 init_saxdeclhandler(&declhandler, S_OK);
2438 V_VT(&v) = VT_EMPTY;
2439 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2440 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2441 EXPECT_HR(hr, S_OK);
2442 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2443 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2445 V_VT(&v) = VT_UNKNOWN;
2446 V_UNKNOWN(&v) = ptr->iface;
2447 ref = get_refcount(ptr->iface);
2448 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2449 EXPECT_HR(hr, S_OK);
2450 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2452 V_VT(&v) = VT_EMPTY;
2453 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2455 ref = get_refcount(ptr->iface);
2456 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2457 EXPECT_HR(hr, S_OK);
2458 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2459 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2460 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2463 V_VT(&v) = VT_EMPTY;
2464 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2465 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2466 EXPECT_HR(hr, S_OK);
2468 V_VT(&v) = VT_EMPTY;
2469 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2470 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2471 EXPECT_HR(hr, S_OK);
2472 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2473 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2475 V_VT(&v) = VT_UNKNOWN;
2476 V_UNKNOWN(&v) = ptr->iface;
2477 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2478 EXPECT_HR(hr, S_OK);
2480 /* only VT_EMPTY seems to be valid to reset property */
2482 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2483 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2484 EXPECT_HR(hr, E_INVALIDARG);
2486 V_VT(&v) = VT_EMPTY;
2487 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2488 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2489 EXPECT_HR(hr, S_OK);
2490 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2491 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2494 V_VT(&v) = VT_UNKNOWN;
2495 V_UNKNOWN(&v) = NULL;
2496 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2497 EXPECT_HR(hr, S_OK);
2499 V_VT(&v) = VT_EMPTY;
2500 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2501 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2502 EXPECT_HR(hr, S_OK);
2503 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2504 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2506 /* block QueryInterface on handler riid */
2507 V_VT(&v) = VT_UNKNOWN;
2508 V_UNKNOWN(&v) = ptr->iface;
2509 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2510 EXPECT_HR(hr, S_OK);
2512 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2513 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2515 V_VT(&v) = VT_UNKNOWN;
2516 V_UNKNOWN(&v) = ptr->iface;
2517 EXPECT_REF(ptr->iface, 1);
2518 ref = get_refcount(ptr->iface);
2519 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2520 EXPECT_HR(hr, E_NOINTERFACE);
2521 EXPECT_REF(ptr->iface, 1);
2523 V_VT(&v) = VT_EMPTY;
2524 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2525 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2526 EXPECT_HR(hr, S_OK);
2527 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2528 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2534 ISAXXMLReader_Release(reader);
2536 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2539 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2540 &IID_ISAXXMLReader, (void**)&reader);
2541 EXPECT_HR(hr, S_OK);
2543 /* xmldecl-version property */
2544 V_VT(&v) = VT_EMPTY;
2545 V_BSTR(&v) = (void*)0xdeadbeef;
2546 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2547 EXPECT_HR(hr, S_OK);
2548 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2549 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2551 /* stream without declaration */
2553 V_BSTR(&v) = _bstr_("<element></element>");
2554 hr = ISAXXMLReader_parse(reader, v);
2555 EXPECT_HR(hr, S_OK);
2557 V_VT(&v) = VT_EMPTY;
2558 V_BSTR(&v) = (void*)0xdeadbeef;
2559 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2560 EXPECT_HR(hr, S_OK);
2561 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2562 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2564 /* stream with declaration */
2566 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2567 hr = ISAXXMLReader_parse(reader, v);
2568 EXPECT_HR(hr, S_OK);
2570 V_VT(&v) = VT_EMPTY;
2571 V_BSTR(&v) = (void*)0xdeadbeef;
2572 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2573 EXPECT_HR(hr, S_OK);
2574 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2575 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2578 ISAXXMLReader_Release(reader);
2582 struct feature_ns_entry_t {
2586 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2589 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2590 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2591 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2592 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2593 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2597 static const char *feature_names[] = {
2598 "http://xml.org/sax/features/namespaces",
2599 "http://xml.org/sax/features/namespace-prefixes",
2603 static void test_saxreader_features(void)
2605 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2606 ISAXXMLReader *reader;
2614 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2617 win_skip("can't create %s instance\n", entry->clsid);
2622 name = feature_names;
2626 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2627 EXPECT_HR(hr, S_OK);
2628 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2631 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2632 EXPECT_HR(hr, S_OK);
2635 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2636 EXPECT_HR(hr, S_OK);
2637 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2639 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2640 EXPECT_HR(hr, S_OK);
2642 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2643 EXPECT_HR(hr, S_OK);
2644 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2646 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2647 EXPECT_HR(hr, S_OK);
2649 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2650 EXPECT_HR(hr, S_OK);
2651 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2656 ISAXXMLReader_Release(reader);
2662 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2663 static const CHAR UTF8BOMTest[] =
2664 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2667 struct enc_test_entry_t {
2675 static const struct enc_test_entry_t encoding_test_data[] = {
2676 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2677 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2678 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2679 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2683 static void test_saxreader_encoding(void)
2685 const struct enc_test_entry_t *entry = encoding_test_data;
2686 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2687 static const CHAR testXmlA[] = "test.xml";
2691 ISAXXMLReader *reader;
2697 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2700 win_skip("can't create %s instance\n", entry->clsid);
2705 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2706 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2707 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2710 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2712 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2714 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2716 DeleteFileA(testXmlA);
2718 /* try BSTR input with no BOM or '<?xml' instruction */
2719 V_VT(&input) = VT_BSTR;
2720 V_BSTR(&input) = _bstr_("<element></element>");
2721 hr = ISAXXMLReader_parse(reader, input);
2722 EXPECT_HR(hr, S_OK);
2724 ISAXXMLReader_Release(reader);
2731 static void test_mxwriter_handlers(void)
2733 ISAXContentHandler *handler;
2734 IMXWriter *writer, *writer2;
2735 ISAXDeclHandler *decl;
2736 ISAXLexicalHandler *lh;
2739 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2740 &IID_IMXWriter, (void**)&writer);
2741 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2743 EXPECT_REF(writer, 1);
2745 /* ISAXContentHandler */
2746 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2747 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2748 EXPECT_REF(writer, 2);
2749 EXPECT_REF(handler, 2);
2751 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2752 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2753 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2754 EXPECT_REF(writer, 3);
2755 EXPECT_REF(writer2, 3);
2756 IMXWriter_Release(writer2);
2757 ISAXContentHandler_Release(handler);
2759 /* ISAXLexicalHandler */
2760 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2761 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2762 EXPECT_REF(writer, 2);
2765 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2766 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2767 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2768 EXPECT_REF(writer, 3);
2769 EXPECT_REF(writer2, 3);
2770 IMXWriter_Release(writer2);
2771 ISAXLexicalHandler_Release(lh);
2773 /* ISAXDeclHandler */
2774 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2775 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2776 EXPECT_REF(writer, 2);
2779 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2780 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2781 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2782 EXPECT_REF(writer, 3);
2783 EXPECT_REF(writer2, 3);
2784 IMXWriter_Release(writer2);
2785 ISAXDeclHandler_Release(decl);
2787 IMXWriter_Release(writer);
2791 static struct msxmlsupported_data_t mxwriter_support_data[] =
2793 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2794 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2795 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2796 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2800 static struct msxmlsupported_data_t mxattributes_support_data[] =
2802 { &CLSID_SAXAttributes, "SAXAttributes" },
2803 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2804 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2805 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2809 struct mxwriter_props_t
2813 VARIANT_BOOL disable_escape;
2814 VARIANT_BOOL indent;
2815 VARIANT_BOOL omitdecl;
2816 VARIANT_BOOL standalone;
2817 const char *encoding;
2820 static const struct mxwriter_props_t mxwriter_default_props[] =
2822 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2823 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2824 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2825 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2829 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2833 while (table->clsid)
2840 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2847 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2848 &IID_IMXWriter, (void**)&writer);
2849 EXPECT_HR(hr, S_OK);
2852 hr = IMXWriter_get_byteOrderMark(writer, &b);
2853 EXPECT_HR(hr, S_OK);
2854 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2856 b = !table->disable_escape;
2857 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2858 EXPECT_HR(hr, S_OK);
2859 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2860 table->disable_escape);
2863 hr = IMXWriter_get_indent(writer, &b);
2864 EXPECT_HR(hr, S_OK);
2865 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2867 b = !table->omitdecl;
2868 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2869 EXPECT_HR(hr, S_OK);
2870 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2872 b = !table->standalone;
2873 hr = IMXWriter_get_standalone(writer, &b);
2874 EXPECT_HR(hr, S_OK);
2875 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2877 hr = IMXWriter_get_encoding(writer, &encoding);
2878 EXPECT_HR(hr, S_OK);
2879 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2880 i, wine_dbgstr_w(encoding), table->encoding);
2881 SysFreeString(encoding);
2883 IMXWriter_Release(writer);
2890 static void test_mxwriter_properties(void)
2892 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2893 static const WCHAR emptyW[] = {0};
2894 static const WCHAR testW[] = {'t','e','s','t',0};
2895 ISAXContentHandler *content;
2902 test_mxwriter_default_properties(mxwriter_default_props);
2904 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2905 &IID_IMXWriter, (void**)&writer);
2906 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2908 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2909 ok(hr == E_POINTER, "got %08x\n", hr);
2911 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2912 ok(hr == E_POINTER, "got %08x\n", hr);
2914 hr = IMXWriter_get_indent(writer, NULL);
2915 ok(hr == E_POINTER, "got %08x\n", hr);
2917 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2918 ok(hr == E_POINTER, "got %08x\n", hr);
2920 hr = IMXWriter_get_standalone(writer, NULL);
2921 ok(hr == E_POINTER, "got %08x\n", hr);
2924 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2925 ok(hr == S_OK, "got %08x\n", hr);
2928 hr = IMXWriter_get_standalone(writer, &b);
2929 ok(hr == S_OK, "got %08x\n", hr);
2930 ok(b == VARIANT_TRUE, "got %d\n", b);
2932 hr = IMXWriter_get_encoding(writer, NULL);
2933 EXPECT_HR(hr, E_POINTER);
2935 /* UTF-16 is a default setting apparently */
2936 str = (void*)0xdeadbeef;
2937 hr = IMXWriter_get_encoding(writer, &str);
2938 EXPECT_HR(hr, S_OK);
2939 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2941 str2 = (void*)0xdeadbeef;
2942 hr = IMXWriter_get_encoding(writer, &str2);
2943 ok(hr == S_OK, "got %08x\n", hr);
2944 ok(str != str2, "expected newly allocated, got same %p\n", str);
2946 SysFreeString(str2);
2949 /* put empty string */
2950 str = SysAllocString(emptyW);
2951 hr = IMXWriter_put_encoding(writer, str);
2952 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2955 str = (void*)0xdeadbeef;
2956 hr = IMXWriter_get_encoding(writer, &str);
2957 EXPECT_HR(hr, S_OK);
2958 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2961 /* invalid encoding name */
2962 str = SysAllocString(testW);
2963 hr = IMXWriter_put_encoding(writer, str);
2964 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2967 /* test case sensivity */
2968 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2969 EXPECT_HR(hr, S_OK);
2970 str = (void*)0xdeadbeef;
2971 hr = IMXWriter_get_encoding(writer, &str);
2972 EXPECT_HR(hr, S_OK);
2973 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2976 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2977 EXPECT_HR(hr, S_OK);
2978 str = (void*)0xdeadbeef;
2979 hr = IMXWriter_get_encoding(writer, &str);
2980 EXPECT_HR(hr, S_OK);
2981 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2984 /* how it affects document creation */
2985 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2986 EXPECT_HR(hr, S_OK);
2988 hr = ISAXContentHandler_startDocument(content);
2989 EXPECT_HR(hr, S_OK);
2990 hr = ISAXContentHandler_endDocument(content);
2991 EXPECT_HR(hr, S_OK);
2993 V_VT(&dest) = VT_EMPTY;
2994 hr = IMXWriter_get_output(writer, &dest);
2995 EXPECT_HR(hr, S_OK);
2996 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2997 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2998 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2999 VariantClear(&dest);
3000 ISAXContentHandler_Release(content);
3002 hr = IMXWriter_get_version(writer, NULL);
3003 ok(hr == E_POINTER, "got %08x\n", hr);
3004 /* default version is 'surprisingly' 1.0 */
3005 hr = IMXWriter_get_version(writer, &str);
3006 ok(hr == S_OK, "got %08x\n", hr);
3007 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3010 /* store version string as is */
3011 hr = IMXWriter_put_version(writer, NULL);
3012 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3014 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3015 ok(hr == S_OK, "got %08x\n", hr);
3017 hr = IMXWriter_put_version(writer, _bstr_(""));
3018 ok(hr == S_OK, "got %08x\n", hr);
3019 hr = IMXWriter_get_version(writer, &str);
3020 ok(hr == S_OK, "got %08x\n", hr);
3021 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3024 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3025 ok(hr == S_OK, "got %08x\n", hr);
3026 hr = IMXWriter_get_version(writer, &str);
3027 ok(hr == S_OK, "got %08x\n", hr);
3028 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3031 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3032 ok(hr == S_OK, "got %08x\n", hr);
3033 hr = IMXWriter_get_version(writer, &str);
3034 ok(hr == S_OK, "got %08x\n", hr);
3035 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3038 IMXWriter_Release(writer);
3042 static void test_mxwriter_flush(void)
3044 static const WCHAR emptyW[] = {0};
3045 ISAXContentHandler *content;
3048 ULARGE_INTEGER pos2;
3056 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3057 &IID_IMXWriter, (void**)&writer);
3058 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3060 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3061 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3062 EXPECT_REF(stream, 1);
3064 /* detach when nothing was attached */
3065 V_VT(&dest) = VT_EMPTY;
3066 hr = IMXWriter_put_output(writer, dest);
3067 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3070 V_VT(&dest) = VT_UNKNOWN;
3071 V_UNKNOWN(&dest) = (IUnknown*)stream;
3072 hr = IMXWriter_put_output(writer, dest);
3073 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3074 todo_wine EXPECT_REF(stream, 3);
3076 /* detach setting VT_EMPTY destination */
3077 V_VT(&dest) = VT_EMPTY;
3078 hr = IMXWriter_put_output(writer, dest);
3079 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3080 EXPECT_REF(stream, 1);
3082 V_VT(&dest) = VT_UNKNOWN;
3083 V_UNKNOWN(&dest) = (IUnknown*)stream;
3084 hr = IMXWriter_put_output(writer, dest);
3085 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3087 /* flush() doesn't detach a stream */
3088 hr = IMXWriter_flush(writer);
3089 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3090 todo_wine EXPECT_REF(stream, 3);
3093 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3094 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3095 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3097 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3098 ok(hr == S_OK, "got %08x\n", hr);
3100 hr = ISAXContentHandler_startDocument(content);
3101 ok(hr == S_OK, "got %08x\n", hr);
3104 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3105 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3106 ok(pos2.QuadPart != 0, "expected stream beginning\n");
3108 /* already started */
3109 hr = ISAXContentHandler_startDocument(content);
3110 ok(hr == S_OK, "got %08x\n", hr);
3112 hr = ISAXContentHandler_endDocument(content);
3113 ok(hr == S_OK, "got %08x\n", hr);
3115 /* flushed on endDocument() */
3117 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3118 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3119 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3121 IStream_Release(stream);
3123 /* auto-flush feature */
3124 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3125 EXPECT_HR(hr, S_OK);
3126 EXPECT_REF(stream, 1);
3128 V_VT(&dest) = VT_UNKNOWN;
3129 V_UNKNOWN(&dest) = (IUnknown*)stream;
3130 hr = IMXWriter_put_output(writer, dest);
3131 EXPECT_HR(hr, S_OK);
3133 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
3134 EXPECT_HR(hr, S_OK);
3136 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3137 EXPECT_HR(hr, S_OK);
3139 hr = ISAXContentHandler_startDocument(content);
3140 EXPECT_HR(hr, S_OK);
3142 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3143 EXPECT_HR(hr, S_OK);
3145 /* internal buffer is flushed automatically on certain threshold */
3148 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3149 EXPECT_HR(hr, S_OK);
3150 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3153 buff = HeapAlloc(GetProcessHeap(), 0, len);
3154 memset(buff, 'A', len);
3155 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3156 EXPECT_HR(hr, S_OK);
3160 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3161 EXPECT_HR(hr, S_OK);
3163 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
3165 hr = IMXWriter_get_output(writer, NULL);
3166 EXPECT_HR(hr, E_POINTER);
3168 ref = get_refcount(stream);
3169 V_VT(&dest) = VT_EMPTY;
3170 hr = IMXWriter_get_output(writer, &dest);
3171 EXPECT_HR(hr, S_OK);
3172 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3173 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3174 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3175 VariantClear(&dest);
3177 hr = ISAXContentHandler_endDocument(content);
3178 EXPECT_HR(hr, S_OK);
3180 IStream_Release(stream);
3182 /* test char count lower than threshold */
3183 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3184 EXPECT_HR(hr, S_OK);
3185 EXPECT_REF(stream, 1);
3187 hr = ISAXContentHandler_startDocument(content);
3188 EXPECT_HR(hr, S_OK);
3190 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3191 EXPECT_HR(hr, S_OK);
3195 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3196 EXPECT_HR(hr, S_OK);
3197 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3199 memset(buff, 'A', len);
3200 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3201 EXPECT_HR(hr, S_OK);
3205 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3206 EXPECT_HR(hr, S_OK);
3207 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3209 hr = ISAXContentHandler_endDocument(content);
3210 EXPECT_HR(hr, S_OK);
3212 /* test auto-flush function when stream is not set */
3213 V_VT(&dest) = VT_EMPTY;
3214 hr = IMXWriter_put_output(writer, dest);
3215 EXPECT_HR(hr, S_OK);
3217 hr = ISAXContentHandler_startDocument(content);
3218 EXPECT_HR(hr, S_OK);
3220 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3221 EXPECT_HR(hr, S_OK);
3223 memset(buff, 'A', len);
3224 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3225 EXPECT_HR(hr, S_OK);
3227 V_VT(&dest) = VT_EMPTY;
3228 hr = IMXWriter_get_output(writer, &dest);
3229 EXPECT_HR(hr, S_OK);
3230 len += strlen("<a>");
3231 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3232 VariantClear(&dest);
3234 HeapFree(GetProcessHeap(), 0, buff);
3235 ISAXContentHandler_Release(content);
3236 IStream_Release(stream);
3237 IMXWriter_Release(writer);
3241 static void test_mxwriter_startenddocument(void)
3243 ISAXContentHandler *content;
3248 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3249 &IID_IMXWriter, (void**)&writer);
3250 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3252 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3253 ok(hr == S_OK, "got %08x\n", hr);
3255 hr = ISAXContentHandler_startDocument(content);
3256 ok(hr == S_OK, "got %08x\n", hr);
3258 hr = ISAXContentHandler_endDocument(content);
3259 ok(hr == S_OK, "got %08x\n", hr);
3261 V_VT(&dest) = VT_EMPTY;
3262 hr = IMXWriter_get_output(writer, &dest);
3263 ok(hr == S_OK, "got %08x\n", hr);
3264 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3265 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3266 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3267 VariantClear(&dest);
3269 /* now try another startDocument */
3270 hr = ISAXContentHandler_startDocument(content);
3271 ok(hr == S_OK, "got %08x\n", hr);
3272 /* and get duplicated prolog */
3273 V_VT(&dest) = VT_EMPTY;
3274 hr = IMXWriter_get_output(writer, &dest);
3275 ok(hr == S_OK, "got %08x\n", hr);
3276 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3277 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3278 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3279 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3280 VariantClear(&dest);
3282 ISAXContentHandler_Release(content);
3283 IMXWriter_Release(writer);
3285 /* now with omitted declaration */
3286 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3287 &IID_IMXWriter, (void**)&writer);
3288 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3290 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3291 ok(hr == S_OK, "got %08x\n", hr);
3293 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3294 ok(hr == S_OK, "got %08x\n", hr);
3296 hr = ISAXContentHandler_startDocument(content);
3297 ok(hr == S_OK, "got %08x\n", hr);
3299 hr = ISAXContentHandler_endDocument(content);
3300 ok(hr == S_OK, "got %08x\n", hr);
3302 V_VT(&dest) = VT_EMPTY;
3303 hr = IMXWriter_get_output(writer, &dest);
3304 ok(hr == S_OK, "got %08x\n", hr);
3305 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3306 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3307 VariantClear(&dest);
3309 ISAXContentHandler_Release(content);
3310 IMXWriter_Release(writer);
3317 StartElement = 0x001,
3319 StartEndElement = 0x011,
3320 DisableEscaping = 0x100
3323 struct writer_startendelement_t {
3325 enum startendtype type;
3327 const char *local_name;
3331 ISAXAttributes *attr;
3334 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\">";
3335 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\"/>";
3336 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
3338 static const struct writer_startendelement_t writer_startendelement[] = {
3340 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3341 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3342 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3343 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3344 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3346 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3347 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3348 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3349 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3350 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3352 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3353 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3354 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3355 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3356 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3358 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3359 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3360 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3361 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3362 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3364 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3365 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3366 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3367 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3368 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3370 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3371 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3372 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3373 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3374 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3376 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3377 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3378 /* endElement tests */
3379 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3380 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3381 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3383 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3384 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3385 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3386 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3387 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3389 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3390 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3391 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3392 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3393 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3395 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3396 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3397 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3398 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3399 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3401 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3402 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3403 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3404 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3405 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3407 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3408 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3409 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3410 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3411 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3413 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3414 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3415 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3416 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3418 /* with attributes */
3419 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3421 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3422 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3423 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3424 /* empty elements */
3425 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3426 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3428 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3429 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3430 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3431 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3432 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3434 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3436 /* with disabled output escaping */
3437 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3438 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3439 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3440 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3445 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3447 while (table->clsid)
3452 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3453 if (hr == S_OK) IUnknown_Release(unk);
3455 table->supported = hr == S_OK;
3456 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3462 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3466 while (table->clsid)
3468 ISAXContentHandler *content;
3472 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3479 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3480 &IID_IMXWriter, (void**)&writer);
3481 EXPECT_HR(hr, S_OK);
3483 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3484 EXPECT_HR(hr, S_OK);
3486 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3487 EXPECT_HR(hr, S_OK);
3489 hr = ISAXContentHandler_startDocument(content);
3490 EXPECT_HR(hr, S_OK);
3492 if (table->type & DisableEscaping)
3494 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3495 EXPECT_HR(hr, S_OK);
3498 if (table->type & StartElement)
3500 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3501 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3502 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3505 if (table->type & EndElement)
3507 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3508 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3509 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3517 V_VT(&dest) = VT_EMPTY;
3518 hr = IMXWriter_get_output(writer, &dest);
3519 EXPECT_HR(hr, S_OK);
3520 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3521 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3522 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3523 VariantClear(&dest);
3526 ISAXContentHandler_Release(content);
3527 IMXWriter_Release(writer);
3536 /* point of these test is to start/end element with different names and name lengths */
3537 struct writer_startendelement2_t {
3539 const char *qnamestart;
3541 const char *qnameend;
3547 static const struct writer_startendelement2_t writer_startendelement2[] = {
3548 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3549 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3550 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3551 /* -1 length is not allowed for version 6 */
3552 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3554 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3555 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3556 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3557 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3561 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3565 while (table->clsid)
3567 ISAXContentHandler *content;
3571 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3578 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3579 &IID_IMXWriter, (void**)&writer);
3580 EXPECT_HR(hr, S_OK);
3582 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3583 EXPECT_HR(hr, S_OK);
3585 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3586 EXPECT_HR(hr, S_OK);
3588 hr = ISAXContentHandler_startDocument(content);
3589 EXPECT_HR(hr, S_OK);
3591 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3592 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3593 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3595 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3596 _bstr_(table->qnameend), table->qnameend_len);
3597 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3604 V_VT(&dest) = VT_EMPTY;
3605 hr = IMXWriter_get_output(writer, &dest);
3606 EXPECT_HR(hr, S_OK);
3607 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3608 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3609 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3610 VariantClear(&dest);
3613 ISAXContentHandler_Release(content);
3614 IMXWriter_Release(writer);
3624 static void test_mxwriter_startendelement(void)
3626 ISAXContentHandler *content;
3631 test_mxwriter_startendelement_batch(writer_startendelement);
3632 test_mxwriter_startendelement_batch2(writer_startendelement2);
3634 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3635 &IID_IMXWriter, (void**)&writer);
3636 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3638 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3639 ok(hr == S_OK, "got %08x\n", hr);
3641 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3642 ok(hr == S_OK, "got %08x\n", hr);
3644 hr = ISAXContentHandler_startDocument(content);
3645 ok(hr == S_OK, "got %08x\n", hr);
3647 /* all string pointers should be not null */
3648 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3649 ok(hr == S_OK, "got %08x\n", hr);
3651 V_VT(&dest) = VT_EMPTY;
3652 hr = IMXWriter_get_output(writer, &dest);
3653 ok(hr == S_OK, "got %08x\n", hr);
3654 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3655 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3656 VariantClear(&dest);
3658 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3659 ok(hr == S_OK, "got %08x\n", hr);
3661 V_VT(&dest) = VT_EMPTY;
3662 hr = IMXWriter_get_output(writer, &dest);
3663 ok(hr == S_OK, "got %08x\n", hr);
3664 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3665 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3666 VariantClear(&dest);
3668 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3669 EXPECT_HR(hr, E_INVALIDARG);
3671 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3672 EXPECT_HR(hr, E_INVALIDARG);
3674 /* only local name is an error too */
3675 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3676 EXPECT_HR(hr, E_INVALIDARG);
3678 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3679 EXPECT_HR(hr, S_OK);
3681 V_VT(&dest) = VT_EMPTY;
3682 hr = IMXWriter_get_output(writer, &dest);
3683 EXPECT_HR(hr, S_OK);
3684 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3685 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3686 VariantClear(&dest);
3688 hr = ISAXContentHandler_endDocument(content);
3689 EXPECT_HR(hr, S_OK);
3691 V_VT(&dest) = VT_EMPTY;
3692 hr = IMXWriter_put_output(writer, dest);
3693 EXPECT_HR(hr, S_OK);
3695 V_VT(&dest) = VT_EMPTY;
3696 hr = IMXWriter_get_output(writer, &dest);
3697 EXPECT_HR(hr, S_OK);
3698 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3699 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3700 VariantClear(&dest);
3702 hr = ISAXContentHandler_startDocument(content);
3703 EXPECT_HR(hr, S_OK);
3705 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3706 EXPECT_HR(hr, S_OK);
3708 V_VT(&dest) = VT_EMPTY;
3709 hr = IMXWriter_get_output(writer, &dest);
3710 EXPECT_HR(hr, S_OK);
3711 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3712 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3713 VariantClear(&dest);
3715 ISAXContentHandler_endDocument(content);
3716 IMXWriter_flush(writer);
3718 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3719 EXPECT_HR(hr, S_OK);
3720 V_VT(&dest) = VT_EMPTY;
3721 hr = IMXWriter_get_output(writer, &dest);
3722 EXPECT_HR(hr, S_OK);
3723 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3724 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3725 VariantClear(&dest);
3727 V_VT(&dest) = VT_EMPTY;
3728 hr = IMXWriter_put_output(writer, dest);
3729 EXPECT_HR(hr, S_OK);
3732 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3733 EXPECT_HR(hr, S_OK);
3734 V_VT(&dest) = VT_EMPTY;
3735 hr = IMXWriter_get_output(writer, &dest);
3736 EXPECT_HR(hr, S_OK);
3737 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3738 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3739 VariantClear(&dest);
3741 ISAXContentHandler_Release(content);
3742 IMXWriter_Release(writer);
3746 struct writer_characters_t {
3752 static const struct writer_characters_t writer_characters[] = {
3753 { &CLSID_MXXMLWriter, "< > & \"", "< > & \"" },
3754 { &CLSID_MXXMLWriter30, "< > & \"", "< > & \"" },
3755 { &CLSID_MXXMLWriter40, "< > & \"", "< > & \"" },
3756 { &CLSID_MXXMLWriter60, "< > & \"", "< > & \"" },
3760 static void test_mxwriter_characters(void)
3762 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3763 const struct writer_characters_t *table = writer_characters;
3764 ISAXContentHandler *content;
3770 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3771 &IID_IMXWriter, (void**)&writer);
3772 EXPECT_HR(hr, S_OK);
3774 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3775 EXPECT_HR(hr, S_OK);
3777 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3778 EXPECT_HR(hr, S_OK);
3780 hr = ISAXContentHandler_startDocument(content);
3781 EXPECT_HR(hr, S_OK);
3783 hr = ISAXContentHandler_characters(content, NULL, 0);
3784 EXPECT_HR(hr, E_INVALIDARG);
3786 hr = ISAXContentHandler_characters(content, chardataW, 0);
3787 EXPECT_HR(hr, S_OK);
3789 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3790 EXPECT_HR(hr, S_OK);
3792 V_VT(&dest) = VT_EMPTY;
3793 hr = IMXWriter_get_output(writer, &dest);
3794 EXPECT_HR(hr, S_OK);
3795 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3796 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3797 VariantClear(&dest);
3799 hr = ISAXContentHandler_endDocument(content);
3800 EXPECT_HR(hr, S_OK);
3802 ISAXContentHandler_Release(content);
3803 IMXWriter_Release(writer);
3805 /* try empty characters data to see if element is closed */
3806 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3807 &IID_IMXWriter, (void**)&writer);
3808 EXPECT_HR(hr, S_OK);
3810 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3811 EXPECT_HR(hr, S_OK);
3813 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3814 EXPECT_HR(hr, S_OK);
3816 hr = ISAXContentHandler_startDocument(content);
3817 EXPECT_HR(hr, S_OK);
3819 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3820 EXPECT_HR(hr, S_OK);
3822 hr = ISAXContentHandler_characters(content, chardataW, 0);
3823 EXPECT_HR(hr, S_OK);
3825 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3826 EXPECT_HR(hr, S_OK);
3828 V_VT(&dest) = VT_EMPTY;
3829 hr = IMXWriter_get_output(writer, &dest);
3830 EXPECT_HR(hr, S_OK);
3831 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3832 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3833 VariantClear(&dest);
3835 ISAXContentHandler_Release(content);
3836 IMXWriter_Release(writer);
3839 while (table->clsid)
3841 ISAXContentHandler *content;
3846 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3853 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3854 &IID_IMXWriter, (void**)&writer);
3855 EXPECT_HR(hr, S_OK);
3857 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3858 EXPECT_HR(hr, S_OK);
3860 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3861 EXPECT_HR(hr, S_OK);
3863 hr = ISAXContentHandler_startDocument(content);
3864 EXPECT_HR(hr, S_OK);
3866 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3867 EXPECT_HR(hr, S_OK);
3872 V_VT(&dest) = VT_EMPTY;
3873 hr = IMXWriter_get_output(writer, &dest);
3874 EXPECT_HR(hr, S_OK);
3875 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3876 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3877 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3878 VariantClear(&dest);
3881 /* with disabled escaping */
3882 V_VT(&dest) = VT_EMPTY;
3883 hr = IMXWriter_put_output(writer, dest);
3884 EXPECT_HR(hr, S_OK);
3886 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3887 EXPECT_HR(hr, S_OK);
3889 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3890 EXPECT_HR(hr, S_OK);
3895 V_VT(&dest) = VT_EMPTY;
3896 hr = IMXWriter_get_output(writer, &dest);
3897 EXPECT_HR(hr, S_OK);
3898 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3899 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3900 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3901 VariantClear(&dest);
3904 ISAXContentHandler_Release(content);
3905 IMXWriter_Release(writer);
3914 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3916 VARIANT_TRUE,"UTF-16",
3918 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3919 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3924 VARIANT_FALSE,"UTF-16",
3926 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3931 VARIANT_TRUE,"UTF-8",
3933 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3934 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3935 * and the writer is released.
3942 VARIANT_TRUE,"utf-8",
3944 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3945 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3946 * and the writer is released.
3953 VARIANT_TRUE,"UTF-16",
3955 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3956 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3961 VARIANT_TRUE,"UTF-16",
3963 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3964 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3970 static void test_mxwriter_stream(void)
3973 ISAXContentHandler *content;
3978 ULARGE_INTEGER pos2;
3979 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3981 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3982 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3984 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3985 &IID_IMXWriter, (void**)&writer);
3986 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3988 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3989 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3991 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3992 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3994 V_VT(&dest) = VT_UNKNOWN;
3995 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3996 hr = IMXWriter_put_output(writer, dest);
3997 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3998 VariantClear(&dest);
4000 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
4001 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
4003 current_write_test = test->expected_writes;
4005 hr = ISAXContentHandler_startDocument(content);
4006 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4008 hr = ISAXContentHandler_endDocument(content);
4009 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4011 ISAXContentHandler_Release(content);
4012 IMXWriter_Release(writer);
4014 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
4015 (int)(current_write_test-test->expected_writes), current_stream_test_index);
4018 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4019 &IID_IMXWriter, (void**)&writer);
4020 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4022 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4023 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
4025 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4026 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4028 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4029 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
4031 V_VT(&dest) = VT_UNKNOWN;
4032 V_UNKNOWN(&dest) = (IUnknown*)stream;
4033 hr = IMXWriter_put_output(writer, dest);
4034 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4036 hr = ISAXContentHandler_startDocument(content);
4037 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4039 /* Setting output of the mxwriter causes the current output to be flushed,
4040 * and the writer to start over.
4042 V_VT(&dest) = VT_EMPTY;
4043 hr = IMXWriter_put_output(writer, dest);
4044 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4047 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4048 ok(hr == S_OK, "Seek failed: %08x\n", hr);
4049 ok(pos2.QuadPart != 0, "expected stream position moved\n");
4051 hr = ISAXContentHandler_startDocument(content);
4052 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4054 hr = ISAXContentHandler_endDocument(content);
4055 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
4057 V_VT(&dest) = VT_EMPTY;
4058 hr = IMXWriter_get_output(writer, &dest);
4059 ok(hr == S_OK, "get_output failed: %08x\n", hr);
4060 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4061 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4062 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4063 VariantClear(&dest);
4065 /* test when BOM is written to output stream */
4066 V_VT(&dest) = VT_EMPTY;
4067 hr = IMXWriter_put_output(writer, dest);
4068 EXPECT_HR(hr, S_OK);
4071 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
4072 EXPECT_HR(hr, S_OK);
4074 V_VT(&dest) = VT_UNKNOWN;
4075 V_UNKNOWN(&dest) = (IUnknown*)stream;
4076 hr = IMXWriter_put_output(writer, dest);
4077 EXPECT_HR(hr, S_OK);
4079 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
4080 EXPECT_HR(hr, S_OK);
4082 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4083 EXPECT_HR(hr, S_OK);
4085 hr = ISAXContentHandler_startDocument(content);
4086 EXPECT_HR(hr, S_OK);
4090 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4091 EXPECT_HR(hr, S_OK);
4092 ok(pos2.QuadPart == 2, "got wrong position\n");
4094 ISAXContentHandler_Release(content);
4095 IMXWriter_Release(writer);
4100 static const char *encoding_names[] = {
4113 static void test_mxwriter_encoding(void)
4115 ISAXContentHandler *content;
4126 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4127 &IID_IMXWriter, (void**)&writer);
4128 EXPECT_HR(hr, S_OK);
4130 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4131 EXPECT_HR(hr, S_OK);
4133 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4134 EXPECT_HR(hr, S_OK);
4136 hr = ISAXContentHandler_startDocument(content);
4137 EXPECT_HR(hr, S_OK);
4139 hr = ISAXContentHandler_endDocument(content);
4140 EXPECT_HR(hr, S_OK);
4142 /* The content is always re-encoded to UTF-16 when the output is
4143 * retrieved as a BSTR.
4145 V_VT(&dest) = VT_EMPTY;
4146 hr = IMXWriter_get_output(writer, &dest);
4147 EXPECT_HR(hr, S_OK);
4148 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4149 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4150 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4151 VariantClear(&dest);
4153 /* switch encoding when something is written already */
4154 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4155 EXPECT_HR(hr, S_OK);
4157 V_VT(&dest) = VT_UNKNOWN;
4158 V_UNKNOWN(&dest) = (IUnknown*)stream;
4159 hr = IMXWriter_put_output(writer, dest);
4160 EXPECT_HR(hr, S_OK);
4162 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4163 EXPECT_HR(hr, S_OK);
4165 /* write empty element */
4166 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
4167 EXPECT_HR(hr, S_OK);
4169 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
4170 EXPECT_HR(hr, S_OK);
4173 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4174 EXPECT_HR(hr, S_OK);
4176 hr = IMXWriter_flush(writer);
4177 EXPECT_HR(hr, S_OK);
4179 hr = GetHGlobalFromStream(stream, &g);
4180 EXPECT_HR(hr, S_OK);
4182 ptr = GlobalLock(g);
4183 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4186 /* so output is unaffected, encoding name is stored however */
4187 hr = IMXWriter_get_encoding(writer, &s);
4188 EXPECT_HR(hr, S_OK);
4189 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4192 IStream_Release(stream);
4195 enc = encoding_names[i];
4198 char expectedA[200];
4200 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4201 EXPECT_HR(hr, S_OK);
4203 V_VT(&dest) = VT_UNKNOWN;
4204 V_UNKNOWN(&dest) = (IUnknown*)stream;
4205 hr = IMXWriter_put_output(writer, dest);
4206 EXPECT_HR(hr, S_OK);
4208 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4209 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4210 "%s: encoding not accepted\n", enc);
4213 enc = encoding_names[++i];
4214 IStream_Release(stream);
4218 hr = ISAXContentHandler_startDocument(content);
4219 EXPECT_HR(hr, S_OK);
4221 hr = ISAXContentHandler_endDocument(content);
4222 EXPECT_HR(hr, S_OK);
4224 hr = IMXWriter_flush(writer);
4225 EXPECT_HR(hr, S_OK);
4227 /* prepare expected string */
4229 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4230 strcat(expectedA, enc);
4231 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4233 hr = GetHGlobalFromStream(stream, &g);
4234 EXPECT_HR(hr, S_OK);
4236 ptr = GlobalLock(g);
4237 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4240 V_VT(&dest) = VT_EMPTY;
4241 hr = IMXWriter_put_output(writer, dest);
4242 EXPECT_HR(hr, S_OK);
4244 IStream_Release(stream);
4246 enc = encoding_names[++i];
4249 ISAXContentHandler_Release(content);
4250 IMXWriter_Release(writer);
4255 static void test_obj_dispex(IUnknown *obj)
4257 static const WCHAR starW[] = {'*',0};
4258 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4259 IDispatchEx *dispex;
4266 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4267 EXPECT_HR(hr, S_OK);
4268 if (FAILED(hr)) return;
4271 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4272 EXPECT_HR(hr, S_OK);
4273 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4275 name = SysAllocString(starW);
4276 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4277 EXPECT_HR(hr, E_NOTIMPL);
4278 SysFreeString(name);
4280 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4281 EXPECT_HR(hr, E_NOTIMPL);
4284 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4285 EXPECT_HR(hr, E_NOTIMPL);
4286 ok(props == 0, "expected 0 got %d\n", props);
4288 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4289 EXPECT_HR(hr, E_NOTIMPL);
4290 if (SUCCEEDED(hr)) SysFreeString(name);
4292 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4293 EXPECT_HR(hr, E_NOTIMPL);
4295 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4296 EXPECT_HR(hr, E_NOTIMPL);
4297 if (hr == S_OK && unk) IUnknown_Release(unk);
4299 IDispatchEx_Release(dispex);
4302 static void test_dispex(void)
4304 IVBSAXXMLReader *vbreader;
4305 ISAXXMLReader *reader;
4309 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4310 &IID_ISAXXMLReader, (void**)&reader);
4311 EXPECT_HR(hr, S_OK);
4313 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4314 EXPECT_HR(hr, S_OK);
4315 test_obj_dispex(unk);
4316 IUnknown_Release(unk);
4318 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4319 EXPECT_HR(hr, S_OK);
4320 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4321 EXPECT_HR(hr, S_OK);
4322 test_obj_dispex(unk);
4323 IUnknown_Release(unk);
4324 IVBSAXXMLReader_Release(vbreader);
4326 ISAXXMLReader_Release(reader);
4329 static void test_mxwriter_dispex(void)
4331 IDispatchEx *dispex;
4336 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4337 &IID_IMXWriter, (void**)&writer);
4338 EXPECT_HR(hr, S_OK);
4340 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4341 EXPECT_HR(hr, S_OK);
4342 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4343 test_obj_dispex(unk);
4344 IUnknown_Release(unk);
4345 IDispatchEx_Release(dispex);
4347 IMXWriter_Release(writer);
4350 static void test_mxwriter_comment(void)
4352 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4353 ISAXContentHandler *content;
4354 ISAXLexicalHandler *lexical;
4359 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4360 &IID_IMXWriter, (void**)&writer);
4361 EXPECT_HR(hr, S_OK);
4363 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4364 EXPECT_HR(hr, S_OK);
4366 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4367 EXPECT_HR(hr, S_OK);
4369 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4370 EXPECT_HR(hr, S_OK);
4372 hr = ISAXContentHandler_startDocument(content);
4373 EXPECT_HR(hr, S_OK);
4375 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4376 EXPECT_HR(hr, E_INVALIDARG);
4378 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4379 EXPECT_HR(hr, S_OK);
4381 V_VT(&dest) = VT_EMPTY;
4382 hr = IMXWriter_get_output(writer, &dest);
4383 EXPECT_HR(hr, S_OK);
4384 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4385 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4386 VariantClear(&dest);
4388 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4389 EXPECT_HR(hr, S_OK);
4391 V_VT(&dest) = VT_EMPTY;
4392 hr = IMXWriter_get_output(writer, &dest);
4393 EXPECT_HR(hr, S_OK);
4394 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4395 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4396 VariantClear(&dest);
4398 ISAXContentHandler_Release(content);
4399 ISAXLexicalHandler_Release(lexical);
4400 IMXWriter_Release(writer);
4404 static void test_mxwriter_cdata(void)
4406 ISAXContentHandler *content;
4407 ISAXLexicalHandler *lexical;
4412 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4413 &IID_IMXWriter, (void**)&writer);
4414 EXPECT_HR(hr, S_OK);
4416 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4417 EXPECT_HR(hr, S_OK);
4419 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4420 EXPECT_HR(hr, S_OK);
4422 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4423 EXPECT_HR(hr, S_OK);
4425 hr = ISAXContentHandler_startDocument(content);
4426 EXPECT_HR(hr, S_OK);
4428 hr = ISAXLexicalHandler_startCDATA(lexical);
4429 EXPECT_HR(hr, S_OK);
4431 V_VT(&dest) = VT_EMPTY;
4432 hr = IMXWriter_get_output(writer, &dest);
4433 EXPECT_HR(hr, S_OK);
4434 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4435 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4436 VariantClear(&dest);
4438 hr = ISAXLexicalHandler_startCDATA(lexical);
4439 EXPECT_HR(hr, S_OK);
4441 /* all these are escaped for text nodes */
4442 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4443 EXPECT_HR(hr, S_OK);
4445 hr = ISAXLexicalHandler_endCDATA(lexical);
4446 EXPECT_HR(hr, S_OK);
4448 V_VT(&dest) = VT_EMPTY;
4449 hr = IMXWriter_get_output(writer, &dest);
4450 EXPECT_HR(hr, S_OK);
4451 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4452 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4453 VariantClear(&dest);
4455 ISAXContentHandler_Release(content);
4456 ISAXLexicalHandler_Release(lexical);
4457 IMXWriter_Release(writer);
4461 static void test_mxwriter_pi(void)
4463 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4464 static const WCHAR dataW[] = {'d','a','t','a',0};
4465 ISAXContentHandler *content;
4470 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4471 &IID_IMXWriter, (void**)&writer);
4472 EXPECT_HR(hr, S_OK);
4474 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4475 EXPECT_HR(hr, S_OK);
4477 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4478 EXPECT_HR(hr, E_INVALIDARG);
4480 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4481 EXPECT_HR(hr, S_OK);
4483 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4484 EXPECT_HR(hr, S_OK);
4486 V_VT(&dest) = VT_EMPTY;
4487 hr = IMXWriter_get_output(writer, &dest);
4488 EXPECT_HR(hr, S_OK);
4489 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4490 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4491 VariantClear(&dest);
4493 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4494 EXPECT_HR(hr, S_OK);
4496 V_VT(&dest) = VT_EMPTY;
4497 hr = IMXWriter_get_output(writer, &dest);
4498 EXPECT_HR(hr, S_OK);
4499 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4500 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)));
4501 VariantClear(&dest);
4503 V_VT(&dest) = VT_EMPTY;
4504 hr = IMXWriter_put_output(writer, dest);
4505 EXPECT_HR(hr, S_OK);
4507 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4508 EXPECT_HR(hr, S_OK);
4510 V_VT(&dest) = VT_EMPTY;
4511 hr = IMXWriter_get_output(writer, &dest);
4512 EXPECT_HR(hr, S_OK);
4513 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4514 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4515 VariantClear(&dest);
4518 ISAXContentHandler_Release(content);
4519 IMXWriter_Release(writer);
4522 static void test_mxwriter_ignorablespaces(void)
4524 static const WCHAR dataW[] = {'d','a','t','a',0};
4525 ISAXContentHandler *content;
4530 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4531 &IID_IMXWriter, (void**)&writer);
4532 EXPECT_HR(hr, S_OK);
4534 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4535 EXPECT_HR(hr, S_OK);
4537 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4538 EXPECT_HR(hr, E_INVALIDARG);
4540 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4541 EXPECT_HR(hr, S_OK);
4543 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4544 EXPECT_HR(hr, S_OK);
4546 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4547 EXPECT_HR(hr, S_OK);
4549 V_VT(&dest) = VT_EMPTY;
4550 hr = IMXWriter_get_output(writer, &dest);
4551 EXPECT_HR(hr, S_OK);
4552 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4553 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4554 VariantClear(&dest);
4556 ISAXContentHandler_Release(content);
4557 IMXWriter_Release(writer);
4560 static void test_mxwriter_dtd(void)
4562 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4563 static const WCHAR nameW[] = {'n','a','m','e'};
4564 static const WCHAR pubW[] = {'p','u','b'};
4565 static const WCHAR sysW[] = {'s','y','s'};
4566 ISAXContentHandler *content;
4567 ISAXLexicalHandler *lexical;
4568 ISAXDeclHandler *decl;
4573 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4574 &IID_IMXWriter, (void**)&writer);
4575 EXPECT_HR(hr, S_OK);
4577 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4578 EXPECT_HR(hr, S_OK);
4580 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4581 EXPECT_HR(hr, S_OK);
4583 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4584 EXPECT_HR(hr, S_OK);
4586 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4587 EXPECT_HR(hr, S_OK);
4589 hr = ISAXContentHandler_startDocument(content);
4590 EXPECT_HR(hr, S_OK);
4592 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4593 EXPECT_HR(hr, E_INVALIDARG);
4595 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4596 EXPECT_HR(hr, E_INVALIDARG);
4598 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4599 EXPECT_HR(hr, E_INVALIDARG);
4601 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4602 EXPECT_HR(hr, E_INVALIDARG);
4604 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4605 EXPECT_HR(hr, S_OK);
4607 V_VT(&dest) = VT_EMPTY;
4608 hr = IMXWriter_get_output(writer, &dest);
4609 EXPECT_HR(hr, S_OK);
4610 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4611 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4612 VariantClear(&dest);
4614 /* system id is required if public is present */
4615 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4616 EXPECT_HR(hr, E_INVALIDARG);
4618 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4619 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4620 EXPECT_HR(hr, S_OK);
4622 V_VT(&dest) = VT_EMPTY;
4623 hr = IMXWriter_get_output(writer, &dest);
4624 EXPECT_HR(hr, S_OK);
4625 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4626 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4627 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4628 VariantClear(&dest);
4630 hr = ISAXLexicalHandler_endDTD(lexical);
4631 EXPECT_HR(hr, S_OK);
4633 hr = ISAXLexicalHandler_endDTD(lexical);
4634 EXPECT_HR(hr, S_OK);
4636 V_VT(&dest) = VT_EMPTY;
4637 hr = IMXWriter_get_output(writer, &dest);
4638 EXPECT_HR(hr, S_OK);
4639 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4640 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4641 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4642 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4643 VariantClear(&dest);
4645 /* element declaration */
4646 V_VT(&dest) = VT_EMPTY;
4647 hr = IMXWriter_put_output(writer, dest);
4648 EXPECT_HR(hr, S_OK);
4650 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4651 EXPECT_HR(hr, E_INVALIDARG);
4653 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4654 EXPECT_HR(hr, E_INVALIDARG);
4656 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4657 EXPECT_HR(hr, S_OK);
4659 V_VT(&dest) = VT_EMPTY;
4660 hr = IMXWriter_get_output(writer, &dest);
4661 EXPECT_HR(hr, S_OK);
4662 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4663 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4664 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4665 VariantClear(&dest);
4667 V_VT(&dest) = VT_EMPTY;
4668 hr = IMXWriter_put_output(writer, dest);
4669 EXPECT_HR(hr, S_OK);
4671 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4672 EXPECT_HR(hr, S_OK);
4674 V_VT(&dest) = VT_EMPTY;
4675 hr = IMXWriter_get_output(writer, &dest);
4676 EXPECT_HR(hr, S_OK);
4677 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4678 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4679 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4680 VariantClear(&dest);
4682 /* attribute declaration */
4683 V_VT(&dest) = VT_EMPTY;
4684 hr = IMXWriter_put_output(writer, dest);
4685 EXPECT_HR(hr, S_OK);
4687 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4688 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4689 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4690 EXPECT_HR(hr, S_OK);
4692 V_VT(&dest) = VT_EMPTY;
4693 hr = IMXWriter_get_output(writer, &dest);
4694 EXPECT_HR(hr, S_OK);
4695 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4696 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4697 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4698 VariantClear(&dest);
4700 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4701 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4702 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4703 EXPECT_HR(hr, S_OK);
4705 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4706 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4707 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
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_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4715 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4716 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4717 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4718 VariantClear(&dest);
4720 /* internal entities */
4721 V_VT(&dest) = VT_EMPTY;
4722 hr = IMXWriter_put_output(writer, dest);
4723 EXPECT_HR(hr, S_OK);
4725 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4726 EXPECT_HR(hr, E_INVALIDARG);
4728 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4729 EXPECT_HR(hr, E_INVALIDARG);
4731 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
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_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4739 VariantClear(&dest);
4741 ISAXContentHandler_Release(content);
4742 ISAXLexicalHandler_Release(lexical);
4743 ISAXDeclHandler_Release(decl);
4744 IMXWriter_Release(writer);
4756 } addattribute_test_t;
4758 static const addattribute_test_t addattribute_data[] = {
4759 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4760 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4761 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4762 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4764 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4765 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4766 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4767 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4769 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4770 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4771 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4772 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4774 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4775 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4776 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4777 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4782 static void test_mxattr_addAttribute(void)
4784 const addattribute_test_t *table = addattribute_data;
4787 while (table->clsid)
4789 ISAXAttributes *saxattr;
4790 IMXAttributes *mxattr;
4795 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4802 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4803 &IID_IMXAttributes, (void**)&mxattr);
4804 EXPECT_HR(hr, S_OK);
4806 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4807 EXPECT_HR(hr, S_OK);
4809 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4810 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4811 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4813 hr = ISAXAttributes_getLength(saxattr, NULL);
4814 EXPECT_HR(hr, E_POINTER);
4818 hr = ISAXAttributes_getLength(saxattr, &len);
4819 EXPECT_HR(hr, S_OK);
4820 ok(len == 0, "got %d\n", len);
4822 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4823 EXPECT_HR(hr, E_INVALIDARG);
4825 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4826 EXPECT_HR(hr, E_INVALIDARG);
4828 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4829 EXPECT_HR(hr, E_INVALIDARG);
4831 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4832 EXPECT_HR(hr, E_INVALIDARG);
4834 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4835 EXPECT_HR(hr, E_INVALIDARG);
4837 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4838 EXPECT_HR(hr, E_INVALIDARG);
4840 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4841 EXPECT_HR(hr, E_INVALIDARG);
4843 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4844 EXPECT_HR(hr, E_INVALIDARG);
4846 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4847 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4848 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4852 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4853 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4854 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4856 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4857 EXPECT_HR(hr, E_POINTER);
4859 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4860 EXPECT_HR(hr, E_POINTER);
4862 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4863 EXPECT_HR(hr, E_POINTER);
4865 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4866 EXPECT_HR(hr, E_POINTER);
4868 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4869 EXPECT_HR(hr, E_POINTER);
4871 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4872 EXPECT_HR(hr, E_POINTER);
4876 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4877 EXPECT_HR(hr, S_OK);
4878 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4880 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4883 value = (void*)0xdeadbeef;
4884 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4885 EXPECT_HR(hr, S_OK);
4889 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4891 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4895 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4896 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4899 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4900 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4901 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4903 EXPECT_HR(hr, E_POINTER);
4906 EXPECT_HR(hr, E_INVALIDARG);
4908 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4909 EXPECT_HR(hr, E_INVALIDARG);
4912 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4913 EXPECT_HR(hr, E_INVALIDARG);
4914 ok(index == -1, "%d: got wrong index %d\n", i, index);
4917 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4918 EXPECT_HR(hr, E_INVALIDARG);
4919 ok(index == -1, "%d: got wrong index %d\n", i, index);
4922 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4923 EXPECT_HR(hr, S_OK);
4924 ok(index == 0, "%d: got wrong index %d\n", i, index);
4927 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4928 EXPECT_HR(hr, E_INVALIDARG);
4929 ok(index == -1, "%d: got wrong index %d\n", i, index);
4931 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4932 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4934 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4935 EXPECT_HR(hr, E_INVALIDARG);
4937 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4938 EXPECT_HR(hr, E_INVALIDARG);
4940 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4941 EXPECT_HR(hr, E_INVALIDARG);
4943 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4944 EXPECT_HR(hr, E_INVALIDARG);
4946 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4947 EXPECT_HR(hr, E_INVALIDARG);
4949 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4950 EXPECT_HR(hr, E_INVALIDARG);
4954 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4955 EXPECT_HR(hr, E_POINTER);
4957 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4958 EXPECT_HR(hr, E_POINTER);
4960 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4961 EXPECT_HR(hr, E_POINTER);
4963 /* versions 4 and 6 crash */
4964 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4965 EXPECT_HR(hr, E_POINTER);
4967 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4968 EXPECT_HR(hr, E_POINTER);
4970 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4971 EXPECT_HR(hr, E_POINTER);
4973 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4974 EXPECT_HR(hr, E_POINTER);
4976 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4977 EXPECT_HR(hr, E_POINTER);
4979 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4980 EXPECT_HR(hr, E_POINTER);
4982 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4983 EXPECT_HR(hr, E_POINTER);
4985 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4986 strlen(table->local), NULL, NULL);
4987 EXPECT_HR(hr, E_POINTER);
4990 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4991 EXPECT_HR(hr, S_OK);
4992 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4994 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4997 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4998 _bstr_(table->local), strlen(table->local), &value, &len);
4999 EXPECT_HR(hr, S_OK);
5000 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5002 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5007 hr = ISAXAttributes_getLength(saxattr, &len);
5008 EXPECT_HR(hr, S_OK);
5009 if (table->hr == S_OK)
5010 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
5012 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
5014 ISAXAttributes_Release(saxattr);
5015 IMXAttributes_Release(mxattr);
5024 static void test_mxattr_clear(void)
5026 ISAXAttributes *saxattr;
5027 IMXAttributes *mxattr;
5032 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5033 &IID_IMXAttributes, (void**)&mxattr);
5034 EXPECT_HR(hr, S_OK);
5036 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5037 EXPECT_HR(hr, S_OK);
5039 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
5040 EXPECT_HR(hr, E_INVALIDARG);
5042 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5043 EXPECT_HR(hr, E_INVALIDARG);
5045 hr = IMXAttributes_clear(mxattr);
5046 EXPECT_HR(hr, S_OK);
5048 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
5049 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
5050 EXPECT_HR(hr, S_OK);
5053 hr = ISAXAttributes_getLength(saxattr, &len);
5054 EXPECT_HR(hr, S_OK);
5055 ok(len == 1, "got %d\n", len);
5058 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
5059 EXPECT_HR(hr, E_POINTER);
5060 ok(len == -1, "got %d\n", len);
5062 ptr = (void*)0xdeadbeef;
5063 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
5064 EXPECT_HR(hr, E_POINTER);
5065 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5068 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5069 EXPECT_HR(hr, S_OK);
5070 ok(len == 5, "got %d\n", len);
5071 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
5073 hr = IMXAttributes_clear(mxattr);
5074 EXPECT_HR(hr, S_OK);
5077 hr = ISAXAttributes_getLength(saxattr, &len);
5078 EXPECT_HR(hr, S_OK);
5079 ok(len == 0, "got %d\n", len);
5082 ptr = (void*)0xdeadbeef;
5083 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5084 EXPECT_HR(hr, E_INVALIDARG);
5085 ok(len == -1, "got %d\n", len);
5086 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5088 IMXAttributes_Release(mxattr);
5089 ISAXAttributes_Release(saxattr);
5093 static void test_mxattr_dispex(void)
5095 IMXAttributes *mxattr;
5096 IDispatchEx *dispex;
5100 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5101 &IID_IMXAttributes, (void**)&mxattr);
5102 EXPECT_HR(hr, S_OK);
5104 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
5105 EXPECT_HR(hr, S_OK);
5106 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
5107 test_obj_dispex(unk);
5108 IUnknown_Release(unk);
5109 IDispatchEx_Release(dispex);
5111 IMXAttributes_Release(mxattr);
5114 static void test_mxattr_qi(void)
5116 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
5117 ISAXAttributes *saxattr;
5118 IMXAttributes *mxattr;
5121 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5122 &IID_IMXAttributes, (void**)&mxattr);
5123 EXPECT_HR(hr, S_OK);
5125 EXPECT_REF(mxattr, 1);
5126 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5127 EXPECT_HR(hr, S_OK);
5129 EXPECT_REF(mxattr, 2);
5130 EXPECT_REF(saxattr, 2);
5132 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
5133 EXPECT_HR(hr, S_OK);
5135 EXPECT_REF(vbsaxattr, 3);
5136 EXPECT_REF(mxattr, 3);
5137 EXPECT_REF(saxattr, 3);
5139 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
5140 EXPECT_HR(hr, S_OK);
5142 EXPECT_REF(vbsaxattr, 4);
5143 EXPECT_REF(mxattr, 4);
5144 EXPECT_REF(saxattr, 4);
5146 IMXAttributes_Release(mxattr);
5147 ISAXAttributes_Release(saxattr);
5148 IVBSAXAttributes_Release(vbsaxattr);
5149 IVBSAXAttributes_Release(vbsaxattr2);
5152 static struct msxmlsupported_data_t saxattr_support_data[] =
5154 { &CLSID_SAXAttributes, "SAXAttributes" },
5155 { &CLSID_SAXAttributes30, "SAXAttributes30" },
5156 { &CLSID_SAXAttributes40, "SAXAttributes40" },
5157 { &CLSID_SAXAttributes60, "SAXAttributes60" },
5161 static void test_mxattr_localname(void)
5163 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
5164 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
5165 static const WCHAR uri1W[] = {'u','r','i','1',0};
5166 static const WCHAR uriW[] = {'u','r','i',0};
5168 const struct msxmlsupported_data_t *table = saxattr_support_data;
5170 while (table->clsid)
5172 ISAXAttributes *saxattr;
5173 IMXAttributes *mxattr;
5177 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5183 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5184 &IID_IMXAttributes, (void**)&mxattr);
5185 EXPECT_HR(hr, S_OK);
5187 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5188 EXPECT_HR(hr, S_OK);
5190 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5191 EXPECT_HR(hr, E_INVALIDARG);
5193 /* add some ambiguos attribute names */
5194 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5195 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5196 EXPECT_HR(hr, S_OK);
5197 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5198 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5199 EXPECT_HR(hr, S_OK);
5202 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5203 EXPECT_HR(hr, S_OK);
5204 ok(index == 0, "%s: got index %d\n", table->name, index);
5207 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5208 EXPECT_HR(hr, E_INVALIDARG);
5209 ok(index == -1, "%s: got index %d\n", table->name, index);
5212 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5213 EXPECT_HR(hr, E_INVALIDARG);
5214 ok(index == -1, "%s: got index %d\n", table->name, index);
5216 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5217 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5219 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5220 EXPECT_HR(hr, E_POINTER);
5222 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5223 EXPECT_HR(hr, E_POINTER);
5227 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5228 EXPECT_HR(hr, E_INVALIDARG);
5230 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5231 EXPECT_HR(hr, E_INVALIDARG);
5234 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5235 EXPECT_HR(hr, E_INVALIDARG);
5237 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5238 EXPECT_HR(hr, E_INVALIDARG);
5242 ISAXAttributes_Release(saxattr);
5243 IMXAttributes_Release(mxattr);
5247 START_TEST(saxreader)
5249 ISAXXMLReader *reader;
5252 hr = CoInitialize(NULL);
5253 ok(hr == S_OK, "failed to init com\n");
5255 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5256 &IID_ISAXXMLReader, (void**)&reader);
5260 skip("Failed to create SAXXMLReader instance\n");
5264 ISAXXMLReader_Release(reader);
5266 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5268 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5271 test_saxreader_properties();
5272 test_saxreader_features();
5273 test_saxreader_encoding();
5276 /* MXXMLWriter tests */
5277 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5278 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5280 test_mxwriter_handlers();
5281 test_mxwriter_startenddocument();
5282 test_mxwriter_startendelement();
5283 test_mxwriter_characters();
5284 test_mxwriter_comment();
5285 test_mxwriter_cdata();
5287 test_mxwriter_ignorablespaces();
5288 test_mxwriter_dtd();
5289 test_mxwriter_properties();
5290 test_mxwriter_flush();
5291 test_mxwriter_stream();
5292 test_mxwriter_encoding();
5293 test_mxwriter_dispex();
5296 win_skip("MXXMLWriter not supported\n");
5298 /* SAXAttributes tests */
5299 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5300 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5303 test_mxattr_addAttribute();
5304 test_mxattr_clear();
5305 test_mxattr_localname();
5306 test_mxattr_dispex();
5309 skip("SAXAttributes not supported\n");