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,
177 static const char *event_names[EVENT_LAST] = {
179 "putDocumentLocator",
182 "startPrefixMapping",
187 "ignorableWhitespace",
188 "processingIntruction",
195 struct attribute_entry {
201 /* used for actual call data only, null for expected call data */
217 /* allocated once at startElement callback */
218 struct attribute_entry *attributes;
221 /* used for actual call data only, null for expected call data */
231 struct call_entry *sequence;
234 #define CONTENT_HANDLER_INDEX 0
235 #define NUM_CALL_SEQUENCES 1
236 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
238 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
240 memset(call, 0, sizeof(*call));
241 ISAXLocator_getLineNumber(locator, &call->line);
242 ISAXLocator_getColumnNumber(locator, &call->column);
245 static void add_call(struct call_sequence **seq, int sequence_index,
246 const struct call_entry *call)
248 struct call_sequence *call_seq = seq[sequence_index];
250 if (!call_seq->sequence)
253 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
254 call_seq->size * sizeof (struct call_entry));
257 if (call_seq->count == call_seq->size)
260 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
262 call_seq->size * sizeof (struct call_entry));
265 assert(call_seq->sequence);
267 call_seq->sequence[call_seq->count].id = call->id;
268 call_seq->sequence[call_seq->count].line = call->line;
269 call_seq->sequence[call_seq->count].column = call->column;
270 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
271 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
272 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
273 call_seq->sequence[call_seq->count].ret = call->ret;
274 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
275 call_seq->sequence[call_seq->count].attributes = call->attributes;
280 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
284 struct call_sequence *call_seq = seg[sequence_index];
286 for (i = 0; i < call_seq->count; i++)
290 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
292 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
293 SysFreeString(call_seq->sequence[i].attributes[j].localW);
294 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
297 SysFreeString(call_seq->sequence[i].arg1W);
298 SysFreeString(call_seq->sequence[i].arg2W);
299 SysFreeString(call_seq->sequence[i].arg3W);
302 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
303 call_seq->sequence = NULL;
304 call_seq->count = call_seq->size = 0;
307 static inline void flush_sequences(struct call_sequence **seq, int n)
310 for (i = 0; i < n; i++)
311 flush_sequence(seq, i);
314 static const char *get_event_name(CH event)
316 return event_names[event];
319 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
320 int todo, const char *file, int line, int *failcount)
324 /* attribute count is not stored for expected data */
325 if (expected->attributes)
327 struct attribute_entry *ptr = expected->attributes;
328 while (ptr->uri) { lenexp++; ptr++; };
331 /* check count first and exit earlier */
332 if (actual->attr_count != lenexp && todo)
336 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
337 context, get_event_name(actual->id), lenexp, actual->attr_count);
340 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
341 context, get_event_name(actual->id), lenexp, actual->attr_count);
343 if (actual->attr_count != lenexp) return;
345 /* now compare all attributes strings */
346 for (i = 0; i < actual->attr_count; i++)
348 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
349 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
350 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
351 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
355 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
356 const struct call_entry *expected, const char *context, int todo,
357 const char *file, int line)
359 struct call_sequence *call_seq = seq[sequence_index];
360 static const struct call_entry end_of_sequence = { CH_ENDTEST };
361 const struct call_entry *actual, *sequence;
364 add_call(seq, sequence_index, &end_of_sequence);
366 sequence = call_seq->sequence;
369 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
371 if (expected->id == actual->id)
373 /* always test position data */
374 if (expected->line != actual->line && todo)
379 ok_(file, line) (FALSE,
380 "%s: in event %s expecting line %d got %d\n",
381 context, get_event_name(actual->id), expected->line, actual->line);
386 ok_(file, line) (expected->line == actual->line,
387 "%s: in event %s expecting line %d got %d\n",
388 context, get_event_name(actual->id), expected->line, actual->line);
391 if (expected->column != actual->column && todo)
396 ok_(file, line) (FALSE,
397 "%s: in event %s expecting column %d got %d\n",
398 context, get_event_name(actual->id), expected->column, actual->column);
403 ok_(file, line) (expected->column == actual->column,
404 "%s: in event %s expecting column %d got %d\n",
405 context, get_event_name(actual->id), expected->column, actual->column);
410 case CH_PUTDOCUMENTLOCATOR:
411 case CH_STARTDOCUMENT:
414 case CH_STARTPREFIXMAPPING:
416 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
417 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
419 case CH_ENDPREFIXMAPPING:
421 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
423 case CH_STARTELEMENT:
424 /* compare attributes */
425 compare_attributes(actual, expected, context, todo, file, line, &failcount);
428 /* uri, localname, qname */
429 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
430 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
431 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
434 case CH_IGNORABLEWHITESPACE:
436 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
438 case CH_PROCESSINGINSTRUCTION:
440 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
441 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
443 case CH_SKIPPEDENTITY:
445 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
448 /* test return value only */
449 if (expected->ret != actual->ret && todo)
452 ok_(file, line) (FALSE,
453 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
454 context, get_event_name(actual->id), expected->ret, actual->ret);
457 ok_(file, line) (expected->ret == actual->ret,
458 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
459 context, get_event_name(actual->id), expected->ret, actual->ret);
462 case EG_IGNORABLEWARNING:
464 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
474 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
475 context, get_event_name(expected->id), get_event_name(actual->id));
478 flush_sequence(seq, sequence_index);
483 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
484 context, get_event_name(expected->id), get_event_name(actual->id));
494 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
497 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
498 context, get_event_name(expected->id), get_event_name(actual->id));
502 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
504 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
505 context, get_event_name(expected->id), get_event_name(actual->id));
508 if (todo && !failcount) /* succeeded yet marked todo */
512 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
516 flush_sequence(seq, sequence_index);
519 #define ok_sequence(seq, index, exp, contx, todo) \
520 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
522 static void init_call_sequences(struct call_sequence **seq, int n)
526 for (i = 0; i < n; i++)
527 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
530 static const WCHAR szSimpleXML[] = {
531 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
532 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
533 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
534 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
535 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
538 static const WCHAR carriage_ret_test[] = {
539 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
540 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
541 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
542 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
543 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
546 static const WCHAR szUtf16XML[] = {
547 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
548 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
549 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
552 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
554 static const CHAR szUtf8XML[] =
555 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
557 static const char utf8xml2[] =
558 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
560 static const CHAR testXML[] =
561 "<?xml version=\"1.0\" ?>\n"
563 " <Number>1234</Number>\n"
564 " <Name>Captain Ahab</Name>\n"
567 static const char test_attributes[] =
568 "<?xml version=\"1.0\" ?>\n"
569 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
570 "<node1 xmlns:p=\"test\" />"
573 static struct call_entry content_handler_test1[] = {
574 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
575 { CH_STARTDOCUMENT, 0, 0, S_OK },
576 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
577 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
578 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
579 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
580 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
581 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
582 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
583 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
584 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
585 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
586 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
587 { CH_ENDDOCUMENT, 0, 0, S_OK},
591 /* applies to versions 4 and 6 */
592 static struct call_entry content_handler_test1_alternate[] = {
593 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
594 { CH_STARTDOCUMENT, 1, 22, S_OK },
595 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
597 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
598 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
599 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
600 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
601 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
602 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
603 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
604 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
605 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
606 { CH_ENDDOCUMENT, 6, 0, S_OK },
610 static struct call_entry content_handler_test2[] = {
611 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
612 { CH_STARTDOCUMENT, 0, 0, S_OK },
613 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
614 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
615 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
616 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
617 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
618 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
619 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
620 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
621 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
622 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
623 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
624 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
625 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
626 { CH_ENDDOCUMENT, 0, 0, S_OK },
630 static struct call_entry content_handler_test2_alternate[] = {
631 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
632 { CH_STARTDOCUMENT, 1, 21, S_OK },
633 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
634 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
635 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
636 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
637 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
638 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
639 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
640 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
641 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
642 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
643 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
644 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
645 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
646 { CH_ENDDOCUMENT, 6, 0, S_OK },
650 static struct call_entry content_handler_testerror[] = {
651 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
652 { EH_FATALERROR, 0, 0, E_FAIL },
656 static struct call_entry content_handler_testerror_alternate[] = {
657 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
658 { EH_FATALERROR, 1, 0, E_FAIL },
662 static struct call_entry content_handler_test_callback_rets[] = {
663 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
664 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
665 { EH_FATALERROR, 0, 0, S_FALSE },
669 static struct call_entry content_handler_test_callback_rets_alt[] = {
670 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
671 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
672 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
673 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
674 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
675 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
676 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
677 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
678 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
679 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
680 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
681 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
682 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
683 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
687 static struct attribute_entry ch_attributes1[] = {
688 { "", "", "xmlns:test", "prefix_test" },
689 { "", "", "xmlns", "prefix" },
690 { "prefix_test", "arg1", "test:arg1", "arg1" },
691 { "", "arg2", "arg2", "arg2" },
692 { "prefix_test", "ar3", "test:ar3", "arg3" },
696 static struct attribute_entry ch_attributes2[] = {
697 { "", "", "xmlns:p", "test" },
701 static struct call_entry content_handler_test_attributes[] = {
702 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
703 { CH_STARTDOCUMENT, 0, 0, S_OK },
704 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
705 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
706 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
707 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
708 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
709 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
710 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
711 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
712 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
713 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
714 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
715 { CH_ENDDOCUMENT, 0, 0 },
719 static struct attribute_entry ch_attributes_alt_4[] = {
720 { "prefix_test", "arg1", "test:arg1", "arg1" },
721 { "", "arg2", "arg2", "arg2" },
722 { "prefix_test", "ar3", "test:ar3", "arg3" },
723 { "", "", "xmlns:test", "prefix_test" },
724 { "", "", "xmlns", "prefix" },
728 static struct call_entry content_handler_test_attributes_alternate_4[] = {
729 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
730 { CH_STARTDOCUMENT, 1, 22, S_OK },
731 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
732 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
733 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
734 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
735 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
736 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
737 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
738 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
739 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
740 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
741 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
742 { CH_ENDDOCUMENT, 4, 0, S_OK },
746 /* 'namespace' feature switched off */
747 static struct attribute_entry ch_attributes_alt_no_ns[] = {
748 { "", "", "xmlns:test", "prefix_test" },
749 { "", "", "xmlns", "prefix" },
750 { "", "", "test:arg1", "arg1" },
751 { "", "", "arg2", "arg2" },
752 { "", "", "test:ar3", "arg3" },
756 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
757 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
758 { CH_STARTDOCUMENT, 1, 22, S_OK },
759 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
760 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
761 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
762 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
763 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
764 { CH_ENDDOCUMENT, 4, 0, S_OK },
768 static struct attribute_entry ch_attributes_alt_6[] = {
769 { "prefix_test", "arg1", "test:arg1", "arg1" },
770 { "", "arg2", "arg2", "arg2" },
771 { "prefix_test", "ar3", "test:ar3", "arg3" },
772 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
773 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
777 static struct attribute_entry ch_attributes2_6[] = {
778 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
782 static struct call_entry content_handler_test_attributes_alternate_6[] = {
783 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
784 { CH_STARTDOCUMENT, 1, 22, S_OK },
785 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
786 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
787 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
788 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
789 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
790 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
791 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
792 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
793 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
794 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
795 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
796 { CH_ENDDOCUMENT, 4, 0, S_OK },
800 /* 'namespaces' is on, 'namespace-prefixes' if off */
801 static struct attribute_entry ch_attributes_no_prefix[] = {
802 { "prefix_test", "arg1", "test:arg1", "arg1" },
803 { "", "arg2", "arg2", "arg2" },
804 { "prefix_test", "ar3", "test:ar3", "arg3" },
808 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
809 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
810 { CH_STARTDOCUMENT, 1, 22, S_OK },
811 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
812 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
813 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
814 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
815 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
816 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
817 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
818 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
819 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
820 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
821 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
822 { CH_ENDDOCUMENT, 4, 0, S_OK },
826 static struct call_entry content_handler_test_attributes_no_prefix[] = {
827 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
828 { CH_STARTDOCUMENT, 0, 0, S_OK },
829 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
830 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
831 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
832 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
833 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
834 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
835 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
836 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
837 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
838 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
839 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
840 { CH_ENDDOCUMENT, 0, 0 },
844 static struct attribute_entry xmlspace_attrs[] = {
845 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
849 static struct call_entry xmlspaceattr_test[] = {
850 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
851 { CH_STARTDOCUMENT, 0, 0, S_OK },
852 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
853 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
854 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
855 { CH_ENDDOCUMENT, 0, 0, S_OK },
859 static struct call_entry xmlspaceattr_test_alternate[] = {
860 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
861 { CH_STARTDOCUMENT, 1, 39, S_OK },
862 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
863 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
864 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
865 { CH_ENDDOCUMENT, 1, 83, S_OK },
869 /* attribute value normalization test */
870 static const char attribute_normalize[] =
871 "<?xml version=\"1.0\" ?>\n"
872 "<a attr1=\" \r \n \tattr_value A \t \r \n\r\n \n\"/>\n";
874 static struct attribute_entry attribute_norm_attrs[] = {
875 { "", "attr1", "attr1", " attr_value A " },
879 static struct call_entry attribute_norm[] = {
880 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
881 { CH_STARTDOCUMENT, 0, 0, S_OK },
882 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
883 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
884 { CH_ENDDOCUMENT, 0, 0, S_OK },
888 static struct call_entry attribute_norm_alt[] = {
889 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
890 { CH_STARTDOCUMENT, 1, 22, S_OK },
891 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
892 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
893 { CH_ENDDOCUMENT, 9, 0, S_OK },
897 static const char xmlspace_attr[] =
898 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
899 "<a xml:space=\"preserve\"> Some text data </a>";
901 static struct call_entry *expectCall;
902 static ISAXLocator *locator;
903 static ISAXXMLReader *g_reader;
906 static void set_expected_seq(struct call_entry *expected)
908 expectCall = expected;
911 /* to be called once on each tested callback return */
912 static HRESULT get_expected_ret(void)
914 HRESULT hr = expectCall->ret;
915 if (expectCall->id != CH_ENDTEST) expectCall++;
919 static HRESULT WINAPI contentHandler_QueryInterface(
920 ISAXContentHandler* iface,
926 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
932 return E_NOINTERFACE;
938 static ULONG WINAPI contentHandler_AddRef(
939 ISAXContentHandler* iface)
944 static ULONG WINAPI contentHandler_Release(
945 ISAXContentHandler* iface)
950 static HRESULT WINAPI contentHandler_putDocumentLocator(
951 ISAXContentHandler* iface,
952 ISAXLocator *pLocator)
954 struct call_entry call;
959 memset(&call, 0, sizeof(call));
960 init_call_entry(locator, &call);
961 call.id = CH_PUTDOCUMENTLOCATOR;
962 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
964 if (msxml_version >= 6) {
965 ISAXAttributes *attr, *attr1;
966 IMXAttributes *mxattr;
968 EXPECT_REF(pLocator, 1);
969 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
971 EXPECT_REF(pLocator, 2);
972 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
974 EXPECT_REF(pLocator, 3);
975 ok(attr == attr1, "got %p, %p\n", attr, attr1);
977 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
978 EXPECT_HR(hr, E_NOINTERFACE);
980 ISAXAttributes_Release(attr);
981 ISAXAttributes_Release(attr1);
984 return get_expected_ret();
987 static ISAXAttributes *test_attr_ptr;
988 static HRESULT WINAPI contentHandler_startDocument(
989 ISAXContentHandler* iface)
991 struct call_entry call;
993 init_call_entry(locator, &call);
994 call.id = CH_STARTDOCUMENT;
995 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
997 test_attr_ptr = NULL;
999 return get_expected_ret();
1002 static HRESULT WINAPI contentHandler_endDocument(
1003 ISAXContentHandler* iface)
1005 struct call_entry call;
1007 init_call_entry(locator, &call);
1008 call.id = CH_ENDDOCUMENT;
1009 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1011 return get_expected_ret();
1014 static HRESULT WINAPI contentHandler_startPrefixMapping(
1015 ISAXContentHandler* iface,
1016 const WCHAR *prefix, int prefix_len,
1017 const WCHAR *uri, int uri_len)
1019 struct call_entry call;
1021 init_call_entry(locator, &call);
1022 call.id = CH_STARTPREFIXMAPPING;
1023 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1024 call.arg2W = SysAllocStringLen(uri, uri_len);
1025 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1027 return get_expected_ret();
1030 static HRESULT WINAPI contentHandler_endPrefixMapping(
1031 ISAXContentHandler* iface,
1032 const WCHAR *prefix, int len)
1034 struct call_entry call;
1036 init_call_entry(locator, &call);
1037 call.id = CH_ENDPREFIXMAPPING;
1038 call.arg1W = SysAllocStringLen(prefix, len);
1039 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1041 return get_expected_ret();
1044 static HRESULT WINAPI contentHandler_startElement(
1045 ISAXContentHandler* iface,
1046 const WCHAR *uri, int uri_len,
1047 const WCHAR *localname, int local_len,
1048 const WCHAR *qname, int qname_len,
1049 ISAXAttributes *saxattr)
1051 struct call_entry call;
1052 IMXAttributes *mxattr;
1056 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1057 EXPECT_HR(hr, E_NOINTERFACE);
1059 init_call_entry(locator, &call);
1060 call.id = CH_STARTELEMENT;
1061 call.arg1W = SysAllocStringLen(uri, uri_len);
1062 call.arg2W = SysAllocStringLen(localname, local_len);
1063 call.arg3W = SysAllocStringLen(qname, qname_len);
1066 test_attr_ptr = saxattr;
1067 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1069 /* store actual attributes */
1071 hr = ISAXAttributes_getLength(saxattr, &len);
1072 EXPECT_HR(hr, S_OK);
1079 struct attribute_entry *attr;
1080 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1083 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1084 EXPECT_HR(hr, S_OK);
1086 for (i = 0; i < len; i++)
1091 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1092 &localname, &local_len, &qname, &qname_len);
1093 EXPECT_HR(hr, S_OK);
1095 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1096 EXPECT_HR(hr, S_OK);
1098 /* if 'namespaces' switched off uri and local name contains garbage */
1099 if (v == VARIANT_FALSE && msxml_version > 0)
1101 attr[i].uriW = SysAllocStringLen(NULL, 0);
1102 attr[i].localW = SysAllocStringLen(NULL, 0);
1106 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1107 attr[i].localW = SysAllocStringLen(localname, local_len);
1110 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1111 attr[i].valueW = SysAllocStringLen(value, value_len);
1114 call.attributes = attr;
1115 call.attr_count = len;
1118 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1120 return get_expected_ret();
1123 static HRESULT WINAPI contentHandler_endElement(
1124 ISAXContentHandler* iface,
1125 const WCHAR *uri, int uri_len,
1126 const WCHAR *localname, int local_len,
1127 const WCHAR *qname, int qname_len)
1129 struct call_entry call;
1131 init_call_entry(locator, &call);
1132 call.id = CH_ENDELEMENT;
1133 call.arg1W = SysAllocStringLen(uri, uri_len);
1134 call.arg2W = SysAllocStringLen(localname, local_len);
1135 call.arg3W = SysAllocStringLen(qname, qname_len);
1136 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1138 return get_expected_ret();
1141 static HRESULT WINAPI contentHandler_characters(
1142 ISAXContentHandler* iface,
1146 struct call_entry call;
1148 init_call_entry(locator, &call);
1149 call.id = CH_CHARACTERS;
1150 call.arg1W = SysAllocStringLen(chars, len);
1151 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1153 return get_expected_ret();
1156 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1157 ISAXContentHandler* iface,
1158 const WCHAR *chars, int len)
1160 struct call_entry call;
1162 init_call_entry(locator, &call);
1163 call.id = CH_IGNORABLEWHITESPACE;
1164 call.arg1W = SysAllocStringLen(chars, len);
1165 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1167 return get_expected_ret();
1170 static HRESULT WINAPI contentHandler_processingInstruction(
1171 ISAXContentHandler* iface,
1172 const WCHAR *target, int target_len,
1173 const WCHAR *data, int data_len)
1175 struct call_entry call;
1177 init_call_entry(locator, &call);
1178 call.id = CH_PROCESSINGINSTRUCTION;
1179 call.arg1W = SysAllocStringLen(target, target_len);
1180 call.arg2W = SysAllocStringLen(data, data_len);
1181 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1183 return get_expected_ret();
1186 static HRESULT WINAPI contentHandler_skippedEntity(
1187 ISAXContentHandler* iface,
1188 const WCHAR *name, int len)
1190 struct call_entry call;
1192 init_call_entry(locator, &call);
1193 call.id = CH_SKIPPEDENTITY;
1194 call.arg1W = SysAllocStringLen(name, len);
1196 return get_expected_ret();
1199 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1201 contentHandler_QueryInterface,
1202 contentHandler_AddRef,
1203 contentHandler_Release,
1204 contentHandler_putDocumentLocator,
1205 contentHandler_startDocument,
1206 contentHandler_endDocument,
1207 contentHandler_startPrefixMapping,
1208 contentHandler_endPrefixMapping,
1209 contentHandler_startElement,
1210 contentHandler_endElement,
1211 contentHandler_characters,
1212 contentHandler_ignorableWhitespace,
1213 contentHandler_processingInstruction,
1214 contentHandler_skippedEntity
1217 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1219 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1220 ISAXErrorHandler* iface,
1226 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1232 return E_NOINTERFACE;
1238 static ULONG WINAPI isaxerrorHandler_AddRef(
1239 ISAXErrorHandler* iface)
1244 static ULONG WINAPI isaxerrorHandler_Release(
1245 ISAXErrorHandler* iface)
1250 static HRESULT WINAPI isaxerrorHandler_error(
1251 ISAXErrorHandler* iface,
1252 ISAXLocator *pLocator,
1253 const WCHAR *pErrorMessage,
1254 HRESULT hrErrorCode)
1256 ok(0, "unexpected call\n");
1260 static HRESULT WINAPI isaxerrorHandler_fatalError(
1261 ISAXErrorHandler* iface,
1262 ISAXLocator *pLocator,
1263 const WCHAR *message,
1266 struct call_entry call;
1268 init_call_entry(locator, &call);
1269 call.id = EH_FATALERROR;
1272 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1278 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1279 ISAXErrorHandler* iface,
1280 ISAXLocator *pLocator,
1281 const WCHAR *pErrorMessage,
1282 HRESULT hrErrorCode)
1284 ok(0, "unexpected call\n");
1288 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1290 isaxerrorHandler_QueryInterface,
1291 isaxerrorHandler_AddRef,
1292 isaxerrorHandler_Release,
1293 isaxerrorHandler_error,
1294 isaxerrorHandler_fatalError,
1295 isaxerrorHanddler_ignorableWarning
1298 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1300 static HRESULT WINAPI isaxattributes_QueryInterface(
1301 ISAXAttributes* iface,
1307 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1313 return E_NOINTERFACE;
1319 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1324 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1329 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1335 static HRESULT WINAPI isaxattributes_getURI(
1336 ISAXAttributes* iface,
1341 ok(0, "unexpected call\n");
1345 static HRESULT WINAPI isaxattributes_getLocalName(
1346 ISAXAttributes* iface,
1348 const WCHAR **pLocalName,
1349 int *pLocalNameLength)
1351 ok(0, "unexpected call\n");
1355 static HRESULT WINAPI isaxattributes_getQName(
1356 ISAXAttributes* iface,
1358 const WCHAR **QName,
1361 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1362 {'a','t','t','r','2','j','u','n','k',0},
1363 {'a','t','t','r','3',0}};
1364 static const int attrqnamelen[] = {7, 5, 5};
1366 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1368 *QName = attrqnamesW[index];
1369 *QNameLength = attrqnamelen[index];
1374 static HRESULT WINAPI isaxattributes_getName(
1375 ISAXAttributes* iface,
1379 const WCHAR ** pLocalName,
1380 int * pLocalNameSize,
1381 const WCHAR ** pQName,
1384 ok(0, "unexpected call\n");
1388 static HRESULT WINAPI isaxattributes_getIndexFromName(
1389 ISAXAttributes* iface,
1392 const WCHAR * pLocalName,
1393 int cocalNameLength,
1396 ok(0, "unexpected call\n");
1400 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1401 ISAXAttributes* iface,
1402 const WCHAR * pQName,
1406 ok(0, "unexpected call\n");
1410 static HRESULT WINAPI isaxattributes_getType(
1411 ISAXAttributes* iface,
1413 const WCHAR ** pType,
1416 ok(0, "unexpected call\n");
1420 static HRESULT WINAPI isaxattributes_getTypeFromName(
1421 ISAXAttributes* iface,
1424 const WCHAR * pLocalName,
1426 const WCHAR ** pType,
1429 ok(0, "unexpected call\n");
1433 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1434 ISAXAttributes* iface,
1435 const WCHAR * pQName,
1437 const WCHAR ** pType,
1440 ok(0, "unexpected call\n");
1444 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1445 const WCHAR **value, int *nValue)
1447 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1448 {'a','2','j','u','n','k',0},
1449 {'<','&','"','>',0}};
1450 static const int attrvalueslen[] = {2, 2, 4};
1452 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1454 *value = attrvaluesW[index];
1455 *nValue = attrvalueslen[index];
1460 static HRESULT WINAPI isaxattributes_getValueFromName(
1461 ISAXAttributes* iface,
1464 const WCHAR * pLocalName,
1466 const WCHAR ** pValue,
1469 ok(0, "unexpected call\n");
1473 static HRESULT WINAPI isaxattributes_getValueFromQName(
1474 ISAXAttributes* iface,
1475 const WCHAR * pQName,
1477 const WCHAR ** pValue,
1480 ok(0, "unexpected call\n");
1484 static const ISAXAttributesVtbl SAXAttributesVtbl =
1486 isaxattributes_QueryInterface,
1487 isaxattributes_AddRef,
1488 isaxattributes_Release,
1489 isaxattributes_getLength,
1490 isaxattributes_getURI,
1491 isaxattributes_getLocalName,
1492 isaxattributes_getQName,
1493 isaxattributes_getName,
1494 isaxattributes_getIndexFromName,
1495 isaxattributes_getIndexFromQName,
1496 isaxattributes_getType,
1497 isaxattributes_getTypeFromName,
1498 isaxattributes_getTypeFromQName,
1499 isaxattributes_getValue,
1500 isaxattributes_getValueFromName,
1501 isaxattributes_getValueFromQName
1504 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1506 struct saxlexicalhandler
1508 ISAXLexicalHandler ISAXLexicalHandler_iface;
1511 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1514 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1516 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1519 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1521 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1525 if (IsEqualGUID(riid, &IID_IUnknown))
1528 ok(0, "got unexpected IID_IUnknown query\n");
1530 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1532 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1537 ISAXLexicalHandler_AddRef(iface);
1539 return E_NOINTERFACE;
1544 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1546 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1547 return InterlockedIncrement(&handler->ref);
1550 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1552 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1553 return InterlockedDecrement(&handler->ref);
1556 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1557 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1558 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1560 ok(0, "call not expected\n");
1564 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1566 ok(0, "call not expected\n");
1570 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1571 const WCHAR * pName, int nName)
1573 ok(0, "call not expected\n");
1577 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1578 const WCHAR * pName, int nName)
1580 ok(0, "call not expected\n");
1584 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1586 ok(0, "call not expected\n");
1590 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1592 ok(0, "call not expected\n");
1596 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1597 const WCHAR * pChars, int nChars)
1599 ok(0, "call not expected\n");
1603 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1605 isaxlexical_QueryInterface,
1607 isaxlexical_Release,
1608 isaxlexical_startDTD,
1610 isaxlexical_startEntity,
1611 isaxlexical_endEntity,
1612 isaxlexical_startCDATA,
1613 isaxlexical_endCDATA,
1617 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1619 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1621 handler->qi_hr = hr;
1624 struct saxdeclhandler
1626 ISAXDeclHandler ISAXDeclHandler_iface;
1629 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1632 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1634 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1637 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1639 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1643 if (IsEqualGUID(riid, &IID_IUnknown))
1646 ok(0, "got unexpected IID_IUnknown query\n");
1648 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1650 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1655 ISAXDeclHandler_AddRef(iface);
1657 return E_NOINTERFACE;
1662 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1664 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1665 return InterlockedIncrement(&handler->ref);
1668 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1670 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1671 return InterlockedDecrement(&handler->ref);
1674 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1675 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1677 ok(0, "call not expected\n");
1681 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1682 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1683 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1684 int nValueDefault, const WCHAR * pValue, int nValue)
1686 ok(0, "call not expected\n");
1690 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1691 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1693 ok(0, "call not expected\n");
1697 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1698 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1699 const WCHAR * pSystemId, int nSystemId)
1701 ok(0, "call not expected\n");
1705 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1707 isaxdecl_QueryInterface,
1710 isaxdecl_elementDecl,
1711 isaxdecl_attributeDecl,
1712 isaxdecl_internalEntityDecl,
1713 isaxdecl_externalEntityDecl
1716 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1718 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1720 handler->qi_hr = hr;
1723 typedef struct mxwriter_write_test_t {
1729 } mxwriter_write_test;
1731 typedef struct mxwriter_stream_test_t {
1733 const char *encoding;
1734 mxwriter_write_test expected_writes[4];
1735 } mxwriter_stream_test;
1737 static const mxwriter_write_test *current_write_test;
1738 static DWORD current_stream_test_index;
1740 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1744 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1747 return E_NOINTERFACE;
1752 static ULONG WINAPI istream_AddRef(IStream *iface)
1757 static ULONG WINAPI istream_Release(IStream *iface)
1762 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1764 ok(0, "unexpected call\n");
1768 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1772 ok(pv != NULL, "pv == NULL\n");
1774 if(current_write_test->last) {
1775 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1779 fail = current_write_test->fail_write;
1781 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1782 current_write_test->cb, cb, current_stream_test_index);
1785 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1787 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1789 ++current_write_test;
1794 return fail ? E_FAIL : S_OK;
1797 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1798 ULARGE_INTEGER *plibNewPosition)
1800 ok(0, "unexpected call\n");
1804 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1806 ok(0, "unexpected call\n");
1810 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1811 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1813 ok(0, "unexpected call\n");
1817 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1819 ok(0, "unexpected call\n");
1823 static HRESULT WINAPI istream_Revert(IStream *iface)
1825 ok(0, "unexpected call\n");
1829 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1830 ULARGE_INTEGER cb, DWORD dwLockType)
1832 ok(0, "unexpected call\n");
1836 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1837 ULARGE_INTEGER cb, DWORD dwLockType)
1839 ok(0, "unexpected call\n");
1843 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1845 ok(0, "unexpected call\n");
1849 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1851 ok(0, "unexpected call\n");
1855 static const IStreamVtbl StreamVtbl = {
1856 istream_QueryInterface,
1867 istream_UnlockRegion,
1872 static IStream mxstream = { &StreamVtbl };
1874 static struct msxmlsupported_data_t reader_support_data[] =
1876 { &CLSID_SAXXMLReader, "SAXReader" },
1877 { &CLSID_SAXXMLReader30, "SAXReader30" },
1878 { &CLSID_SAXXMLReader40, "SAXReader40" },
1879 { &CLSID_SAXXMLReader60, "SAXReader60" },
1883 static void test_saxreader(void)
1885 const struct msxmlsupported_data_t *table = reader_support_data;
1887 ISAXXMLReader *reader = NULL;
1889 ISAXContentHandler *content;
1890 ISAXErrorHandler *lpErrorHandler;
1892 SAFEARRAYBOUND SADim[1];
1895 ULARGE_INTEGER size;
1899 static const CHAR testXmlA[] = "test.xml";
1900 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1901 IXMLDOMDocument *doc;
1904 while (table->clsid)
1906 struct call_entry *test_seq;
1909 if (!is_clsid_supported(table->clsid, reader_support_data))
1915 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1916 EXPECT_HR(hr, S_OK);
1919 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1921 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1926 /* crashes on old versions */
1927 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1928 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1930 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1931 EXPECT_HR(hr, E_POINTER);
1933 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1934 EXPECT_HR(hr, E_POINTER);
1937 hr = ISAXXMLReader_getContentHandler(reader, &content);
1938 EXPECT_HR(hr, S_OK);
1939 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1941 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1942 EXPECT_HR(hr, S_OK);
1943 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1945 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1946 EXPECT_HR(hr, S_OK);
1948 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1949 EXPECT_HR(hr, S_OK);
1951 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1952 EXPECT_HR(hr, S_OK);
1954 hr = ISAXXMLReader_getContentHandler(reader, &content);
1955 EXPECT_HR(hr, S_OK);
1956 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1958 V_VT(&var) = VT_BSTR;
1959 V_BSTR(&var) = SysAllocString(szSimpleXML);
1961 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1962 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1963 test_seq = content_handler_test1_alternate;
1965 test_seq = content_handler_test1;
1966 set_expected_seq(test_seq);
1967 hr = ISAXXMLReader_parse(reader, var);
1968 EXPECT_HR(hr, S_OK);
1969 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1973 SADim[0].lLbound = 0;
1974 SADim[0].cElements = sizeof(testXML)-1;
1975 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1976 SafeArrayAccessData(sa, (void**)&ptr);
1977 memcpy(ptr, testXML, sizeof(testXML)-1);
1978 SafeArrayUnaccessData(sa);
1979 V_VT(&var) = VT_ARRAY|VT_UI1;
1982 set_expected_seq(test_seq);
1983 hr = ISAXXMLReader_parse(reader, var);
1984 EXPECT_HR(hr, S_OK);
1985 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1987 SafeArrayDestroy(sa);
1989 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1990 size.QuadPart = strlen(testXML);
1991 IStream_SetSize(stream, size);
1992 IStream_Write(stream, testXML, strlen(testXML), &written);
1994 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1995 V_VT(&var) = VT_UNKNOWN;
1996 V_UNKNOWN(&var) = (IUnknown*)stream;
1998 set_expected_seq(test_seq);
1999 hr = ISAXXMLReader_parse(reader, var);
2000 EXPECT_HR(hr, S_OK);
2001 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2003 IStream_Release(stream);
2005 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2006 size.QuadPart = strlen(test_attributes);
2007 IStream_SetSize(stream, size);
2008 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2010 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2011 V_VT(&var) = VT_UNKNOWN;
2012 V_UNKNOWN(&var) = (IUnknown*)stream;
2014 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2015 test_seq = content_handler_test_attributes_alternate_4;
2016 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2017 test_seq = content_handler_test_attributes_alternate_6;
2019 test_seq = content_handler_test_attributes;
2021 set_expected_seq(test_seq);
2022 hr = ISAXXMLReader_parse(reader, var);
2023 EXPECT_HR(hr, S_OK);
2025 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2026 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2027 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2029 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2031 IStream_Release(stream);
2033 V_VT(&var) = VT_BSTR;
2034 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2036 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2037 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2038 test_seq = content_handler_test2_alternate;
2040 test_seq = content_handler_test2;
2042 set_expected_seq(test_seq);
2043 hr = ISAXXMLReader_parse(reader, var);
2044 EXPECT_HR(hr, S_OK);
2045 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2050 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2051 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2052 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2055 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2056 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2057 test_seq = content_handler_test1_alternate;
2059 test_seq = content_handler_test1;
2060 set_expected_seq(test_seq);
2061 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2062 EXPECT_HR(hr, S_OK);
2063 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2066 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2067 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2068 test_seq = content_handler_testerror_alternate;
2070 test_seq = content_handler_testerror;
2071 set_expected_seq(test_seq);
2072 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2073 EXPECT_HR(hr, E_FAIL);
2074 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2076 /* callback ret values */
2077 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2078 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2080 test_seq = content_handler_test_callback_rets_alt;
2081 set_expected_seq(test_seq);
2082 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2083 EXPECT_HR(hr, S_OK);
2087 test_seq = content_handler_test_callback_rets;
2088 set_expected_seq(test_seq);
2089 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2090 EXPECT_HR(hr, S_FALSE);
2092 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2094 DeleteFileA(testXmlA);
2096 /* parse from IXMLDOMDocument */
2097 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2098 &IID_IXMLDOMDocument, (void**)&doc);
2099 EXPECT_HR(hr, S_OK);
2101 str = SysAllocString(szSimpleXML);
2102 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2103 EXPECT_HR(hr, S_OK);
2106 V_VT(&var) = VT_UNKNOWN;
2107 V_UNKNOWN(&var) = (IUnknown*)doc;
2109 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2110 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2111 test_seq = content_handler_test2_alternate;
2113 test_seq = content_handler_test2;
2115 set_expected_seq(test_seq);
2116 hr = ISAXXMLReader_parse(reader, var);
2117 EXPECT_HR(hr, S_OK);
2118 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2119 IXMLDOMDocument_Release(doc);
2121 /* xml:space test */
2122 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2123 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2125 test_seq = xmlspaceattr_test_alternate;
2128 test_seq = xmlspaceattr_test;
2130 set_expected_seq(test_seq);
2131 V_VT(&var) = VT_BSTR;
2132 V_BSTR(&var) = _bstr_(xmlspace_attr);
2133 hr = ISAXXMLReader_parse(reader, var);
2134 EXPECT_HR(hr, S_OK);
2136 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2137 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2139 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2142 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2144 /* switch off 'namespaces' feature */
2145 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2146 EXPECT_HR(hr, S_OK);
2148 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2149 size.QuadPart = strlen(test_attributes);
2150 IStream_SetSize(stream, size);
2151 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2153 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2154 V_VT(&var) = VT_UNKNOWN;
2155 V_UNKNOWN(&var) = (IUnknown*)stream;
2157 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2158 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2160 test_seq = content_handler_test_attributes_alt_no_ns;
2163 test_seq = content_handler_test_attributes;
2165 set_expected_seq(test_seq);
2166 hr = ISAXXMLReader_parse(reader, var);
2167 EXPECT_HR(hr, S_OK);
2168 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2169 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2170 EXPECT_HR(hr, S_OK);
2172 /* switch off 'namespace-prefixes' feature */
2173 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2174 EXPECT_HR(hr, S_OK);
2176 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2177 size.QuadPart = strlen(test_attributes);
2178 IStream_SetSize(stream, size);
2179 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2181 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2182 V_VT(&var) = VT_UNKNOWN;
2183 V_UNKNOWN(&var) = (IUnknown*)stream;
2185 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2186 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2188 test_seq = content_handler_test_attributes_alt_no_prefix;
2191 test_seq = content_handler_test_attributes_no_prefix;
2193 set_expected_seq(test_seq);
2194 hr = ISAXXMLReader_parse(reader, var);
2195 EXPECT_HR(hr, S_OK);
2196 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2198 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2199 EXPECT_HR(hr, S_OK);
2201 /* attribute normalization */
2202 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2203 size.QuadPart = strlen(attribute_normalize);
2204 IStream_SetSize(stream, size);
2205 IStream_Write(stream, attribute_normalize, strlen(attribute_normalize), &written);
2207 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2208 V_VT(&var) = VT_UNKNOWN;
2209 V_UNKNOWN(&var) = (IUnknown*)stream;
2211 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2212 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2214 test_seq = attribute_norm_alt;
2217 test_seq = attribute_norm;
2219 set_expected_seq(test_seq);
2220 hr = ISAXXMLReader_parse(reader, var);
2221 EXPECT_HR(hr, S_OK);
2222 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2224 ISAXXMLReader_Release(reader);
2231 struct saxreader_props_test_t
2233 const char *prop_name;
2237 static struct saxlexicalhandler lexicalhandler;
2238 static struct saxdeclhandler declhandler;
2240 static const struct saxreader_props_test_t props_test_data[] = {
2241 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2242 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2246 static void test_saxreader_properties(void)
2248 const struct saxreader_props_test_t *ptr = props_test_data;
2249 ISAXXMLReader *reader;
2252 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2253 &IID_ISAXXMLReader, (void**)&reader);
2254 EXPECT_HR(hr, S_OK);
2256 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2257 EXPECT_HR(hr, E_POINTER);
2259 while (ptr->prop_name)
2264 init_saxlexicalhandler(&lexicalhandler, S_OK);
2265 init_saxdeclhandler(&declhandler, S_OK);
2267 V_VT(&v) = VT_EMPTY;
2268 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2269 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2270 EXPECT_HR(hr, S_OK);
2271 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2272 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2274 V_VT(&v) = VT_UNKNOWN;
2275 V_UNKNOWN(&v) = ptr->iface;
2276 ref = get_refcount(ptr->iface);
2277 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2278 EXPECT_HR(hr, S_OK);
2279 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2281 V_VT(&v) = VT_EMPTY;
2282 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2284 ref = get_refcount(ptr->iface);
2285 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2286 EXPECT_HR(hr, S_OK);
2287 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2288 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2289 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2292 V_VT(&v) = VT_EMPTY;
2293 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2294 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2295 EXPECT_HR(hr, S_OK);
2297 V_VT(&v) = VT_EMPTY;
2298 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2299 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2300 EXPECT_HR(hr, S_OK);
2301 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2302 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2304 V_VT(&v) = VT_UNKNOWN;
2305 V_UNKNOWN(&v) = ptr->iface;
2306 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2307 EXPECT_HR(hr, S_OK);
2309 /* only VT_EMPTY seems to be valid to reset property */
2311 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2312 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2313 EXPECT_HR(hr, E_INVALIDARG);
2315 V_VT(&v) = VT_EMPTY;
2316 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2317 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2318 EXPECT_HR(hr, S_OK);
2319 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2320 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2323 V_VT(&v) = VT_UNKNOWN;
2324 V_UNKNOWN(&v) = NULL;
2325 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2326 EXPECT_HR(hr, S_OK);
2328 V_VT(&v) = VT_EMPTY;
2329 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2330 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2331 EXPECT_HR(hr, S_OK);
2332 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2333 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2335 /* block QueryInterface on handler riid */
2336 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2337 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2339 V_VT(&v) = VT_UNKNOWN;
2340 V_UNKNOWN(&v) = ptr->iface;
2341 EXPECT_REF(ptr->iface, 1);
2342 ref = get_refcount(ptr->iface);
2343 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2344 EXPECT_HR(hr, E_NOINTERFACE);
2345 EXPECT_REF(ptr->iface, 1);
2350 ISAXXMLReader_Release(reader);
2354 struct feature_ns_entry_t {
2358 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2361 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2362 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2363 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2364 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2365 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2369 static const char *feature_names[] = {
2370 "http://xml.org/sax/features/namespaces",
2371 "http://xml.org/sax/features/namespace-prefixes",
2375 static void test_saxreader_features(void)
2377 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2378 ISAXXMLReader *reader;
2386 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2389 win_skip("can't create %s instance\n", entry->clsid);
2394 name = feature_names;
2398 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2399 EXPECT_HR(hr, S_OK);
2400 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2403 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2404 EXPECT_HR(hr, S_OK);
2407 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2408 EXPECT_HR(hr, S_OK);
2409 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2411 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2412 EXPECT_HR(hr, S_OK);
2414 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2415 EXPECT_HR(hr, S_OK);
2416 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2418 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2419 EXPECT_HR(hr, S_OK);
2421 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2422 EXPECT_HR(hr, S_OK);
2423 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2428 ISAXXMLReader_Release(reader);
2434 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2435 static const CHAR UTF8BOMTest[] =
2436 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2439 struct enc_test_entry_t {
2447 static const struct enc_test_entry_t encoding_test_data[] = {
2448 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2449 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2450 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2451 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2455 static void test_saxreader_encoding(void)
2457 const struct enc_test_entry_t *entry = encoding_test_data;
2458 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2459 static const CHAR testXmlA[] = "test.xml";
2463 ISAXXMLReader *reader;
2469 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2472 win_skip("can't create %s instance\n", entry->clsid);
2477 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2478 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2479 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2482 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2484 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2486 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2488 DeleteFileA(testXmlA);
2490 /* try BSTR input with no BOM or '<?xml' instruction */
2491 V_VT(&input) = VT_BSTR;
2492 V_BSTR(&input) = _bstr_("<element></element>");
2493 hr = ISAXXMLReader_parse(reader, input);
2494 EXPECT_HR(hr, S_OK);
2496 ISAXXMLReader_Release(reader);
2503 static void test_mxwriter_handlers(void)
2505 ISAXContentHandler *handler;
2506 IMXWriter *writer, *writer2;
2507 ISAXDeclHandler *decl;
2508 ISAXLexicalHandler *lh;
2511 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2512 &IID_IMXWriter, (void**)&writer);
2513 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2515 EXPECT_REF(writer, 1);
2517 /* ISAXContentHandler */
2518 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2519 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2520 EXPECT_REF(writer, 2);
2521 EXPECT_REF(handler, 2);
2523 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2524 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2525 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2526 EXPECT_REF(writer, 3);
2527 EXPECT_REF(writer2, 3);
2528 IMXWriter_Release(writer2);
2529 ISAXContentHandler_Release(handler);
2531 /* ISAXLexicalHandler */
2532 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2533 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2534 EXPECT_REF(writer, 2);
2537 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2538 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2539 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2540 EXPECT_REF(writer, 3);
2541 EXPECT_REF(writer2, 3);
2542 IMXWriter_Release(writer2);
2543 ISAXLexicalHandler_Release(lh);
2545 /* ISAXDeclHandler */
2546 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2547 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2548 EXPECT_REF(writer, 2);
2551 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2552 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2553 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2554 EXPECT_REF(writer, 3);
2555 EXPECT_REF(writer2, 3);
2556 IMXWriter_Release(writer2);
2557 ISAXDeclHandler_Release(decl);
2559 IMXWriter_Release(writer);
2563 static struct msxmlsupported_data_t mxwriter_support_data[] =
2565 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2566 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2567 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2568 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2572 static struct msxmlsupported_data_t mxattributes_support_data[] =
2574 { &CLSID_SAXAttributes, "SAXAttributes" },
2575 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2576 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2577 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2581 struct mxwriter_props_t
2585 VARIANT_BOOL disable_escape;
2586 VARIANT_BOOL indent;
2587 VARIANT_BOOL omitdecl;
2588 VARIANT_BOOL standalone;
2589 const char *encoding;
2592 static const struct mxwriter_props_t mxwriter_default_props[] =
2594 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2595 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2596 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2597 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2601 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2605 while (table->clsid)
2612 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2619 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2620 &IID_IMXWriter, (void**)&writer);
2621 EXPECT_HR(hr, S_OK);
2624 hr = IMXWriter_get_byteOrderMark(writer, &b);
2625 EXPECT_HR(hr, S_OK);
2626 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2628 b = !table->disable_escape;
2629 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2630 EXPECT_HR(hr, S_OK);
2631 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2632 table->disable_escape);
2635 hr = IMXWriter_get_indent(writer, &b);
2636 EXPECT_HR(hr, S_OK);
2637 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2639 b = !table->omitdecl;
2640 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2641 EXPECT_HR(hr, S_OK);
2642 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2644 b = !table->standalone;
2645 hr = IMXWriter_get_standalone(writer, &b);
2646 EXPECT_HR(hr, S_OK);
2647 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2649 hr = IMXWriter_get_encoding(writer, &encoding);
2650 EXPECT_HR(hr, S_OK);
2651 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2652 i, wine_dbgstr_w(encoding), table->encoding);
2653 SysFreeString(encoding);
2655 IMXWriter_Release(writer);
2662 static void test_mxwriter_properties(void)
2664 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2665 static const WCHAR emptyW[] = {0};
2666 static const WCHAR testW[] = {'t','e','s','t',0};
2667 ISAXContentHandler *content;
2674 test_mxwriter_default_properties(mxwriter_default_props);
2676 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2677 &IID_IMXWriter, (void**)&writer);
2678 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2680 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2681 ok(hr == E_POINTER, "got %08x\n", hr);
2683 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2684 ok(hr == E_POINTER, "got %08x\n", hr);
2686 hr = IMXWriter_get_indent(writer, NULL);
2687 ok(hr == E_POINTER, "got %08x\n", hr);
2689 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2690 ok(hr == E_POINTER, "got %08x\n", hr);
2692 hr = IMXWriter_get_standalone(writer, NULL);
2693 ok(hr == E_POINTER, "got %08x\n", hr);
2696 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2697 ok(hr == S_OK, "got %08x\n", hr);
2700 hr = IMXWriter_get_standalone(writer, &b);
2701 ok(hr == S_OK, "got %08x\n", hr);
2702 ok(b == VARIANT_TRUE, "got %d\n", b);
2704 hr = IMXWriter_get_encoding(writer, NULL);
2705 EXPECT_HR(hr, E_POINTER);
2707 /* UTF-16 is a default setting apparently */
2708 str = (void*)0xdeadbeef;
2709 hr = IMXWriter_get_encoding(writer, &str);
2710 EXPECT_HR(hr, S_OK);
2711 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2713 str2 = (void*)0xdeadbeef;
2714 hr = IMXWriter_get_encoding(writer, &str2);
2715 ok(hr == S_OK, "got %08x\n", hr);
2716 ok(str != str2, "expected newly allocated, got same %p\n", str);
2718 SysFreeString(str2);
2721 /* put empty string */
2722 str = SysAllocString(emptyW);
2723 hr = IMXWriter_put_encoding(writer, str);
2724 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2727 str = (void*)0xdeadbeef;
2728 hr = IMXWriter_get_encoding(writer, &str);
2729 EXPECT_HR(hr, S_OK);
2730 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2733 /* invalid encoding name */
2734 str = SysAllocString(testW);
2735 hr = IMXWriter_put_encoding(writer, str);
2736 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2739 /* test case sensivity */
2740 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2741 EXPECT_HR(hr, S_OK);
2742 str = (void*)0xdeadbeef;
2743 hr = IMXWriter_get_encoding(writer, &str);
2744 EXPECT_HR(hr, S_OK);
2745 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2748 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2749 EXPECT_HR(hr, S_OK);
2750 str = (void*)0xdeadbeef;
2751 hr = IMXWriter_get_encoding(writer, &str);
2752 EXPECT_HR(hr, S_OK);
2753 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2756 /* how it affects document creation */
2757 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2758 EXPECT_HR(hr, S_OK);
2760 hr = ISAXContentHandler_startDocument(content);
2761 EXPECT_HR(hr, S_OK);
2762 hr = ISAXContentHandler_endDocument(content);
2763 EXPECT_HR(hr, S_OK);
2765 V_VT(&dest) = VT_EMPTY;
2766 hr = IMXWriter_get_output(writer, &dest);
2767 EXPECT_HR(hr, S_OK);
2768 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2769 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2770 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2771 VariantClear(&dest);
2772 ISAXContentHandler_Release(content);
2774 hr = IMXWriter_get_version(writer, NULL);
2775 ok(hr == E_POINTER, "got %08x\n", hr);
2776 /* default version is 'surprisingly' 1.0 */
2777 hr = IMXWriter_get_version(writer, &str);
2778 ok(hr == S_OK, "got %08x\n", hr);
2779 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2782 /* store version string as is */
2783 hr = IMXWriter_put_version(writer, NULL);
2784 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2786 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2787 ok(hr == S_OK, "got %08x\n", hr);
2789 hr = IMXWriter_put_version(writer, _bstr_(""));
2790 ok(hr == S_OK, "got %08x\n", hr);
2791 hr = IMXWriter_get_version(writer, &str);
2792 ok(hr == S_OK, "got %08x\n", hr);
2793 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2796 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2797 ok(hr == S_OK, "got %08x\n", hr);
2798 hr = IMXWriter_get_version(writer, &str);
2799 ok(hr == S_OK, "got %08x\n", hr);
2800 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2803 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2804 ok(hr == S_OK, "got %08x\n", hr);
2805 hr = IMXWriter_get_version(writer, &str);
2806 ok(hr == S_OK, "got %08x\n", hr);
2807 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2810 IMXWriter_Release(writer);
2814 static void test_mxwriter_flush(void)
2816 ISAXContentHandler *content;
2819 ULARGE_INTEGER pos2;
2824 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2825 &IID_IMXWriter, (void**)&writer);
2826 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2828 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2829 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2830 EXPECT_REF(stream, 1);
2832 /* detach when nothing was attached */
2833 V_VT(&dest) = VT_EMPTY;
2834 hr = IMXWriter_put_output(writer, dest);
2835 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2838 V_VT(&dest) = VT_UNKNOWN;
2839 V_UNKNOWN(&dest) = (IUnknown*)stream;
2840 hr = IMXWriter_put_output(writer, dest);
2841 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2842 todo_wine EXPECT_REF(stream, 3);
2844 /* detach setting VT_EMPTY destination */
2845 V_VT(&dest) = VT_EMPTY;
2846 hr = IMXWriter_put_output(writer, dest);
2847 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2848 EXPECT_REF(stream, 1);
2850 V_VT(&dest) = VT_UNKNOWN;
2851 V_UNKNOWN(&dest) = (IUnknown*)stream;
2852 hr = IMXWriter_put_output(writer, dest);
2853 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2855 /* flush() doesn't detach a stream */
2856 hr = IMXWriter_flush(writer);
2857 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2858 todo_wine EXPECT_REF(stream, 3);
2861 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2862 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2863 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2865 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2866 ok(hr == S_OK, "got %08x\n", hr);
2868 hr = ISAXContentHandler_startDocument(content);
2869 ok(hr == S_OK, "got %08x\n", hr);
2872 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2873 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2874 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2876 /* already started */
2877 hr = ISAXContentHandler_startDocument(content);
2878 ok(hr == S_OK, "got %08x\n", hr);
2880 hr = ISAXContentHandler_endDocument(content);
2881 ok(hr == S_OK, "got %08x\n", hr);
2883 /* flushed on endDocument() */
2885 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2886 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2887 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2889 ISAXContentHandler_Release(content);
2890 IStream_Release(stream);
2891 IMXWriter_Release(writer);
2894 static void test_mxwriter_startenddocument(void)
2896 ISAXContentHandler *content;
2901 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2902 &IID_IMXWriter, (void**)&writer);
2903 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2905 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2906 ok(hr == S_OK, "got %08x\n", hr);
2908 hr = ISAXContentHandler_startDocument(content);
2909 ok(hr == S_OK, "got %08x\n", hr);
2911 hr = ISAXContentHandler_endDocument(content);
2912 ok(hr == S_OK, "got %08x\n", hr);
2914 V_VT(&dest) = VT_EMPTY;
2915 hr = IMXWriter_get_output(writer, &dest);
2916 ok(hr == S_OK, "got %08x\n", hr);
2917 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2918 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2919 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2920 VariantClear(&dest);
2922 /* now try another startDocument */
2923 hr = ISAXContentHandler_startDocument(content);
2924 ok(hr == S_OK, "got %08x\n", hr);
2925 /* and get duplicated prolog */
2926 V_VT(&dest) = VT_EMPTY;
2927 hr = IMXWriter_get_output(writer, &dest);
2928 ok(hr == S_OK, "got %08x\n", hr);
2929 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2930 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
2931 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2932 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2933 VariantClear(&dest);
2935 ISAXContentHandler_Release(content);
2936 IMXWriter_Release(writer);
2938 /* now with omitted declaration */
2939 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2940 &IID_IMXWriter, (void**)&writer);
2941 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2943 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2944 ok(hr == S_OK, "got %08x\n", hr);
2946 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2947 ok(hr == S_OK, "got %08x\n", hr);
2949 hr = ISAXContentHandler_startDocument(content);
2950 ok(hr == S_OK, "got %08x\n", hr);
2952 hr = ISAXContentHandler_endDocument(content);
2953 ok(hr == S_OK, "got %08x\n", hr);
2955 V_VT(&dest) = VT_EMPTY;
2956 hr = IMXWriter_get_output(writer, &dest);
2957 ok(hr == S_OK, "got %08x\n", hr);
2958 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2959 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2960 VariantClear(&dest);
2962 ISAXContentHandler_Release(content);
2963 IMXWriter_Release(writer);
2970 StartElement = 0x001,
2972 StartEndElement = 0x011,
2973 DisableEscaping = 0x100
2976 struct writer_startendelement_t {
2978 enum startendtype type;
2980 const char *local_name;
2984 ISAXAttributes *attr;
2987 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\">";
2988 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\"/>";
2989 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
2991 static const struct writer_startendelement_t writer_startendelement[] = {
2993 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2994 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2995 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2996 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
2997 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2999 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3000 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3001 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3002 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3003 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3005 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3006 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3007 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3008 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3009 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3011 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3012 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3013 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3014 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3015 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3017 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3018 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3019 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3020 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3021 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3023 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3024 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3025 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3026 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3027 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3029 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3030 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3031 /* endElement tests */
3032 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3033 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3034 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3036 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3037 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3038 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3039 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3040 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3042 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3043 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3044 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3045 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3046 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3048 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3049 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3050 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3051 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3052 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3054 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3055 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3056 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3057 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3058 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3060 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3061 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3062 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3063 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3064 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3066 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3067 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3068 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3069 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3071 /* with attributes */
3072 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3074 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3075 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3076 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3077 /* empty elements */
3078 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3079 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3081 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3082 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3083 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3084 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3085 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3087 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3089 /* with disabled output escaping */
3090 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3091 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3092 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3093 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3098 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3100 while (table->clsid)
3105 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3106 if (hr == S_OK) IUnknown_Release(unk);
3108 table->supported = hr == S_OK;
3109 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3115 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3119 while (table->clsid)
3121 ISAXContentHandler *content;
3125 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3132 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3133 &IID_IMXWriter, (void**)&writer);
3134 EXPECT_HR(hr, S_OK);
3136 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3137 EXPECT_HR(hr, S_OK);
3139 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3140 EXPECT_HR(hr, S_OK);
3142 hr = ISAXContentHandler_startDocument(content);
3143 EXPECT_HR(hr, S_OK);
3145 if (table->type & DisableEscaping)
3147 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3148 EXPECT_HR(hr, S_OK);
3151 if (table->type & StartElement)
3153 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3154 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3155 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3158 if (table->type & EndElement)
3160 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3161 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3162 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3170 V_VT(&dest) = VT_EMPTY;
3171 hr = IMXWriter_get_output(writer, &dest);
3172 EXPECT_HR(hr, S_OK);
3173 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3174 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3175 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3176 VariantClear(&dest);
3179 ISAXContentHandler_Release(content);
3180 IMXWriter_Release(writer);
3189 static void test_mxwriter_startendelement(void)
3191 ISAXContentHandler *content;
3196 test_mxwriter_startendelement_batch(writer_startendelement);
3198 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3199 &IID_IMXWriter, (void**)&writer);
3200 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3202 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3203 ok(hr == S_OK, "got %08x\n", hr);
3205 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3206 ok(hr == S_OK, "got %08x\n", hr);
3208 hr = ISAXContentHandler_startDocument(content);
3209 ok(hr == S_OK, "got %08x\n", hr);
3211 /* all string pointers should be not null */
3212 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3213 ok(hr == S_OK, "got %08x\n", hr);
3215 V_VT(&dest) = VT_EMPTY;
3216 hr = IMXWriter_get_output(writer, &dest);
3217 ok(hr == S_OK, "got %08x\n", hr);
3218 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3219 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3220 VariantClear(&dest);
3222 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3223 ok(hr == S_OK, "got %08x\n", hr);
3225 V_VT(&dest) = VT_EMPTY;
3226 hr = IMXWriter_get_output(writer, &dest);
3227 ok(hr == S_OK, "got %08x\n", hr);
3228 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3229 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3230 VariantClear(&dest);
3232 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3233 EXPECT_HR(hr, E_INVALIDARG);
3235 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3236 EXPECT_HR(hr, E_INVALIDARG);
3238 /* only local name is an error too */
3239 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3240 EXPECT_HR(hr, E_INVALIDARG);
3242 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3243 EXPECT_HR(hr, S_OK);
3245 V_VT(&dest) = VT_EMPTY;
3246 hr = IMXWriter_get_output(writer, &dest);
3247 EXPECT_HR(hr, S_OK);
3248 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3249 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3250 VariantClear(&dest);
3252 hr = ISAXContentHandler_endDocument(content);
3253 EXPECT_HR(hr, S_OK);
3255 V_VT(&dest) = VT_EMPTY;
3256 hr = IMXWriter_put_output(writer, dest);
3257 EXPECT_HR(hr, S_OK);
3259 V_VT(&dest) = VT_EMPTY;
3260 hr = IMXWriter_get_output(writer, &dest);
3261 EXPECT_HR(hr, S_OK);
3262 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3263 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3264 VariantClear(&dest);
3266 hr = ISAXContentHandler_startDocument(content);
3267 EXPECT_HR(hr, S_OK);
3269 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3270 EXPECT_HR(hr, S_OK);
3272 V_VT(&dest) = VT_EMPTY;
3273 hr = IMXWriter_get_output(writer, &dest);
3274 EXPECT_HR(hr, S_OK);
3275 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3276 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3277 VariantClear(&dest);
3279 ISAXContentHandler_endDocument(content);
3280 IMXWriter_flush(writer);
3282 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3283 EXPECT_HR(hr, S_OK);
3284 V_VT(&dest) = VT_EMPTY;
3285 hr = IMXWriter_get_output(writer, &dest);
3286 EXPECT_HR(hr, S_OK);
3287 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3288 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3289 VariantClear(&dest);
3291 ISAXContentHandler_Release(content);
3292 IMXWriter_Release(writer);
3296 struct writer_characters_t {
3302 static const struct writer_characters_t writer_characters[] = {
3303 { &CLSID_MXXMLWriter, "< > & \"", "< > & \"" },
3304 { &CLSID_MXXMLWriter30, "< > & \"", "< > & \"" },
3305 { &CLSID_MXXMLWriter40, "< > & \"", "< > & \"" },
3306 { &CLSID_MXXMLWriter60, "< > & \"", "< > & \"" },
3310 static void test_mxwriter_characters(void)
3312 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3313 const struct writer_characters_t *table = writer_characters;
3314 ISAXContentHandler *content;
3320 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3321 &IID_IMXWriter, (void**)&writer);
3322 EXPECT_HR(hr, S_OK);
3324 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3325 EXPECT_HR(hr, S_OK);
3327 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3328 EXPECT_HR(hr, S_OK);
3330 hr = ISAXContentHandler_startDocument(content);
3331 EXPECT_HR(hr, S_OK);
3333 hr = ISAXContentHandler_characters(content, NULL, 0);
3334 EXPECT_HR(hr, E_INVALIDARG);
3336 hr = ISAXContentHandler_characters(content, chardataW, 0);
3337 EXPECT_HR(hr, S_OK);
3339 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3340 EXPECT_HR(hr, S_OK);
3342 V_VT(&dest) = VT_EMPTY;
3343 hr = IMXWriter_get_output(writer, &dest);
3344 EXPECT_HR(hr, S_OK);
3345 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3346 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3347 VariantClear(&dest);
3349 hr = ISAXContentHandler_endDocument(content);
3350 EXPECT_HR(hr, S_OK);
3352 ISAXContentHandler_Release(content);
3353 IMXWriter_Release(writer);
3355 /* try empty characters data to see if element is closed */
3356 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3357 &IID_IMXWriter, (void**)&writer);
3358 EXPECT_HR(hr, S_OK);
3360 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3361 EXPECT_HR(hr, S_OK);
3363 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3364 EXPECT_HR(hr, S_OK);
3366 hr = ISAXContentHandler_startDocument(content);
3367 EXPECT_HR(hr, S_OK);
3369 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3370 EXPECT_HR(hr, S_OK);
3372 hr = ISAXContentHandler_characters(content, chardataW, 0);
3373 EXPECT_HR(hr, S_OK);
3375 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3376 EXPECT_HR(hr, S_OK);
3378 V_VT(&dest) = VT_EMPTY;
3379 hr = IMXWriter_get_output(writer, &dest);
3380 EXPECT_HR(hr, S_OK);
3381 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3382 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3383 VariantClear(&dest);
3385 ISAXContentHandler_Release(content);
3386 IMXWriter_Release(writer);
3389 while (table->clsid)
3391 ISAXContentHandler *content;
3396 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3403 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3404 &IID_IMXWriter, (void**)&writer);
3405 EXPECT_HR(hr, S_OK);
3407 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3408 EXPECT_HR(hr, S_OK);
3410 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3411 EXPECT_HR(hr, S_OK);
3413 hr = ISAXContentHandler_startDocument(content);
3414 EXPECT_HR(hr, S_OK);
3416 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3417 EXPECT_HR(hr, S_OK);
3422 V_VT(&dest) = VT_EMPTY;
3423 hr = IMXWriter_get_output(writer, &dest);
3424 EXPECT_HR(hr, S_OK);
3425 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3426 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3427 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3428 VariantClear(&dest);
3431 /* with disabled escaping */
3432 V_VT(&dest) = VT_EMPTY;
3433 hr = IMXWriter_put_output(writer, dest);
3434 EXPECT_HR(hr, S_OK);
3436 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3437 EXPECT_HR(hr, S_OK);
3439 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3440 EXPECT_HR(hr, S_OK);
3445 V_VT(&dest) = VT_EMPTY;
3446 hr = IMXWriter_get_output(writer, &dest);
3447 EXPECT_HR(hr, S_OK);
3448 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3449 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3450 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3451 VariantClear(&dest);
3454 ISAXContentHandler_Release(content);
3455 IMXWriter_Release(writer);
3464 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3466 VARIANT_TRUE,"UTF-16",
3468 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3469 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3474 VARIANT_FALSE,"UTF-16",
3476 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3481 VARIANT_TRUE,"UTF-8",
3483 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3484 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3485 * and the writer is released.
3492 VARIANT_TRUE,"utf-8",
3494 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3495 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3496 * and the writer is released.
3503 VARIANT_TRUE,"UTF-16",
3505 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3506 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3511 VARIANT_TRUE,"UTF-16",
3513 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3514 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3520 static void test_mxwriter_stream(void)
3523 ISAXContentHandler *content;
3528 ULARGE_INTEGER pos2;
3529 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3531 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3532 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3534 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3535 &IID_IMXWriter, (void**)&writer);
3536 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3538 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3539 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3541 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3542 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3544 V_VT(&dest) = VT_UNKNOWN;
3545 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3546 hr = IMXWriter_put_output(writer, dest);
3547 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3548 VariantClear(&dest);
3550 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3551 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3553 current_write_test = test->expected_writes;
3555 hr = ISAXContentHandler_startDocument(content);
3556 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3558 hr = ISAXContentHandler_endDocument(content);
3559 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3561 ISAXContentHandler_Release(content);
3562 IMXWriter_Release(writer);
3564 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3565 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3568 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3569 &IID_IMXWriter, (void**)&writer);
3570 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3572 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3573 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3575 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3576 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3578 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3579 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3581 V_VT(&dest) = VT_UNKNOWN;
3582 V_UNKNOWN(&dest) = (IUnknown*)stream;
3583 hr = IMXWriter_put_output(writer, dest);
3584 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3586 hr = ISAXContentHandler_startDocument(content);
3587 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3589 /* Setting output of the mxwriter causes the current output to be flushed,
3590 * and the writer to start over.
3592 V_VT(&dest) = VT_EMPTY;
3593 hr = IMXWriter_put_output(writer, dest);
3594 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3597 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3598 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3599 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3601 hr = ISAXContentHandler_startDocument(content);
3602 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3604 hr = ISAXContentHandler_endDocument(content);
3605 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3607 V_VT(&dest) = VT_EMPTY;
3608 hr = IMXWriter_get_output(writer, &dest);
3609 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3610 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3611 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3612 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3613 VariantClear(&dest);
3615 /* test when BOM is written to output stream */
3616 V_VT(&dest) = VT_EMPTY;
3617 hr = IMXWriter_put_output(writer, dest);
3618 EXPECT_HR(hr, S_OK);
3621 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3622 EXPECT_HR(hr, S_OK);
3624 V_VT(&dest) = VT_UNKNOWN;
3625 V_UNKNOWN(&dest) = (IUnknown*)stream;
3626 hr = IMXWriter_put_output(writer, dest);
3627 EXPECT_HR(hr, S_OK);
3629 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3630 EXPECT_HR(hr, S_OK);
3632 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3633 EXPECT_HR(hr, S_OK);
3635 hr = ISAXContentHandler_startDocument(content);
3636 EXPECT_HR(hr, S_OK);
3640 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3641 EXPECT_HR(hr, S_OK);
3642 ok(pos2.QuadPart == 2, "got wrong position\n");
3644 ISAXContentHandler_Release(content);
3645 IMXWriter_Release(writer);
3650 static void test_mxwriter_encoding(void)
3652 ISAXContentHandler *content;
3661 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3662 &IID_IMXWriter, (void**)&writer);
3663 EXPECT_HR(hr, S_OK);
3665 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3666 EXPECT_HR(hr, S_OK);
3668 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3669 EXPECT_HR(hr, S_OK);
3671 hr = ISAXContentHandler_startDocument(content);
3672 EXPECT_HR(hr, S_OK);
3674 hr = ISAXContentHandler_endDocument(content);
3675 EXPECT_HR(hr, S_OK);
3677 /* The content is always re-encoded to UTF-16 when the output is
3678 * retrieved as a BSTR.
3680 V_VT(&dest) = VT_EMPTY;
3681 hr = IMXWriter_get_output(writer, &dest);
3682 EXPECT_HR(hr, S_OK);
3683 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3684 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3685 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3686 VariantClear(&dest);
3688 /* switch encoding when something is written already */
3689 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3690 EXPECT_HR(hr, S_OK);
3692 V_VT(&dest) = VT_UNKNOWN;
3693 V_UNKNOWN(&dest) = (IUnknown*)stream;
3694 hr = IMXWriter_put_output(writer, dest);
3695 EXPECT_HR(hr, S_OK);
3697 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3698 EXPECT_HR(hr, S_OK);
3700 /* write empty element */
3701 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3702 EXPECT_HR(hr, S_OK);
3704 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3705 EXPECT_HR(hr, S_OK);
3708 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3709 EXPECT_HR(hr, S_OK);
3711 hr = IMXWriter_flush(writer);
3712 EXPECT_HR(hr, S_OK);
3714 hr = GetHGlobalFromStream(stream, &g);
3715 EXPECT_HR(hr, S_OK);
3717 ptr = GlobalLock(g);
3718 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3721 /* so output is unaffected, encoding name is stored however */
3722 hr = IMXWriter_get_encoding(writer, &s);
3723 EXPECT_HR(hr, S_OK);
3724 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3727 IStream_Release(stream);
3729 ISAXContentHandler_Release(content);
3730 IMXWriter_Release(writer);
3735 static void test_obj_dispex(IUnknown *obj)
3737 static const WCHAR starW[] = {'*',0};
3738 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
3739 IDispatchEx *dispex;
3746 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
3747 EXPECT_HR(hr, S_OK);
3748 if (FAILED(hr)) return;
3751 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
3752 EXPECT_HR(hr, S_OK);
3753 ok(ticnt == 1, "ticnt=%u\n", ticnt);
3755 name = SysAllocString(starW);
3756 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
3757 EXPECT_HR(hr, E_NOTIMPL);
3758 SysFreeString(name);
3760 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
3761 EXPECT_HR(hr, E_NOTIMPL);
3764 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
3765 EXPECT_HR(hr, E_NOTIMPL);
3766 ok(props == 0, "expected 0 got %d\n", props);
3768 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
3769 EXPECT_HR(hr, E_NOTIMPL);
3770 if (SUCCEEDED(hr)) SysFreeString(name);
3772 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
3773 EXPECT_HR(hr, E_NOTIMPL);
3775 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
3776 EXPECT_HR(hr, E_NOTIMPL);
3777 if (hr == S_OK && unk) IUnknown_Release(unk);
3779 IDispatchEx_Release(dispex);
3782 static void test_dispex(void)
3784 IVBSAXXMLReader *vbreader;
3785 ISAXXMLReader *reader;
3789 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
3790 &IID_ISAXXMLReader, (void**)&reader);
3791 EXPECT_HR(hr, S_OK);
3793 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
3794 EXPECT_HR(hr, S_OK);
3795 test_obj_dispex(unk);
3796 IUnknown_Release(unk);
3798 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
3799 EXPECT_HR(hr, S_OK);
3800 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
3801 EXPECT_HR(hr, S_OK);
3802 test_obj_dispex(unk);
3803 IUnknown_Release(unk);
3804 IVBSAXXMLReader_Release(vbreader);
3806 ISAXXMLReader_Release(reader);
3809 static void test_mxwriter_dispex(void)
3811 IDispatchEx *dispex;
3816 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3817 &IID_IMXWriter, (void**)&writer);
3818 EXPECT_HR(hr, S_OK);
3820 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
3821 EXPECT_HR(hr, S_OK);
3822 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
3823 test_obj_dispex(unk);
3824 IUnknown_Release(unk);
3825 IDispatchEx_Release(dispex);
3827 IMXWriter_Release(writer);
3830 static void test_mxwriter_comment(void)
3832 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
3833 ISAXContentHandler *content;
3834 ISAXLexicalHandler *lexical;
3839 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3840 &IID_IMXWriter, (void**)&writer);
3841 EXPECT_HR(hr, S_OK);
3843 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3844 EXPECT_HR(hr, S_OK);
3846 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3847 EXPECT_HR(hr, S_OK);
3849 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3850 EXPECT_HR(hr, S_OK);
3852 hr = ISAXContentHandler_startDocument(content);
3853 EXPECT_HR(hr, S_OK);
3855 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
3856 EXPECT_HR(hr, E_INVALIDARG);
3858 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
3859 EXPECT_HR(hr, S_OK);
3861 V_VT(&dest) = VT_EMPTY;
3862 hr = IMXWriter_get_output(writer, &dest);
3863 EXPECT_HR(hr, S_OK);
3864 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3865 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3866 VariantClear(&dest);
3868 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
3869 EXPECT_HR(hr, S_OK);
3871 V_VT(&dest) = VT_EMPTY;
3872 hr = IMXWriter_get_output(writer, &dest);
3873 EXPECT_HR(hr, S_OK);
3874 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3875 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3876 VariantClear(&dest);
3878 ISAXContentHandler_Release(content);
3879 ISAXLexicalHandler_Release(lexical);
3880 IMXWriter_Release(writer);
3884 static void test_mxwriter_cdata(void)
3886 ISAXContentHandler *content;
3887 ISAXLexicalHandler *lexical;
3892 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3893 &IID_IMXWriter, (void**)&writer);
3894 EXPECT_HR(hr, S_OK);
3896 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3897 EXPECT_HR(hr, S_OK);
3899 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3900 EXPECT_HR(hr, S_OK);
3902 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3903 EXPECT_HR(hr, S_OK);
3905 hr = ISAXContentHandler_startDocument(content);
3906 EXPECT_HR(hr, S_OK);
3908 hr = ISAXLexicalHandler_startCDATA(lexical);
3909 EXPECT_HR(hr, S_OK);
3911 V_VT(&dest) = VT_EMPTY;
3912 hr = IMXWriter_get_output(writer, &dest);
3913 EXPECT_HR(hr, S_OK);
3914 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3915 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3916 VariantClear(&dest);
3918 hr = ISAXLexicalHandler_startCDATA(lexical);
3919 EXPECT_HR(hr, S_OK);
3921 /* all these are escaped for text nodes */
3922 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
3923 EXPECT_HR(hr, S_OK);
3925 hr = ISAXLexicalHandler_endCDATA(lexical);
3926 EXPECT_HR(hr, S_OK);
3928 V_VT(&dest) = VT_EMPTY;
3929 hr = IMXWriter_get_output(writer, &dest);
3930 EXPECT_HR(hr, S_OK);
3931 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3932 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3933 VariantClear(&dest);
3935 ISAXContentHandler_Release(content);
3936 ISAXLexicalHandler_Release(lexical);
3937 IMXWriter_Release(writer);
3941 static void test_mxwriter_pi(void)
3943 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
3944 static const WCHAR dataW[] = {'d','a','t','a',0};
3945 ISAXContentHandler *content;
3950 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3951 &IID_IMXWriter, (void**)&writer);
3952 EXPECT_HR(hr, S_OK);
3954 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3955 EXPECT_HR(hr, S_OK);
3957 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
3958 EXPECT_HR(hr, E_INVALIDARG);
3960 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
3961 EXPECT_HR(hr, S_OK);
3963 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
3964 EXPECT_HR(hr, S_OK);
3966 V_VT(&dest) = VT_EMPTY;
3967 hr = IMXWriter_get_output(writer, &dest);
3968 EXPECT_HR(hr, S_OK);
3969 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3970 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3971 VariantClear(&dest);
3973 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
3974 EXPECT_HR(hr, S_OK);
3976 V_VT(&dest) = VT_EMPTY;
3977 hr = IMXWriter_get_output(writer, &dest);
3978 EXPECT_HR(hr, S_OK);
3979 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3980 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)));
3981 VariantClear(&dest);
3983 V_VT(&dest) = VT_EMPTY;
3984 hr = IMXWriter_put_output(writer, dest);
3985 EXPECT_HR(hr, S_OK);
3987 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
3988 EXPECT_HR(hr, S_OK);
3990 V_VT(&dest) = VT_EMPTY;
3991 hr = IMXWriter_get_output(writer, &dest);
3992 EXPECT_HR(hr, S_OK);
3993 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3994 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3995 VariantClear(&dest);
3998 ISAXContentHandler_Release(content);
3999 IMXWriter_Release(writer);
4002 static void test_mxwriter_ignorablespaces(void)
4004 static const WCHAR dataW[] = {'d','a','t','a',0};
4005 ISAXContentHandler *content;
4010 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4011 &IID_IMXWriter, (void**)&writer);
4012 EXPECT_HR(hr, S_OK);
4014 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4015 EXPECT_HR(hr, S_OK);
4017 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4018 EXPECT_HR(hr, E_INVALIDARG);
4020 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4021 EXPECT_HR(hr, S_OK);
4023 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4024 EXPECT_HR(hr, S_OK);
4026 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4027 EXPECT_HR(hr, S_OK);
4029 V_VT(&dest) = VT_EMPTY;
4030 hr = IMXWriter_get_output(writer, &dest);
4031 EXPECT_HR(hr, S_OK);
4032 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4033 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4034 VariantClear(&dest);
4036 ISAXContentHandler_Release(content);
4037 IMXWriter_Release(writer);
4040 static void test_mxwriter_dtd(void)
4042 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4043 static const WCHAR nameW[] = {'n','a','m','e'};
4044 static const WCHAR pubW[] = {'p','u','b'};
4045 static const WCHAR sysW[] = {'s','y','s'};
4046 ISAXContentHandler *content;
4047 ISAXLexicalHandler *lexical;
4048 ISAXDeclHandler *decl;
4053 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4054 &IID_IMXWriter, (void**)&writer);
4055 EXPECT_HR(hr, S_OK);
4057 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4058 EXPECT_HR(hr, S_OK);
4060 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4061 EXPECT_HR(hr, S_OK);
4063 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4064 EXPECT_HR(hr, S_OK);
4066 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4067 EXPECT_HR(hr, S_OK);
4069 hr = ISAXContentHandler_startDocument(content);
4070 EXPECT_HR(hr, S_OK);
4072 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4073 EXPECT_HR(hr, E_INVALIDARG);
4075 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4076 EXPECT_HR(hr, E_INVALIDARG);
4078 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4079 EXPECT_HR(hr, E_INVALIDARG);
4081 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4082 EXPECT_HR(hr, E_INVALIDARG);
4084 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4085 EXPECT_HR(hr, S_OK);
4087 V_VT(&dest) = VT_EMPTY;
4088 hr = IMXWriter_get_output(writer, &dest);
4089 EXPECT_HR(hr, S_OK);
4090 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4091 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4092 VariantClear(&dest);
4094 /* system id is required if public is present */
4095 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4096 EXPECT_HR(hr, E_INVALIDARG);
4098 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4099 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4100 EXPECT_HR(hr, S_OK);
4102 V_VT(&dest) = VT_EMPTY;
4103 hr = IMXWriter_get_output(writer, &dest);
4104 EXPECT_HR(hr, S_OK);
4105 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4106 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4107 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4108 VariantClear(&dest);
4110 hr = ISAXLexicalHandler_endDTD(lexical);
4111 EXPECT_HR(hr, S_OK);
4113 hr = ISAXLexicalHandler_endDTD(lexical);
4114 EXPECT_HR(hr, S_OK);
4116 V_VT(&dest) = VT_EMPTY;
4117 hr = IMXWriter_get_output(writer, &dest);
4118 EXPECT_HR(hr, S_OK);
4119 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4120 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4121 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4122 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4123 VariantClear(&dest);
4125 /* element declaration */
4126 V_VT(&dest) = VT_EMPTY;
4127 hr = IMXWriter_put_output(writer, dest);
4128 EXPECT_HR(hr, S_OK);
4130 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4131 EXPECT_HR(hr, E_INVALIDARG);
4133 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4134 EXPECT_HR(hr, E_INVALIDARG);
4136 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4137 EXPECT_HR(hr, S_OK);
4139 V_VT(&dest) = VT_EMPTY;
4140 hr = IMXWriter_get_output(writer, &dest);
4141 EXPECT_HR(hr, S_OK);
4142 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4143 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4144 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4145 VariantClear(&dest);
4147 V_VT(&dest) = VT_EMPTY;
4148 hr = IMXWriter_put_output(writer, dest);
4149 EXPECT_HR(hr, S_OK);
4151 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4152 EXPECT_HR(hr, S_OK);
4154 V_VT(&dest) = VT_EMPTY;
4155 hr = IMXWriter_get_output(writer, &dest);
4156 EXPECT_HR(hr, S_OK);
4157 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4158 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4159 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4160 VariantClear(&dest);
4162 ISAXContentHandler_Release(content);
4163 ISAXLexicalHandler_Release(lexical);
4164 ISAXDeclHandler_Release(decl);
4165 IMXWriter_Release(writer);
4177 } addattribute_test_t;
4179 static const addattribute_test_t addattribute_data[] = {
4180 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4181 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4182 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4183 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4185 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4186 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4187 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4188 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4190 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4191 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4192 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4193 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4195 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4196 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4197 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4198 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4203 static void test_mxattr_addAttribute(void)
4205 const addattribute_test_t *table = addattribute_data;
4208 while (table->clsid)
4210 ISAXAttributes *saxattr;
4211 IMXAttributes *mxattr;
4216 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4223 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4224 &IID_IMXAttributes, (void**)&mxattr);
4225 EXPECT_HR(hr, S_OK);
4227 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4228 EXPECT_HR(hr, S_OK);
4230 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4231 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4232 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4234 hr = ISAXAttributes_getLength(saxattr, NULL);
4235 EXPECT_HR(hr, E_POINTER);
4239 hr = ISAXAttributes_getLength(saxattr, &len);
4240 EXPECT_HR(hr, S_OK);
4241 ok(len == 0, "got %d\n", len);
4243 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4244 EXPECT_HR(hr, E_INVALIDARG);
4246 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4247 EXPECT_HR(hr, E_INVALIDARG);
4249 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4250 EXPECT_HR(hr, E_INVALIDARG);
4252 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4253 EXPECT_HR(hr, E_INVALIDARG);
4255 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4256 EXPECT_HR(hr, E_INVALIDARG);
4258 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4259 EXPECT_HR(hr, E_INVALIDARG);
4261 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4262 EXPECT_HR(hr, E_INVALIDARG);
4264 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4265 EXPECT_HR(hr, E_INVALIDARG);
4267 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4268 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4269 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4273 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4274 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4275 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4277 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4278 EXPECT_HR(hr, E_POINTER);
4280 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4281 EXPECT_HR(hr, E_POINTER);
4283 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4284 EXPECT_HR(hr, E_POINTER);
4286 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4287 EXPECT_HR(hr, E_POINTER);
4289 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4290 EXPECT_HR(hr, E_POINTER);
4292 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4293 EXPECT_HR(hr, E_POINTER);
4297 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4298 EXPECT_HR(hr, S_OK);
4299 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4301 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4304 value = (void*)0xdeadbeef;
4305 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4306 EXPECT_HR(hr, S_OK);
4310 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4312 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4316 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4317 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4320 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4321 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4322 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4324 EXPECT_HR(hr, E_POINTER);
4327 EXPECT_HR(hr, E_INVALIDARG);
4329 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4330 EXPECT_HR(hr, E_INVALIDARG);
4333 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4334 EXPECT_HR(hr, E_INVALIDARG);
4335 ok(index == -1, "%d: got wrong index %d\n", i, index);
4338 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4339 EXPECT_HR(hr, E_INVALIDARG);
4340 ok(index == -1, "%d: got wrong index %d\n", i, index);
4343 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4344 EXPECT_HR(hr, S_OK);
4345 ok(index == 0, "%d: got wrong index %d\n", i, index);
4348 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4349 EXPECT_HR(hr, E_INVALIDARG);
4350 ok(index == -1, "%d: got wrong index %d\n", i, index);
4352 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4353 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4355 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4356 EXPECT_HR(hr, E_INVALIDARG);
4358 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4359 EXPECT_HR(hr, E_INVALIDARG);
4361 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4362 EXPECT_HR(hr, E_INVALIDARG);
4364 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4365 EXPECT_HR(hr, E_INVALIDARG);
4367 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4368 EXPECT_HR(hr, E_INVALIDARG);
4370 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4371 EXPECT_HR(hr, E_INVALIDARG);
4375 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4376 EXPECT_HR(hr, E_POINTER);
4378 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4379 EXPECT_HR(hr, E_POINTER);
4381 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4382 EXPECT_HR(hr, E_POINTER);
4384 /* versions 4 and 6 crash */
4385 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4386 EXPECT_HR(hr, E_POINTER);
4388 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4389 EXPECT_HR(hr, E_POINTER);
4391 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4392 EXPECT_HR(hr, E_POINTER);
4394 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4395 EXPECT_HR(hr, E_POINTER);
4397 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4398 EXPECT_HR(hr, E_POINTER);
4400 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4401 EXPECT_HR(hr, E_POINTER);
4403 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4404 EXPECT_HR(hr, E_POINTER);
4406 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4407 strlen(table->local), NULL, NULL);
4408 EXPECT_HR(hr, E_POINTER);
4411 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4412 EXPECT_HR(hr, S_OK);
4413 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4415 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4418 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4419 _bstr_(table->local), strlen(table->local), &value, &len);
4420 EXPECT_HR(hr, S_OK);
4421 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4423 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4428 hr = ISAXAttributes_getLength(saxattr, &len);
4429 EXPECT_HR(hr, S_OK);
4430 if (table->hr == S_OK)
4431 ok(len == 1, "%d: got %d length, expected 0\n", i, len);
4433 ok(len == 0, "%d: got %d length, expected 1\n", i, len);
4435 ISAXAttributes_Release(saxattr);
4436 IMXAttributes_Release(mxattr);
4445 static void test_mxattr_clear(void)
4447 ISAXAttributes *saxattr;
4448 IMXAttributes *mxattr;
4453 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4454 &IID_IMXAttributes, (void**)&mxattr);
4455 EXPECT_HR(hr, S_OK);
4457 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4458 EXPECT_HR(hr, S_OK);
4460 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4461 EXPECT_HR(hr, E_INVALIDARG);
4463 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4464 EXPECT_HR(hr, E_INVALIDARG);
4466 hr = IMXAttributes_clear(mxattr);
4467 EXPECT_HR(hr, S_OK);
4469 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4470 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4471 EXPECT_HR(hr, S_OK);
4474 hr = ISAXAttributes_getLength(saxattr, &len);
4475 EXPECT_HR(hr, S_OK);
4476 ok(len == 1, "got %d\n", len);
4479 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4480 EXPECT_HR(hr, E_POINTER);
4481 ok(len == -1, "got %d\n", len);
4483 ptr = (void*)0xdeadbeef;
4484 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4485 EXPECT_HR(hr, E_POINTER);
4486 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4489 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4490 EXPECT_HR(hr, S_OK);
4491 ok(len == 5, "got %d\n", len);
4492 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4494 hr = IMXAttributes_clear(mxattr);
4495 EXPECT_HR(hr, S_OK);
4498 hr = ISAXAttributes_getLength(saxattr, &len);
4499 EXPECT_HR(hr, S_OK);
4500 ok(len == 0, "got %d\n", len);
4503 ptr = (void*)0xdeadbeef;
4504 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4505 EXPECT_HR(hr, E_INVALIDARG);
4506 ok(len == -1, "got %d\n", len);
4507 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4509 IMXAttributes_Release(mxattr);
4510 ISAXAttributes_Release(saxattr);
4514 static void test_mxattr_dispex(void)
4516 IMXAttributes *mxattr;
4517 IDispatchEx *dispex;
4521 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4522 &IID_IMXAttributes, (void**)&mxattr);
4523 EXPECT_HR(hr, S_OK);
4525 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4526 EXPECT_HR(hr, S_OK);
4527 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4528 test_obj_dispex(unk);
4529 IUnknown_Release(unk);
4530 IDispatchEx_Release(dispex);
4532 IMXAttributes_Release(mxattr);
4535 static void test_mxattr_qi(void)
4537 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4538 ISAXAttributes *saxattr;
4539 IMXAttributes *mxattr;
4542 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4543 &IID_IMXAttributes, (void**)&mxattr);
4544 EXPECT_HR(hr, S_OK);
4546 EXPECT_REF(mxattr, 1);
4547 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4548 EXPECT_HR(hr, S_OK);
4550 EXPECT_REF(mxattr, 2);
4551 EXPECT_REF(saxattr, 2);
4553 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4554 EXPECT_HR(hr, S_OK);
4556 EXPECT_REF(vbsaxattr, 3);
4557 EXPECT_REF(mxattr, 3);
4558 EXPECT_REF(saxattr, 3);
4560 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4561 EXPECT_HR(hr, S_OK);
4563 EXPECT_REF(vbsaxattr, 4);
4564 EXPECT_REF(mxattr, 4);
4565 EXPECT_REF(saxattr, 4);
4567 IMXAttributes_Release(mxattr);
4568 ISAXAttributes_Release(saxattr);
4569 IVBSAXAttributes_Release(vbsaxattr);
4570 IVBSAXAttributes_Release(vbsaxattr2);
4573 static struct msxmlsupported_data_t saxattr_support_data[] =
4575 { &CLSID_SAXAttributes, "SAXAttributes" },
4576 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4577 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4578 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4582 static void test_mxattr_localname(void)
4584 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4585 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4586 static const WCHAR uri1W[] = {'u','r','i','1',0};
4587 static const WCHAR uriW[] = {'u','r','i',0};
4589 const struct msxmlsupported_data_t *table = saxattr_support_data;
4591 while (table->clsid)
4593 ISAXAttributes *saxattr;
4594 IMXAttributes *mxattr;
4598 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4604 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4605 &IID_IMXAttributes, (void**)&mxattr);
4606 EXPECT_HR(hr, S_OK);
4608 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4609 EXPECT_HR(hr, S_OK);
4611 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4612 EXPECT_HR(hr, E_INVALIDARG);
4614 /* add some ambiguos attribute names */
4615 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4616 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4617 EXPECT_HR(hr, S_OK);
4618 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4619 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4620 EXPECT_HR(hr, S_OK);
4623 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4624 EXPECT_HR(hr, S_OK);
4625 ok(index == 0, "%s: got index %d\n", table->name, index);
4628 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4629 EXPECT_HR(hr, E_INVALIDARG);
4630 ok(index == -1, "%s: got index %d\n", table->name, index);
4633 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4634 EXPECT_HR(hr, E_INVALIDARG);
4635 ok(index == -1, "%s: got index %d\n", table->name, index);
4637 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4638 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4640 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4641 EXPECT_HR(hr, E_POINTER);
4643 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4644 EXPECT_HR(hr, E_POINTER);
4648 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4649 EXPECT_HR(hr, E_INVALIDARG);
4651 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4652 EXPECT_HR(hr, E_INVALIDARG);
4655 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
4656 EXPECT_HR(hr, E_INVALIDARG);
4658 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
4659 EXPECT_HR(hr, E_INVALIDARG);
4663 ISAXAttributes_Release(saxattr);
4664 IMXAttributes_Release(mxattr);
4668 START_TEST(saxreader)
4670 ISAXXMLReader *reader;
4673 hr = CoInitialize(NULL);
4674 ok(hr == S_OK, "failed to init com\n");
4676 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4677 &IID_ISAXXMLReader, (void**)&reader);
4681 skip("Failed to create SAXXMLReader instance\n");
4685 ISAXXMLReader_Release(reader);
4687 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4689 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
4692 test_saxreader_properties();
4693 test_saxreader_features();
4694 test_saxreader_encoding();
4697 /* MXXMLWriter tests */
4698 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
4699 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
4701 test_mxwriter_handlers();
4702 test_mxwriter_startenddocument();
4703 test_mxwriter_startendelement();
4704 test_mxwriter_characters();
4705 test_mxwriter_comment();
4706 test_mxwriter_cdata();
4708 test_mxwriter_ignorablespaces();
4709 test_mxwriter_dtd();
4710 test_mxwriter_properties();
4711 test_mxwriter_flush();
4712 test_mxwriter_stream();
4713 test_mxwriter_encoding();
4714 test_mxwriter_dispex();
4717 win_skip("MXXMLWriter not supported\n");
4719 /* SAXAttributes tests */
4720 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
4721 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
4724 test_mxattr_addAttribute();
4725 test_mxattr_clear();
4726 test_mxattr_localname();
4727 test_mxattr_dispex();
4730 skip("SAXAttributes not supported\n");