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 "processingInstruction",
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 init_call_entry(locator, &call);
960 call.id = CH_PUTDOCUMENTLOCATOR;
961 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
963 if (msxml_version >= 6) {
964 ISAXAttributes *attr, *attr1;
965 IMXAttributes *mxattr;
967 EXPECT_REF(pLocator, 1);
968 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
970 EXPECT_REF(pLocator, 2);
971 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
973 EXPECT_REF(pLocator, 3);
974 ok(attr == attr1, "got %p, %p\n", attr, attr1);
976 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
977 EXPECT_HR(hr, E_NOINTERFACE);
979 ISAXAttributes_Release(attr);
980 ISAXAttributes_Release(attr1);
983 return get_expected_ret();
986 static ISAXAttributes *test_attr_ptr;
987 static HRESULT WINAPI contentHandler_startDocument(
988 ISAXContentHandler* iface)
990 struct call_entry call;
992 init_call_entry(locator, &call);
993 call.id = CH_STARTDOCUMENT;
994 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
996 test_attr_ptr = NULL;
998 return get_expected_ret();
1001 static HRESULT WINAPI contentHandler_endDocument(
1002 ISAXContentHandler* iface)
1004 struct call_entry call;
1006 init_call_entry(locator, &call);
1007 call.id = CH_ENDDOCUMENT;
1008 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1010 return get_expected_ret();
1013 static HRESULT WINAPI contentHandler_startPrefixMapping(
1014 ISAXContentHandler* iface,
1015 const WCHAR *prefix, int prefix_len,
1016 const WCHAR *uri, int uri_len)
1018 struct call_entry call;
1020 init_call_entry(locator, &call);
1021 call.id = CH_STARTPREFIXMAPPING;
1022 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1023 call.arg2W = SysAllocStringLen(uri, uri_len);
1024 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1026 return get_expected_ret();
1029 static HRESULT WINAPI contentHandler_endPrefixMapping(
1030 ISAXContentHandler* iface,
1031 const WCHAR *prefix, int len)
1033 struct call_entry call;
1035 init_call_entry(locator, &call);
1036 call.id = CH_ENDPREFIXMAPPING;
1037 call.arg1W = SysAllocStringLen(prefix, len);
1038 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1040 return get_expected_ret();
1043 static HRESULT WINAPI contentHandler_startElement(
1044 ISAXContentHandler* iface,
1045 const WCHAR *uri, int uri_len,
1046 const WCHAR *localname, int local_len,
1047 const WCHAR *qname, int qname_len,
1048 ISAXAttributes *saxattr)
1050 struct call_entry call;
1051 IMXAttributes *mxattr;
1055 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1056 EXPECT_HR(hr, E_NOINTERFACE);
1058 init_call_entry(locator, &call);
1059 call.id = CH_STARTELEMENT;
1060 call.arg1W = SysAllocStringLen(uri, uri_len);
1061 call.arg2W = SysAllocStringLen(localname, local_len);
1062 call.arg3W = SysAllocStringLen(qname, qname_len);
1065 test_attr_ptr = saxattr;
1066 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1068 /* store actual attributes */
1070 hr = ISAXAttributes_getLength(saxattr, &len);
1071 EXPECT_HR(hr, S_OK);
1078 struct attribute_entry *attr;
1079 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1082 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1083 EXPECT_HR(hr, S_OK);
1085 for (i = 0; i < len; i++)
1090 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1091 &localname, &local_len, &qname, &qname_len);
1092 EXPECT_HR(hr, S_OK);
1094 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1095 EXPECT_HR(hr, S_OK);
1097 /* if 'namespaces' switched off uri and local name contains garbage */
1098 if (v == VARIANT_FALSE && msxml_version > 0)
1100 attr[i].uriW = SysAllocStringLen(NULL, 0);
1101 attr[i].localW = SysAllocStringLen(NULL, 0);
1105 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1106 attr[i].localW = SysAllocStringLen(localname, local_len);
1109 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1110 attr[i].valueW = SysAllocStringLen(value, value_len);
1113 call.attributes = attr;
1114 call.attr_count = len;
1117 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1119 return get_expected_ret();
1122 static HRESULT WINAPI contentHandler_endElement(
1123 ISAXContentHandler* iface,
1124 const WCHAR *uri, int uri_len,
1125 const WCHAR *localname, int local_len,
1126 const WCHAR *qname, int qname_len)
1128 struct call_entry call;
1130 init_call_entry(locator, &call);
1131 call.id = CH_ENDELEMENT;
1132 call.arg1W = SysAllocStringLen(uri, uri_len);
1133 call.arg2W = SysAllocStringLen(localname, local_len);
1134 call.arg3W = SysAllocStringLen(qname, qname_len);
1135 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1137 return get_expected_ret();
1140 static HRESULT WINAPI contentHandler_characters(
1141 ISAXContentHandler* iface,
1145 struct call_entry call;
1147 init_call_entry(locator, &call);
1148 call.id = CH_CHARACTERS;
1149 call.arg1W = SysAllocStringLen(chars, len);
1150 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1152 return get_expected_ret();
1155 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1156 ISAXContentHandler* iface,
1157 const WCHAR *chars, int len)
1159 struct call_entry call;
1161 init_call_entry(locator, &call);
1162 call.id = CH_IGNORABLEWHITESPACE;
1163 call.arg1W = SysAllocStringLen(chars, len);
1164 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1166 return get_expected_ret();
1169 static HRESULT WINAPI contentHandler_processingInstruction(
1170 ISAXContentHandler* iface,
1171 const WCHAR *target, int target_len,
1172 const WCHAR *data, int data_len)
1174 struct call_entry call;
1176 init_call_entry(locator, &call);
1177 call.id = CH_PROCESSINGINSTRUCTION;
1178 call.arg1W = SysAllocStringLen(target, target_len);
1179 call.arg2W = SysAllocStringLen(data, data_len);
1180 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1182 return get_expected_ret();
1185 static HRESULT WINAPI contentHandler_skippedEntity(
1186 ISAXContentHandler* iface,
1187 const WCHAR *name, int len)
1189 struct call_entry call;
1191 init_call_entry(locator, &call);
1192 call.id = CH_SKIPPEDENTITY;
1193 call.arg1W = SysAllocStringLen(name, len);
1195 return get_expected_ret();
1198 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1200 contentHandler_QueryInterface,
1201 contentHandler_AddRef,
1202 contentHandler_Release,
1203 contentHandler_putDocumentLocator,
1204 contentHandler_startDocument,
1205 contentHandler_endDocument,
1206 contentHandler_startPrefixMapping,
1207 contentHandler_endPrefixMapping,
1208 contentHandler_startElement,
1209 contentHandler_endElement,
1210 contentHandler_characters,
1211 contentHandler_ignorableWhitespace,
1212 contentHandler_processingInstruction,
1213 contentHandler_skippedEntity
1216 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1218 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1219 ISAXErrorHandler* iface,
1225 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1231 return E_NOINTERFACE;
1237 static ULONG WINAPI isaxerrorHandler_AddRef(
1238 ISAXErrorHandler* iface)
1243 static ULONG WINAPI isaxerrorHandler_Release(
1244 ISAXErrorHandler* iface)
1249 static HRESULT WINAPI isaxerrorHandler_error(
1250 ISAXErrorHandler* iface,
1251 ISAXLocator *pLocator,
1252 const WCHAR *pErrorMessage,
1253 HRESULT hrErrorCode)
1255 ok(0, "unexpected call\n");
1259 static HRESULT WINAPI isaxerrorHandler_fatalError(
1260 ISAXErrorHandler* iface,
1261 ISAXLocator *pLocator,
1262 const WCHAR *message,
1265 struct call_entry call;
1267 init_call_entry(locator, &call);
1268 call.id = EH_FATALERROR;
1271 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1277 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1278 ISAXErrorHandler* iface,
1279 ISAXLocator *pLocator,
1280 const WCHAR *pErrorMessage,
1281 HRESULT hrErrorCode)
1283 ok(0, "unexpected call\n");
1287 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1289 isaxerrorHandler_QueryInterface,
1290 isaxerrorHandler_AddRef,
1291 isaxerrorHandler_Release,
1292 isaxerrorHandler_error,
1293 isaxerrorHandler_fatalError,
1294 isaxerrorHanddler_ignorableWarning
1297 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1299 static HRESULT WINAPI isaxattributes_QueryInterface(
1300 ISAXAttributes* iface,
1306 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1312 return E_NOINTERFACE;
1318 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1323 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1328 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1334 static HRESULT WINAPI isaxattributes_getURI(
1335 ISAXAttributes* iface,
1340 ok(0, "unexpected call\n");
1344 static HRESULT WINAPI isaxattributes_getLocalName(
1345 ISAXAttributes* iface,
1347 const WCHAR **pLocalName,
1348 int *pLocalNameLength)
1350 ok(0, "unexpected call\n");
1354 static HRESULT WINAPI isaxattributes_getQName(
1355 ISAXAttributes* iface,
1357 const WCHAR **QName,
1360 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1361 {'a','t','t','r','2','j','u','n','k',0},
1362 {'a','t','t','r','3',0}};
1363 static const int attrqnamelen[] = {7, 5, 5};
1365 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1367 *QName = attrqnamesW[index];
1368 *QNameLength = attrqnamelen[index];
1373 static HRESULT WINAPI isaxattributes_getName(
1374 ISAXAttributes* iface,
1378 const WCHAR ** pLocalName,
1379 int * pLocalNameSize,
1380 const WCHAR ** pQName,
1383 ok(0, "unexpected call\n");
1387 static HRESULT WINAPI isaxattributes_getIndexFromName(
1388 ISAXAttributes* iface,
1391 const WCHAR * pLocalName,
1392 int cocalNameLength,
1395 ok(0, "unexpected call\n");
1399 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1400 ISAXAttributes* iface,
1401 const WCHAR * pQName,
1405 ok(0, "unexpected call\n");
1409 static HRESULT WINAPI isaxattributes_getType(
1410 ISAXAttributes* iface,
1412 const WCHAR ** pType,
1415 ok(0, "unexpected call\n");
1419 static HRESULT WINAPI isaxattributes_getTypeFromName(
1420 ISAXAttributes* iface,
1423 const WCHAR * pLocalName,
1425 const WCHAR ** pType,
1428 ok(0, "unexpected call\n");
1432 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1433 ISAXAttributes* iface,
1434 const WCHAR * pQName,
1436 const WCHAR ** pType,
1439 ok(0, "unexpected call\n");
1443 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1444 const WCHAR **value, int *nValue)
1446 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1447 {'a','2','j','u','n','k',0},
1448 {'<','&','"','>',0}};
1449 static const int attrvalueslen[] = {2, 2, 4};
1451 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1453 *value = attrvaluesW[index];
1454 *nValue = attrvalueslen[index];
1459 static HRESULT WINAPI isaxattributes_getValueFromName(
1460 ISAXAttributes* iface,
1463 const WCHAR * pLocalName,
1465 const WCHAR ** pValue,
1468 ok(0, "unexpected call\n");
1472 static HRESULT WINAPI isaxattributes_getValueFromQName(
1473 ISAXAttributes* iface,
1474 const WCHAR * pQName,
1476 const WCHAR ** pValue,
1479 ok(0, "unexpected call\n");
1483 static const ISAXAttributesVtbl SAXAttributesVtbl =
1485 isaxattributes_QueryInterface,
1486 isaxattributes_AddRef,
1487 isaxattributes_Release,
1488 isaxattributes_getLength,
1489 isaxattributes_getURI,
1490 isaxattributes_getLocalName,
1491 isaxattributes_getQName,
1492 isaxattributes_getName,
1493 isaxattributes_getIndexFromName,
1494 isaxattributes_getIndexFromQName,
1495 isaxattributes_getType,
1496 isaxattributes_getTypeFromName,
1497 isaxattributes_getTypeFromQName,
1498 isaxattributes_getValue,
1499 isaxattributes_getValueFromName,
1500 isaxattributes_getValueFromQName
1503 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1505 struct saxlexicalhandler
1507 ISAXLexicalHandler ISAXLexicalHandler_iface;
1510 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1513 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1515 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1518 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1520 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1524 if (IsEqualGUID(riid, &IID_IUnknown))
1527 ok(0, "got unexpected IID_IUnknown query\n");
1529 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1531 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1536 ISAXLexicalHandler_AddRef(iface);
1538 return E_NOINTERFACE;
1543 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1545 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1546 return InterlockedIncrement(&handler->ref);
1549 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1551 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1552 return InterlockedDecrement(&handler->ref);
1555 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1556 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1557 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1559 ok(0, "call not expected\n");
1563 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1565 ok(0, "call not expected\n");
1569 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1570 const WCHAR * pName, int nName)
1572 ok(0, "call not expected\n");
1576 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1577 const WCHAR * pName, int nName)
1579 ok(0, "call not expected\n");
1583 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1585 ok(0, "call not expected\n");
1589 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1591 ok(0, "call not expected\n");
1595 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1596 const WCHAR * pChars, int nChars)
1598 ok(0, "call not expected\n");
1602 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1604 isaxlexical_QueryInterface,
1606 isaxlexical_Release,
1607 isaxlexical_startDTD,
1609 isaxlexical_startEntity,
1610 isaxlexical_endEntity,
1611 isaxlexical_startCDATA,
1612 isaxlexical_endCDATA,
1616 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1618 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1620 handler->qi_hr = hr;
1623 struct saxdeclhandler
1625 ISAXDeclHandler ISAXDeclHandler_iface;
1628 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1631 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1633 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1636 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1638 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1642 if (IsEqualGUID(riid, &IID_IUnknown))
1645 ok(0, "got unexpected IID_IUnknown query\n");
1647 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1649 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1654 ISAXDeclHandler_AddRef(iface);
1656 return E_NOINTERFACE;
1661 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1663 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1664 return InterlockedIncrement(&handler->ref);
1667 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1669 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1670 return InterlockedDecrement(&handler->ref);
1673 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1674 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1676 ok(0, "call not expected\n");
1680 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1681 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1682 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1683 int nValueDefault, const WCHAR * pValue, int nValue)
1685 ok(0, "call not expected\n");
1689 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1690 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1692 ok(0, "call not expected\n");
1696 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1697 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1698 const WCHAR * pSystemId, int nSystemId)
1700 ok(0, "call not expected\n");
1704 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1706 isaxdecl_QueryInterface,
1709 isaxdecl_elementDecl,
1710 isaxdecl_attributeDecl,
1711 isaxdecl_internalEntityDecl,
1712 isaxdecl_externalEntityDecl
1715 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1717 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1719 handler->qi_hr = hr;
1722 typedef struct mxwriter_write_test_t {
1728 } mxwriter_write_test;
1730 typedef struct mxwriter_stream_test_t {
1732 const char *encoding;
1733 mxwriter_write_test expected_writes[4];
1734 } mxwriter_stream_test;
1736 static const mxwriter_write_test *current_write_test;
1737 static DWORD current_stream_test_index;
1739 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1743 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1746 return E_NOINTERFACE;
1751 static ULONG WINAPI istream_AddRef(IStream *iface)
1756 static ULONG WINAPI istream_Release(IStream *iface)
1761 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1763 ok(0, "unexpected call\n");
1767 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1771 ok(pv != NULL, "pv == NULL\n");
1773 if(current_write_test->last) {
1774 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1778 fail = current_write_test->fail_write;
1780 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1781 current_write_test->cb, cb, current_stream_test_index);
1784 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1786 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1788 ++current_write_test;
1793 return fail ? E_FAIL : S_OK;
1796 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1797 ULARGE_INTEGER *plibNewPosition)
1799 ok(0, "unexpected call\n");
1803 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1805 ok(0, "unexpected call\n");
1809 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1810 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1812 ok(0, "unexpected call\n");
1816 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1818 ok(0, "unexpected call\n");
1822 static HRESULT WINAPI istream_Revert(IStream *iface)
1824 ok(0, "unexpected call\n");
1828 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1829 ULARGE_INTEGER cb, DWORD dwLockType)
1831 ok(0, "unexpected call\n");
1835 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1836 ULARGE_INTEGER cb, DWORD dwLockType)
1838 ok(0, "unexpected call\n");
1842 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1844 ok(0, "unexpected call\n");
1848 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1850 ok(0, "unexpected call\n");
1854 static const IStreamVtbl StreamVtbl = {
1855 istream_QueryInterface,
1866 istream_UnlockRegion,
1871 static IStream mxstream = { &StreamVtbl };
1873 static struct msxmlsupported_data_t reader_support_data[] =
1875 { &CLSID_SAXXMLReader, "SAXReader" },
1876 { &CLSID_SAXXMLReader30, "SAXReader30" },
1877 { &CLSID_SAXXMLReader40, "SAXReader40" },
1878 { &CLSID_SAXXMLReader60, "SAXReader60" },
1882 static void test_saxreader(void)
1884 const struct msxmlsupported_data_t *table = reader_support_data;
1886 ISAXXMLReader *reader = NULL;
1888 ISAXContentHandler *content;
1889 ISAXErrorHandler *lpErrorHandler;
1891 SAFEARRAYBOUND SADim[1];
1894 ULARGE_INTEGER size;
1898 static const CHAR testXmlA[] = "test.xml";
1899 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1900 IXMLDOMDocument *doc;
1903 while (table->clsid)
1905 struct call_entry *test_seq;
1908 if (!is_clsid_supported(table->clsid, reader_support_data))
1914 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1915 EXPECT_HR(hr, S_OK);
1918 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1920 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1925 /* crashes on old versions */
1926 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1927 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1929 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1930 EXPECT_HR(hr, E_POINTER);
1932 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1933 EXPECT_HR(hr, E_POINTER);
1936 hr = ISAXXMLReader_getContentHandler(reader, &content);
1937 EXPECT_HR(hr, S_OK);
1938 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1940 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1941 EXPECT_HR(hr, S_OK);
1942 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1944 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1945 EXPECT_HR(hr, S_OK);
1947 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1948 EXPECT_HR(hr, S_OK);
1950 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1951 EXPECT_HR(hr, S_OK);
1953 hr = ISAXXMLReader_getContentHandler(reader, &content);
1954 EXPECT_HR(hr, S_OK);
1955 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1957 V_VT(&var) = VT_BSTR;
1958 V_BSTR(&var) = SysAllocString(szSimpleXML);
1960 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1961 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1962 test_seq = content_handler_test1_alternate;
1964 test_seq = content_handler_test1;
1965 set_expected_seq(test_seq);
1966 hr = ISAXXMLReader_parse(reader, var);
1967 EXPECT_HR(hr, S_OK);
1968 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1972 SADim[0].lLbound = 0;
1973 SADim[0].cElements = sizeof(testXML)-1;
1974 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1975 SafeArrayAccessData(sa, (void**)&ptr);
1976 memcpy(ptr, testXML, sizeof(testXML)-1);
1977 SafeArrayUnaccessData(sa);
1978 V_VT(&var) = VT_ARRAY|VT_UI1;
1981 set_expected_seq(test_seq);
1982 hr = ISAXXMLReader_parse(reader, var);
1983 EXPECT_HR(hr, S_OK);
1984 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1986 SafeArrayDestroy(sa);
1988 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1989 size.QuadPart = strlen(testXML);
1990 IStream_SetSize(stream, size);
1991 IStream_Write(stream, testXML, strlen(testXML), &written);
1993 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1994 V_VT(&var) = VT_UNKNOWN;
1995 V_UNKNOWN(&var) = (IUnknown*)stream;
1997 set_expected_seq(test_seq);
1998 hr = ISAXXMLReader_parse(reader, var);
1999 EXPECT_HR(hr, S_OK);
2000 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2002 IStream_Release(stream);
2004 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2005 size.QuadPart = strlen(test_attributes);
2006 IStream_SetSize(stream, size);
2007 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2009 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2010 V_VT(&var) = VT_UNKNOWN;
2011 V_UNKNOWN(&var) = (IUnknown*)stream;
2013 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2014 test_seq = content_handler_test_attributes_alternate_4;
2015 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2016 test_seq = content_handler_test_attributes_alternate_6;
2018 test_seq = content_handler_test_attributes;
2020 set_expected_seq(test_seq);
2021 hr = ISAXXMLReader_parse(reader, var);
2022 EXPECT_HR(hr, S_OK);
2024 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2025 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2026 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2028 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2030 IStream_Release(stream);
2032 V_VT(&var) = VT_BSTR;
2033 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2035 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2036 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2037 test_seq = content_handler_test2_alternate;
2039 test_seq = content_handler_test2;
2041 set_expected_seq(test_seq);
2042 hr = ISAXXMLReader_parse(reader, var);
2043 EXPECT_HR(hr, S_OK);
2044 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2049 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2050 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2051 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2054 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2055 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2056 test_seq = content_handler_test1_alternate;
2058 test_seq = content_handler_test1;
2059 set_expected_seq(test_seq);
2060 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2061 EXPECT_HR(hr, S_OK);
2062 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2065 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2066 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2067 test_seq = content_handler_testerror_alternate;
2069 test_seq = content_handler_testerror;
2070 set_expected_seq(test_seq);
2071 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2072 EXPECT_HR(hr, E_FAIL);
2073 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2075 /* callback ret values */
2076 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2077 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2079 test_seq = content_handler_test_callback_rets_alt;
2080 set_expected_seq(test_seq);
2081 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2082 EXPECT_HR(hr, S_OK);
2086 test_seq = content_handler_test_callback_rets;
2087 set_expected_seq(test_seq);
2088 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2089 EXPECT_HR(hr, S_FALSE);
2091 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2093 DeleteFileA(testXmlA);
2095 /* parse from IXMLDOMDocument */
2096 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2097 &IID_IXMLDOMDocument, (void**)&doc);
2098 EXPECT_HR(hr, S_OK);
2100 str = SysAllocString(szSimpleXML);
2101 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2102 EXPECT_HR(hr, S_OK);
2105 V_VT(&var) = VT_UNKNOWN;
2106 V_UNKNOWN(&var) = (IUnknown*)doc;
2108 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2109 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2110 test_seq = content_handler_test2_alternate;
2112 test_seq = content_handler_test2;
2114 set_expected_seq(test_seq);
2115 hr = ISAXXMLReader_parse(reader, var);
2116 EXPECT_HR(hr, S_OK);
2117 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2118 IXMLDOMDocument_Release(doc);
2120 /* xml:space test */
2121 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2122 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2124 test_seq = xmlspaceattr_test_alternate;
2127 test_seq = xmlspaceattr_test;
2129 set_expected_seq(test_seq);
2130 V_VT(&var) = VT_BSTR;
2131 V_BSTR(&var) = _bstr_(xmlspace_attr);
2132 hr = ISAXXMLReader_parse(reader, var);
2133 EXPECT_HR(hr, S_OK);
2135 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2136 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2138 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2141 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2143 /* switch off 'namespaces' feature */
2144 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2145 EXPECT_HR(hr, S_OK);
2147 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2148 size.QuadPart = strlen(test_attributes);
2149 IStream_SetSize(stream, size);
2150 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2152 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2153 V_VT(&var) = VT_UNKNOWN;
2154 V_UNKNOWN(&var) = (IUnknown*)stream;
2156 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2157 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2159 test_seq = content_handler_test_attributes_alt_no_ns;
2162 test_seq = content_handler_test_attributes;
2164 set_expected_seq(test_seq);
2165 hr = ISAXXMLReader_parse(reader, var);
2166 EXPECT_HR(hr, S_OK);
2167 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2168 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2169 EXPECT_HR(hr, S_OK);
2171 /* switch off 'namespace-prefixes' feature */
2172 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2173 EXPECT_HR(hr, S_OK);
2175 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2176 size.QuadPart = strlen(test_attributes);
2177 IStream_SetSize(stream, size);
2178 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2180 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2181 V_VT(&var) = VT_UNKNOWN;
2182 V_UNKNOWN(&var) = (IUnknown*)stream;
2184 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2185 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2187 test_seq = content_handler_test_attributes_alt_no_prefix;
2190 test_seq = content_handler_test_attributes_no_prefix;
2192 set_expected_seq(test_seq);
2193 hr = ISAXXMLReader_parse(reader, var);
2194 EXPECT_HR(hr, S_OK);
2195 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2197 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2198 EXPECT_HR(hr, S_OK);
2200 /* attribute normalization */
2201 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2202 size.QuadPart = strlen(attribute_normalize);
2203 IStream_SetSize(stream, size);
2204 IStream_Write(stream, attribute_normalize, strlen(attribute_normalize), &written);
2206 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2207 V_VT(&var) = VT_UNKNOWN;
2208 V_UNKNOWN(&var) = (IUnknown*)stream;
2210 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2211 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2213 test_seq = attribute_norm_alt;
2216 test_seq = attribute_norm;
2218 set_expected_seq(test_seq);
2219 hr = ISAXXMLReader_parse(reader, var);
2220 EXPECT_HR(hr, S_OK);
2221 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2223 ISAXXMLReader_Release(reader);
2230 struct saxreader_props_test_t
2232 const char *prop_name;
2236 static struct saxlexicalhandler lexicalhandler;
2237 static struct saxdeclhandler declhandler;
2239 static const struct saxreader_props_test_t props_test_data[] = {
2240 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2241 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2245 static void test_saxreader_properties(void)
2247 const struct saxreader_props_test_t *ptr = props_test_data;
2248 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)
2263 init_saxlexicalhandler(&lexicalhandler, S_OK);
2264 init_saxdeclhandler(&declhandler, S_OK);
2266 V_VT(&v) = VT_EMPTY;
2267 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2268 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2269 EXPECT_HR(hr, S_OK);
2270 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2271 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2273 V_VT(&v) = VT_UNKNOWN;
2274 V_UNKNOWN(&v) = ptr->iface;
2275 ref = get_refcount(ptr->iface);
2276 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2277 EXPECT_HR(hr, S_OK);
2278 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2280 V_VT(&v) = VT_EMPTY;
2281 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2283 ref = get_refcount(ptr->iface);
2284 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2285 EXPECT_HR(hr, S_OK);
2286 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2287 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2288 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2291 V_VT(&v) = VT_EMPTY;
2292 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2293 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2294 EXPECT_HR(hr, S_OK);
2296 V_VT(&v) = VT_EMPTY;
2297 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2298 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2299 EXPECT_HR(hr, S_OK);
2300 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2301 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2303 V_VT(&v) = VT_UNKNOWN;
2304 V_UNKNOWN(&v) = ptr->iface;
2305 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2306 EXPECT_HR(hr, S_OK);
2308 /* only VT_EMPTY seems to be valid to reset property */
2310 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2311 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2312 EXPECT_HR(hr, E_INVALIDARG);
2314 V_VT(&v) = VT_EMPTY;
2315 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2316 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2317 EXPECT_HR(hr, S_OK);
2318 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2319 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2322 V_VT(&v) = VT_UNKNOWN;
2323 V_UNKNOWN(&v) = NULL;
2324 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2325 EXPECT_HR(hr, S_OK);
2327 V_VT(&v) = VT_EMPTY;
2328 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2329 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2330 EXPECT_HR(hr, S_OK);
2331 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2332 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2334 /* block QueryInterface on handler riid */
2335 V_VT(&v) = VT_UNKNOWN;
2336 V_UNKNOWN(&v) = ptr->iface;
2337 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2338 EXPECT_HR(hr, S_OK);
2340 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2341 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2343 V_VT(&v) = VT_UNKNOWN;
2344 V_UNKNOWN(&v) = ptr->iface;
2345 EXPECT_REF(ptr->iface, 1);
2346 ref = get_refcount(ptr->iface);
2347 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2348 EXPECT_HR(hr, E_NOINTERFACE);
2349 EXPECT_REF(ptr->iface, 1);
2351 V_VT(&v) = VT_EMPTY;
2352 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2353 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2354 EXPECT_HR(hr, S_OK);
2355 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2356 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2362 ISAXXMLReader_Release(reader);
2364 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2367 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2368 &IID_ISAXXMLReader, (void**)&reader);
2369 EXPECT_HR(hr, S_OK);
2371 /* xmldecl-version property */
2372 V_VT(&v) = VT_EMPTY;
2373 V_BSTR(&v) = (void*)0xdeadbeef;
2374 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2375 EXPECT_HR(hr, S_OK);
2376 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2377 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2379 /* stream without declaration */
2381 V_BSTR(&v) = _bstr_("<element></element>");
2382 hr = ISAXXMLReader_parse(reader, v);
2383 EXPECT_HR(hr, S_OK);
2385 V_VT(&v) = VT_EMPTY;
2386 V_BSTR(&v) = (void*)0xdeadbeef;
2387 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2388 EXPECT_HR(hr, S_OK);
2389 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2390 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2392 /* stream with declaration */
2394 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2395 hr = ISAXXMLReader_parse(reader, v);
2396 EXPECT_HR(hr, S_OK);
2398 V_VT(&v) = VT_EMPTY;
2399 V_BSTR(&v) = (void*)0xdeadbeef;
2400 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2401 EXPECT_HR(hr, S_OK);
2402 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2403 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2406 ISAXXMLReader_Release(reader);
2410 struct feature_ns_entry_t {
2414 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2417 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2418 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2419 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2420 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2421 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2425 static const char *feature_names[] = {
2426 "http://xml.org/sax/features/namespaces",
2427 "http://xml.org/sax/features/namespace-prefixes",
2431 static void test_saxreader_features(void)
2433 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2434 ISAXXMLReader *reader;
2442 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2445 win_skip("can't create %s instance\n", entry->clsid);
2450 name = feature_names;
2454 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2455 EXPECT_HR(hr, S_OK);
2456 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2459 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2460 EXPECT_HR(hr, S_OK);
2463 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2464 EXPECT_HR(hr, S_OK);
2465 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2467 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2468 EXPECT_HR(hr, S_OK);
2470 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2471 EXPECT_HR(hr, S_OK);
2472 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2474 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2475 EXPECT_HR(hr, S_OK);
2477 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2478 EXPECT_HR(hr, S_OK);
2479 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2484 ISAXXMLReader_Release(reader);
2490 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2491 static const CHAR UTF8BOMTest[] =
2492 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2495 struct enc_test_entry_t {
2503 static const struct enc_test_entry_t encoding_test_data[] = {
2504 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2505 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2506 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2507 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2511 static void test_saxreader_encoding(void)
2513 const struct enc_test_entry_t *entry = encoding_test_data;
2514 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2515 static const CHAR testXmlA[] = "test.xml";
2519 ISAXXMLReader *reader;
2525 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2528 win_skip("can't create %s instance\n", entry->clsid);
2533 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2534 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2535 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2538 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2540 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2542 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2544 DeleteFileA(testXmlA);
2546 /* try BSTR input with no BOM or '<?xml' instruction */
2547 V_VT(&input) = VT_BSTR;
2548 V_BSTR(&input) = _bstr_("<element></element>");
2549 hr = ISAXXMLReader_parse(reader, input);
2550 EXPECT_HR(hr, S_OK);
2552 ISAXXMLReader_Release(reader);
2559 static void test_mxwriter_handlers(void)
2561 ISAXContentHandler *handler;
2562 IMXWriter *writer, *writer2;
2563 ISAXDeclHandler *decl;
2564 ISAXLexicalHandler *lh;
2567 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2568 &IID_IMXWriter, (void**)&writer);
2569 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2571 EXPECT_REF(writer, 1);
2573 /* ISAXContentHandler */
2574 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2575 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2576 EXPECT_REF(writer, 2);
2577 EXPECT_REF(handler, 2);
2579 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2580 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2581 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2582 EXPECT_REF(writer, 3);
2583 EXPECT_REF(writer2, 3);
2584 IMXWriter_Release(writer2);
2585 ISAXContentHandler_Release(handler);
2587 /* ISAXLexicalHandler */
2588 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2589 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2590 EXPECT_REF(writer, 2);
2593 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2594 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2595 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2596 EXPECT_REF(writer, 3);
2597 EXPECT_REF(writer2, 3);
2598 IMXWriter_Release(writer2);
2599 ISAXLexicalHandler_Release(lh);
2601 /* ISAXDeclHandler */
2602 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2603 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2604 EXPECT_REF(writer, 2);
2607 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2608 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2609 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2610 EXPECT_REF(writer, 3);
2611 EXPECT_REF(writer2, 3);
2612 IMXWriter_Release(writer2);
2613 ISAXDeclHandler_Release(decl);
2615 IMXWriter_Release(writer);
2619 static struct msxmlsupported_data_t mxwriter_support_data[] =
2621 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2622 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2623 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2624 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2628 static struct msxmlsupported_data_t mxattributes_support_data[] =
2630 { &CLSID_SAXAttributes, "SAXAttributes" },
2631 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2632 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2633 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2637 struct mxwriter_props_t
2641 VARIANT_BOOL disable_escape;
2642 VARIANT_BOOL indent;
2643 VARIANT_BOOL omitdecl;
2644 VARIANT_BOOL standalone;
2645 const char *encoding;
2648 static const struct mxwriter_props_t mxwriter_default_props[] =
2650 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2651 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2652 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2653 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2657 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2661 while (table->clsid)
2668 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2675 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2676 &IID_IMXWriter, (void**)&writer);
2677 EXPECT_HR(hr, S_OK);
2680 hr = IMXWriter_get_byteOrderMark(writer, &b);
2681 EXPECT_HR(hr, S_OK);
2682 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2684 b = !table->disable_escape;
2685 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2686 EXPECT_HR(hr, S_OK);
2687 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2688 table->disable_escape);
2691 hr = IMXWriter_get_indent(writer, &b);
2692 EXPECT_HR(hr, S_OK);
2693 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2695 b = !table->omitdecl;
2696 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2697 EXPECT_HR(hr, S_OK);
2698 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2700 b = !table->standalone;
2701 hr = IMXWriter_get_standalone(writer, &b);
2702 EXPECT_HR(hr, S_OK);
2703 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2705 hr = IMXWriter_get_encoding(writer, &encoding);
2706 EXPECT_HR(hr, S_OK);
2707 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2708 i, wine_dbgstr_w(encoding), table->encoding);
2709 SysFreeString(encoding);
2711 IMXWriter_Release(writer);
2718 static void test_mxwriter_properties(void)
2720 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2721 static const WCHAR emptyW[] = {0};
2722 static const WCHAR testW[] = {'t','e','s','t',0};
2723 ISAXContentHandler *content;
2730 test_mxwriter_default_properties(mxwriter_default_props);
2732 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2733 &IID_IMXWriter, (void**)&writer);
2734 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2736 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2737 ok(hr == E_POINTER, "got %08x\n", hr);
2739 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2740 ok(hr == E_POINTER, "got %08x\n", hr);
2742 hr = IMXWriter_get_indent(writer, NULL);
2743 ok(hr == E_POINTER, "got %08x\n", hr);
2745 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2746 ok(hr == E_POINTER, "got %08x\n", hr);
2748 hr = IMXWriter_get_standalone(writer, NULL);
2749 ok(hr == E_POINTER, "got %08x\n", hr);
2752 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2753 ok(hr == S_OK, "got %08x\n", hr);
2756 hr = IMXWriter_get_standalone(writer, &b);
2757 ok(hr == S_OK, "got %08x\n", hr);
2758 ok(b == VARIANT_TRUE, "got %d\n", b);
2760 hr = IMXWriter_get_encoding(writer, NULL);
2761 EXPECT_HR(hr, E_POINTER);
2763 /* UTF-16 is a default setting apparently */
2764 str = (void*)0xdeadbeef;
2765 hr = IMXWriter_get_encoding(writer, &str);
2766 EXPECT_HR(hr, S_OK);
2767 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2769 str2 = (void*)0xdeadbeef;
2770 hr = IMXWriter_get_encoding(writer, &str2);
2771 ok(hr == S_OK, "got %08x\n", hr);
2772 ok(str != str2, "expected newly allocated, got same %p\n", str);
2774 SysFreeString(str2);
2777 /* put empty string */
2778 str = SysAllocString(emptyW);
2779 hr = IMXWriter_put_encoding(writer, str);
2780 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2783 str = (void*)0xdeadbeef;
2784 hr = IMXWriter_get_encoding(writer, &str);
2785 EXPECT_HR(hr, S_OK);
2786 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2789 /* invalid encoding name */
2790 str = SysAllocString(testW);
2791 hr = IMXWriter_put_encoding(writer, str);
2792 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2795 /* test case sensivity */
2796 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2797 EXPECT_HR(hr, S_OK);
2798 str = (void*)0xdeadbeef;
2799 hr = IMXWriter_get_encoding(writer, &str);
2800 EXPECT_HR(hr, S_OK);
2801 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2804 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2805 EXPECT_HR(hr, S_OK);
2806 str = (void*)0xdeadbeef;
2807 hr = IMXWriter_get_encoding(writer, &str);
2808 EXPECT_HR(hr, S_OK);
2809 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2812 /* how it affects document creation */
2813 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2814 EXPECT_HR(hr, S_OK);
2816 hr = ISAXContentHandler_startDocument(content);
2817 EXPECT_HR(hr, S_OK);
2818 hr = ISAXContentHandler_endDocument(content);
2819 EXPECT_HR(hr, S_OK);
2821 V_VT(&dest) = VT_EMPTY;
2822 hr = IMXWriter_get_output(writer, &dest);
2823 EXPECT_HR(hr, S_OK);
2824 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2825 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2826 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2827 VariantClear(&dest);
2828 ISAXContentHandler_Release(content);
2830 hr = IMXWriter_get_version(writer, NULL);
2831 ok(hr == E_POINTER, "got %08x\n", hr);
2832 /* default version is 'surprisingly' 1.0 */
2833 hr = IMXWriter_get_version(writer, &str);
2834 ok(hr == S_OK, "got %08x\n", hr);
2835 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2838 /* store version string as is */
2839 hr = IMXWriter_put_version(writer, NULL);
2840 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2842 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2843 ok(hr == S_OK, "got %08x\n", hr);
2845 hr = IMXWriter_put_version(writer, _bstr_(""));
2846 ok(hr == S_OK, "got %08x\n", hr);
2847 hr = IMXWriter_get_version(writer, &str);
2848 ok(hr == S_OK, "got %08x\n", hr);
2849 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2852 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2853 ok(hr == S_OK, "got %08x\n", hr);
2854 hr = IMXWriter_get_version(writer, &str);
2855 ok(hr == S_OK, "got %08x\n", hr);
2856 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2859 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2860 ok(hr == S_OK, "got %08x\n", hr);
2861 hr = IMXWriter_get_version(writer, &str);
2862 ok(hr == S_OK, "got %08x\n", hr);
2863 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2866 IMXWriter_Release(writer);
2870 static void test_mxwriter_flush(void)
2872 static const WCHAR emptyW[] = {0};
2873 ISAXContentHandler *content;
2876 ULARGE_INTEGER pos2;
2884 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2885 &IID_IMXWriter, (void**)&writer);
2886 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2888 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2889 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2890 EXPECT_REF(stream, 1);
2892 /* detach when nothing was attached */
2893 V_VT(&dest) = VT_EMPTY;
2894 hr = IMXWriter_put_output(writer, dest);
2895 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2898 V_VT(&dest) = VT_UNKNOWN;
2899 V_UNKNOWN(&dest) = (IUnknown*)stream;
2900 hr = IMXWriter_put_output(writer, dest);
2901 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2902 todo_wine EXPECT_REF(stream, 3);
2904 /* detach setting VT_EMPTY destination */
2905 V_VT(&dest) = VT_EMPTY;
2906 hr = IMXWriter_put_output(writer, dest);
2907 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2908 EXPECT_REF(stream, 1);
2910 V_VT(&dest) = VT_UNKNOWN;
2911 V_UNKNOWN(&dest) = (IUnknown*)stream;
2912 hr = IMXWriter_put_output(writer, dest);
2913 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2915 /* flush() doesn't detach a stream */
2916 hr = IMXWriter_flush(writer);
2917 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2918 todo_wine EXPECT_REF(stream, 3);
2921 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2922 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2923 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2925 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2926 ok(hr == S_OK, "got %08x\n", hr);
2928 hr = ISAXContentHandler_startDocument(content);
2929 ok(hr == S_OK, "got %08x\n", hr);
2932 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2933 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2934 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2936 /* already started */
2937 hr = ISAXContentHandler_startDocument(content);
2938 ok(hr == S_OK, "got %08x\n", hr);
2940 hr = ISAXContentHandler_endDocument(content);
2941 ok(hr == S_OK, "got %08x\n", hr);
2943 /* flushed on endDocument() */
2945 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2946 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2947 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2949 IStream_Release(stream);
2951 /* auto-flush feature */
2952 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2953 EXPECT_HR(hr, S_OK);
2954 EXPECT_REF(stream, 1);
2956 V_VT(&dest) = VT_UNKNOWN;
2957 V_UNKNOWN(&dest) = (IUnknown*)stream;
2958 hr = IMXWriter_put_output(writer, dest);
2959 EXPECT_HR(hr, S_OK);
2961 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
2962 EXPECT_HR(hr, S_OK);
2964 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2965 EXPECT_HR(hr, S_OK);
2967 hr = ISAXContentHandler_startDocument(content);
2968 EXPECT_HR(hr, S_OK);
2970 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
2971 EXPECT_HR(hr, S_OK);
2973 /* internal buffer is flushed automatically on certain threshold */
2976 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2977 EXPECT_HR(hr, S_OK);
2978 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2981 buff = HeapAlloc(GetProcessHeap(), 0, len);
2982 memset(buff, 'A', len);
2983 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
2984 EXPECT_HR(hr, S_OK);
2988 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2989 EXPECT_HR(hr, S_OK);
2991 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
2993 hr = IMXWriter_get_output(writer, NULL);
2994 EXPECT_HR(hr, E_POINTER);
2996 ref = get_refcount(stream);
2997 V_VT(&dest) = VT_EMPTY;
2998 hr = IMXWriter_get_output(writer, &dest);
2999 EXPECT_HR(hr, S_OK);
3000 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3001 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3002 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3003 VariantClear(&dest);
3005 hr = ISAXContentHandler_endDocument(content);
3006 EXPECT_HR(hr, S_OK);
3008 IStream_Release(stream);
3010 /* test char count lower than threshold */
3011 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3012 EXPECT_HR(hr, S_OK);
3013 EXPECT_REF(stream, 1);
3015 hr = ISAXContentHandler_startDocument(content);
3016 EXPECT_HR(hr, S_OK);
3018 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3019 EXPECT_HR(hr, S_OK);
3023 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3024 EXPECT_HR(hr, S_OK);
3025 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3027 memset(buff, 'A', len);
3028 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3029 EXPECT_HR(hr, S_OK);
3033 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3034 EXPECT_HR(hr, S_OK);
3035 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3037 hr = ISAXContentHandler_endDocument(content);
3038 EXPECT_HR(hr, S_OK);
3040 /* test auto-flush function when stream is not set */
3041 V_VT(&dest) = VT_EMPTY;
3042 hr = IMXWriter_put_output(writer, dest);
3043 EXPECT_HR(hr, S_OK);
3045 hr = ISAXContentHandler_startDocument(content);
3046 EXPECT_HR(hr, S_OK);
3048 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3049 EXPECT_HR(hr, S_OK);
3051 memset(buff, 'A', len);
3052 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3053 EXPECT_HR(hr, S_OK);
3055 V_VT(&dest) = VT_EMPTY;
3056 hr = IMXWriter_get_output(writer, &dest);
3057 EXPECT_HR(hr, S_OK);
3058 len += strlen("<a>");
3059 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3060 VariantClear(&dest);
3062 HeapFree(GetProcessHeap(), 0, buff);
3063 ISAXContentHandler_Release(content);
3064 IStream_Release(stream);
3065 IMXWriter_Release(writer);
3069 static void test_mxwriter_startenddocument(void)
3071 ISAXContentHandler *content;
3076 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3077 &IID_IMXWriter, (void**)&writer);
3078 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3080 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3081 ok(hr == S_OK, "got %08x\n", hr);
3083 hr = ISAXContentHandler_startDocument(content);
3084 ok(hr == S_OK, "got %08x\n", hr);
3086 hr = ISAXContentHandler_endDocument(content);
3087 ok(hr == S_OK, "got %08x\n", hr);
3089 V_VT(&dest) = VT_EMPTY;
3090 hr = IMXWriter_get_output(writer, &dest);
3091 ok(hr == S_OK, "got %08x\n", hr);
3092 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3093 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3094 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3095 VariantClear(&dest);
3097 /* now try another startDocument */
3098 hr = ISAXContentHandler_startDocument(content);
3099 ok(hr == S_OK, "got %08x\n", hr);
3100 /* and get duplicated prolog */
3101 V_VT(&dest) = VT_EMPTY;
3102 hr = IMXWriter_get_output(writer, &dest);
3103 ok(hr == S_OK, "got %08x\n", hr);
3104 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3105 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3106 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3107 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3108 VariantClear(&dest);
3110 ISAXContentHandler_Release(content);
3111 IMXWriter_Release(writer);
3113 /* now with omitted declaration */
3114 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3115 &IID_IMXWriter, (void**)&writer);
3116 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3118 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3119 ok(hr == S_OK, "got %08x\n", hr);
3121 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3122 ok(hr == S_OK, "got %08x\n", hr);
3124 hr = ISAXContentHandler_startDocument(content);
3125 ok(hr == S_OK, "got %08x\n", hr);
3127 hr = ISAXContentHandler_endDocument(content);
3128 ok(hr == S_OK, "got %08x\n", hr);
3130 V_VT(&dest) = VT_EMPTY;
3131 hr = IMXWriter_get_output(writer, &dest);
3132 ok(hr == S_OK, "got %08x\n", hr);
3133 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3134 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3135 VariantClear(&dest);
3137 ISAXContentHandler_Release(content);
3138 IMXWriter_Release(writer);
3145 StartElement = 0x001,
3147 StartEndElement = 0x011,
3148 DisableEscaping = 0x100
3151 struct writer_startendelement_t {
3153 enum startendtype type;
3155 const char *local_name;
3159 ISAXAttributes *attr;
3162 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\">";
3163 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\"/>";
3164 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
3166 static const struct writer_startendelement_t writer_startendelement[] = {
3168 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3169 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3170 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3171 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3172 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3174 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3175 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3176 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3177 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3178 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3180 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3181 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3182 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3183 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3184 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3186 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3187 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3188 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3189 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3190 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3192 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3193 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3194 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3195 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3196 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3198 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3199 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3200 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3201 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3202 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3204 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3205 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3206 /* endElement tests */
3207 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3208 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3209 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3211 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3212 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3213 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3214 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3215 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3217 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3218 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3219 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3220 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3221 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3223 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3224 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3225 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3226 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3227 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3229 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3230 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3231 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3232 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3233 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3235 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3236 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3237 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3238 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3239 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3241 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3242 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3243 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3244 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3246 /* with attributes */
3247 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3249 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3250 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3251 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3252 /* empty elements */
3253 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3254 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3256 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3257 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3258 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3259 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3260 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3262 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3264 /* with disabled output escaping */
3265 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3266 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3267 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3268 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3273 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3275 while (table->clsid)
3280 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3281 if (hr == S_OK) IUnknown_Release(unk);
3283 table->supported = hr == S_OK;
3284 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3290 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3294 while (table->clsid)
3296 ISAXContentHandler *content;
3300 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3307 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3308 &IID_IMXWriter, (void**)&writer);
3309 EXPECT_HR(hr, S_OK);
3311 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3312 EXPECT_HR(hr, S_OK);
3314 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3315 EXPECT_HR(hr, S_OK);
3317 hr = ISAXContentHandler_startDocument(content);
3318 EXPECT_HR(hr, S_OK);
3320 if (table->type & DisableEscaping)
3322 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3323 EXPECT_HR(hr, S_OK);
3326 if (table->type & StartElement)
3328 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3329 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3330 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3333 if (table->type & EndElement)
3335 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3336 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3337 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3345 V_VT(&dest) = VT_EMPTY;
3346 hr = IMXWriter_get_output(writer, &dest);
3347 EXPECT_HR(hr, S_OK);
3348 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3349 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3350 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3351 VariantClear(&dest);
3354 ISAXContentHandler_Release(content);
3355 IMXWriter_Release(writer);
3364 /* point of these test is to start/end element with different names and name lengths */
3365 struct writer_startendelement2_t {
3367 const char *qnamestart;
3369 const char *qnameend;
3375 static const struct writer_startendelement2_t writer_startendelement2[] = {
3376 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3377 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3378 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3379 /* -1 length is not allowed for version 6 */
3380 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3382 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3383 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3384 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3385 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3389 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3393 while (table->clsid)
3395 ISAXContentHandler *content;
3399 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3406 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3407 &IID_IMXWriter, (void**)&writer);
3408 EXPECT_HR(hr, S_OK);
3410 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3411 EXPECT_HR(hr, S_OK);
3413 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3414 EXPECT_HR(hr, S_OK);
3416 hr = ISAXContentHandler_startDocument(content);
3417 EXPECT_HR(hr, S_OK);
3419 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3420 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3421 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3423 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3424 _bstr_(table->qnameend), table->qnameend_len);
3425 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3432 V_VT(&dest) = VT_EMPTY;
3433 hr = IMXWriter_get_output(writer, &dest);
3434 EXPECT_HR(hr, S_OK);
3435 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3436 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3437 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3438 VariantClear(&dest);
3441 ISAXContentHandler_Release(content);
3442 IMXWriter_Release(writer);
3452 static void test_mxwriter_startendelement(void)
3454 ISAXContentHandler *content;
3459 test_mxwriter_startendelement_batch(writer_startendelement);
3460 test_mxwriter_startendelement_batch2(writer_startendelement2);
3462 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3463 &IID_IMXWriter, (void**)&writer);
3464 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3466 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3467 ok(hr == S_OK, "got %08x\n", hr);
3469 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3470 ok(hr == S_OK, "got %08x\n", hr);
3472 hr = ISAXContentHandler_startDocument(content);
3473 ok(hr == S_OK, "got %08x\n", hr);
3475 /* all string pointers should be not null */
3476 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3477 ok(hr == S_OK, "got %08x\n", hr);
3479 V_VT(&dest) = VT_EMPTY;
3480 hr = IMXWriter_get_output(writer, &dest);
3481 ok(hr == S_OK, "got %08x\n", hr);
3482 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3483 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3484 VariantClear(&dest);
3486 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3487 ok(hr == S_OK, "got %08x\n", hr);
3489 V_VT(&dest) = VT_EMPTY;
3490 hr = IMXWriter_get_output(writer, &dest);
3491 ok(hr == S_OK, "got %08x\n", hr);
3492 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3493 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3494 VariantClear(&dest);
3496 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3497 EXPECT_HR(hr, E_INVALIDARG);
3499 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3500 EXPECT_HR(hr, E_INVALIDARG);
3502 /* only local name is an error too */
3503 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3504 EXPECT_HR(hr, E_INVALIDARG);
3506 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3507 EXPECT_HR(hr, S_OK);
3509 V_VT(&dest) = VT_EMPTY;
3510 hr = IMXWriter_get_output(writer, &dest);
3511 EXPECT_HR(hr, S_OK);
3512 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3513 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3514 VariantClear(&dest);
3516 hr = ISAXContentHandler_endDocument(content);
3517 EXPECT_HR(hr, S_OK);
3519 V_VT(&dest) = VT_EMPTY;
3520 hr = IMXWriter_put_output(writer, dest);
3521 EXPECT_HR(hr, S_OK);
3523 V_VT(&dest) = VT_EMPTY;
3524 hr = IMXWriter_get_output(writer, &dest);
3525 EXPECT_HR(hr, S_OK);
3526 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3527 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3528 VariantClear(&dest);
3530 hr = ISAXContentHandler_startDocument(content);
3531 EXPECT_HR(hr, S_OK);
3533 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3534 EXPECT_HR(hr, S_OK);
3536 V_VT(&dest) = VT_EMPTY;
3537 hr = IMXWriter_get_output(writer, &dest);
3538 EXPECT_HR(hr, S_OK);
3539 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3540 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3541 VariantClear(&dest);
3543 ISAXContentHandler_endDocument(content);
3544 IMXWriter_flush(writer);
3546 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3547 EXPECT_HR(hr, S_OK);
3548 V_VT(&dest) = VT_EMPTY;
3549 hr = IMXWriter_get_output(writer, &dest);
3550 EXPECT_HR(hr, S_OK);
3551 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3552 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3553 VariantClear(&dest);
3555 V_VT(&dest) = VT_EMPTY;
3556 hr = IMXWriter_put_output(writer, dest);
3557 EXPECT_HR(hr, S_OK);
3560 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3561 EXPECT_HR(hr, S_OK);
3562 V_VT(&dest) = VT_EMPTY;
3563 hr = IMXWriter_get_output(writer, &dest);
3564 EXPECT_HR(hr, S_OK);
3565 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3566 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3567 VariantClear(&dest);
3569 ISAXContentHandler_Release(content);
3570 IMXWriter_Release(writer);
3574 struct writer_characters_t {
3580 static const struct writer_characters_t writer_characters[] = {
3581 { &CLSID_MXXMLWriter, "< > & \"", "< > & \"" },
3582 { &CLSID_MXXMLWriter30, "< > & \"", "< > & \"" },
3583 { &CLSID_MXXMLWriter40, "< > & \"", "< > & \"" },
3584 { &CLSID_MXXMLWriter60, "< > & \"", "< > & \"" },
3588 static void test_mxwriter_characters(void)
3590 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3591 const struct writer_characters_t *table = writer_characters;
3592 ISAXContentHandler *content;
3598 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3599 &IID_IMXWriter, (void**)&writer);
3600 EXPECT_HR(hr, S_OK);
3602 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3603 EXPECT_HR(hr, S_OK);
3605 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3606 EXPECT_HR(hr, S_OK);
3608 hr = ISAXContentHandler_startDocument(content);
3609 EXPECT_HR(hr, S_OK);
3611 hr = ISAXContentHandler_characters(content, NULL, 0);
3612 EXPECT_HR(hr, E_INVALIDARG);
3614 hr = ISAXContentHandler_characters(content, chardataW, 0);
3615 EXPECT_HR(hr, S_OK);
3617 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3618 EXPECT_HR(hr, S_OK);
3620 V_VT(&dest) = VT_EMPTY;
3621 hr = IMXWriter_get_output(writer, &dest);
3622 EXPECT_HR(hr, S_OK);
3623 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3624 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3625 VariantClear(&dest);
3627 hr = ISAXContentHandler_endDocument(content);
3628 EXPECT_HR(hr, S_OK);
3630 ISAXContentHandler_Release(content);
3631 IMXWriter_Release(writer);
3633 /* try empty characters data to see if element is closed */
3634 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3635 &IID_IMXWriter, (void**)&writer);
3636 EXPECT_HR(hr, S_OK);
3638 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3639 EXPECT_HR(hr, S_OK);
3641 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3642 EXPECT_HR(hr, S_OK);
3644 hr = ISAXContentHandler_startDocument(content);
3645 EXPECT_HR(hr, S_OK);
3647 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3648 EXPECT_HR(hr, S_OK);
3650 hr = ISAXContentHandler_characters(content, chardataW, 0);
3651 EXPECT_HR(hr, S_OK);
3653 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3654 EXPECT_HR(hr, S_OK);
3656 V_VT(&dest) = VT_EMPTY;
3657 hr = IMXWriter_get_output(writer, &dest);
3658 EXPECT_HR(hr, S_OK);
3659 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3660 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3661 VariantClear(&dest);
3663 ISAXContentHandler_Release(content);
3664 IMXWriter_Release(writer);
3667 while (table->clsid)
3669 ISAXContentHandler *content;
3674 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3681 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3682 &IID_IMXWriter, (void**)&writer);
3683 EXPECT_HR(hr, S_OK);
3685 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3686 EXPECT_HR(hr, S_OK);
3688 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3689 EXPECT_HR(hr, S_OK);
3691 hr = ISAXContentHandler_startDocument(content);
3692 EXPECT_HR(hr, S_OK);
3694 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3695 EXPECT_HR(hr, S_OK);
3700 V_VT(&dest) = VT_EMPTY;
3701 hr = IMXWriter_get_output(writer, &dest);
3702 EXPECT_HR(hr, S_OK);
3703 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3704 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3705 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3706 VariantClear(&dest);
3709 /* with disabled escaping */
3710 V_VT(&dest) = VT_EMPTY;
3711 hr = IMXWriter_put_output(writer, dest);
3712 EXPECT_HR(hr, S_OK);
3714 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3715 EXPECT_HR(hr, S_OK);
3717 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3718 EXPECT_HR(hr, S_OK);
3723 V_VT(&dest) = VT_EMPTY;
3724 hr = IMXWriter_get_output(writer, &dest);
3725 EXPECT_HR(hr, S_OK);
3726 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3727 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3728 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3729 VariantClear(&dest);
3732 ISAXContentHandler_Release(content);
3733 IMXWriter_Release(writer);
3742 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3744 VARIANT_TRUE,"UTF-16",
3746 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3747 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3752 VARIANT_FALSE,"UTF-16",
3754 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3759 VARIANT_TRUE,"UTF-8",
3761 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3762 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3763 * and the writer is released.
3770 VARIANT_TRUE,"utf-8",
3772 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3773 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3774 * and the writer is released.
3781 VARIANT_TRUE,"UTF-16",
3783 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3784 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3789 VARIANT_TRUE,"UTF-16",
3791 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3792 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3798 static void test_mxwriter_stream(void)
3801 ISAXContentHandler *content;
3806 ULARGE_INTEGER pos2;
3807 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3809 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3810 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3812 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3813 &IID_IMXWriter, (void**)&writer);
3814 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3816 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3817 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3819 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3820 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3822 V_VT(&dest) = VT_UNKNOWN;
3823 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3824 hr = IMXWriter_put_output(writer, dest);
3825 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3826 VariantClear(&dest);
3828 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3829 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3831 current_write_test = test->expected_writes;
3833 hr = ISAXContentHandler_startDocument(content);
3834 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3836 hr = ISAXContentHandler_endDocument(content);
3837 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3839 ISAXContentHandler_Release(content);
3840 IMXWriter_Release(writer);
3842 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3843 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3846 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3847 &IID_IMXWriter, (void**)&writer);
3848 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3850 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3851 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3853 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3854 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3856 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3857 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3859 V_VT(&dest) = VT_UNKNOWN;
3860 V_UNKNOWN(&dest) = (IUnknown*)stream;
3861 hr = IMXWriter_put_output(writer, dest);
3862 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3864 hr = ISAXContentHandler_startDocument(content);
3865 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3867 /* Setting output of the mxwriter causes the current output to be flushed,
3868 * and the writer to start over.
3870 V_VT(&dest) = VT_EMPTY;
3871 hr = IMXWriter_put_output(writer, dest);
3872 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3875 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3876 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3877 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3879 hr = ISAXContentHandler_startDocument(content);
3880 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3882 hr = ISAXContentHandler_endDocument(content);
3883 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3885 V_VT(&dest) = VT_EMPTY;
3886 hr = IMXWriter_get_output(writer, &dest);
3887 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3888 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3889 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3890 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3891 VariantClear(&dest);
3893 /* test when BOM is written to output stream */
3894 V_VT(&dest) = VT_EMPTY;
3895 hr = IMXWriter_put_output(writer, dest);
3896 EXPECT_HR(hr, S_OK);
3899 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3900 EXPECT_HR(hr, S_OK);
3902 V_VT(&dest) = VT_UNKNOWN;
3903 V_UNKNOWN(&dest) = (IUnknown*)stream;
3904 hr = IMXWriter_put_output(writer, dest);
3905 EXPECT_HR(hr, S_OK);
3907 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3908 EXPECT_HR(hr, S_OK);
3910 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3911 EXPECT_HR(hr, S_OK);
3913 hr = ISAXContentHandler_startDocument(content);
3914 EXPECT_HR(hr, S_OK);
3918 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3919 EXPECT_HR(hr, S_OK);
3920 ok(pos2.QuadPart == 2, "got wrong position\n");
3922 ISAXContentHandler_Release(content);
3923 IMXWriter_Release(writer);
3928 static const char *encoding_names[] = {
3941 static void test_mxwriter_encoding(void)
3943 ISAXContentHandler *content;
3954 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3955 &IID_IMXWriter, (void**)&writer);
3956 EXPECT_HR(hr, S_OK);
3958 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3959 EXPECT_HR(hr, S_OK);
3961 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3962 EXPECT_HR(hr, S_OK);
3964 hr = ISAXContentHandler_startDocument(content);
3965 EXPECT_HR(hr, S_OK);
3967 hr = ISAXContentHandler_endDocument(content);
3968 EXPECT_HR(hr, S_OK);
3970 /* The content is always re-encoded to UTF-16 when the output is
3971 * retrieved as a BSTR.
3973 V_VT(&dest) = VT_EMPTY;
3974 hr = IMXWriter_get_output(writer, &dest);
3975 EXPECT_HR(hr, S_OK);
3976 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3977 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3978 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3979 VariantClear(&dest);
3981 /* switch encoding when something is written already */
3982 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3983 EXPECT_HR(hr, S_OK);
3985 V_VT(&dest) = VT_UNKNOWN;
3986 V_UNKNOWN(&dest) = (IUnknown*)stream;
3987 hr = IMXWriter_put_output(writer, dest);
3988 EXPECT_HR(hr, S_OK);
3990 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3991 EXPECT_HR(hr, S_OK);
3993 /* write empty element */
3994 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3995 EXPECT_HR(hr, S_OK);
3997 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3998 EXPECT_HR(hr, S_OK);
4001 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4002 EXPECT_HR(hr, S_OK);
4004 hr = IMXWriter_flush(writer);
4005 EXPECT_HR(hr, S_OK);
4007 hr = GetHGlobalFromStream(stream, &g);
4008 EXPECT_HR(hr, S_OK);
4010 ptr = GlobalLock(g);
4011 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4014 /* so output is unaffected, encoding name is stored however */
4015 hr = IMXWriter_get_encoding(writer, &s);
4016 EXPECT_HR(hr, S_OK);
4017 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4020 IStream_Release(stream);
4023 enc = encoding_names[i];
4026 char expectedA[200];
4028 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4029 EXPECT_HR(hr, S_OK);
4031 V_VT(&dest) = VT_UNKNOWN;
4032 V_UNKNOWN(&dest) = (IUnknown*)stream;
4033 hr = IMXWriter_put_output(writer, dest);
4034 EXPECT_HR(hr, S_OK);
4036 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4037 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4038 "%s: encoding not accepted\n", enc);
4041 enc = encoding_names[++i];
4042 IStream_Release(stream);
4046 hr = ISAXContentHandler_startDocument(content);
4047 EXPECT_HR(hr, S_OK);
4049 hr = ISAXContentHandler_endDocument(content);
4050 EXPECT_HR(hr, S_OK);
4052 hr = IMXWriter_flush(writer);
4053 EXPECT_HR(hr, S_OK);
4055 /* prepare expected string */
4057 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4058 strcat(expectedA, enc);
4059 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4061 hr = GetHGlobalFromStream(stream, &g);
4062 EXPECT_HR(hr, S_OK);
4064 ptr = GlobalLock(g);
4065 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4068 V_VT(&dest) = VT_EMPTY;
4069 hr = IMXWriter_put_output(writer, dest);
4070 EXPECT_HR(hr, S_OK);
4072 IStream_Release(stream);
4074 enc = encoding_names[++i];
4077 ISAXContentHandler_Release(content);
4078 IMXWriter_Release(writer);
4083 static void test_obj_dispex(IUnknown *obj)
4085 static const WCHAR starW[] = {'*',0};
4086 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4087 IDispatchEx *dispex;
4094 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4095 EXPECT_HR(hr, S_OK);
4096 if (FAILED(hr)) return;
4099 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4100 EXPECT_HR(hr, S_OK);
4101 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4103 name = SysAllocString(starW);
4104 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4105 EXPECT_HR(hr, E_NOTIMPL);
4106 SysFreeString(name);
4108 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4109 EXPECT_HR(hr, E_NOTIMPL);
4112 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4113 EXPECT_HR(hr, E_NOTIMPL);
4114 ok(props == 0, "expected 0 got %d\n", props);
4116 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4117 EXPECT_HR(hr, E_NOTIMPL);
4118 if (SUCCEEDED(hr)) SysFreeString(name);
4120 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4121 EXPECT_HR(hr, E_NOTIMPL);
4123 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4124 EXPECT_HR(hr, E_NOTIMPL);
4125 if (hr == S_OK && unk) IUnknown_Release(unk);
4127 IDispatchEx_Release(dispex);
4130 static void test_dispex(void)
4132 IVBSAXXMLReader *vbreader;
4133 ISAXXMLReader *reader;
4137 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4138 &IID_ISAXXMLReader, (void**)&reader);
4139 EXPECT_HR(hr, S_OK);
4141 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4142 EXPECT_HR(hr, S_OK);
4143 test_obj_dispex(unk);
4144 IUnknown_Release(unk);
4146 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4147 EXPECT_HR(hr, S_OK);
4148 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4149 EXPECT_HR(hr, S_OK);
4150 test_obj_dispex(unk);
4151 IUnknown_Release(unk);
4152 IVBSAXXMLReader_Release(vbreader);
4154 ISAXXMLReader_Release(reader);
4157 static void test_mxwriter_dispex(void)
4159 IDispatchEx *dispex;
4164 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4165 &IID_IMXWriter, (void**)&writer);
4166 EXPECT_HR(hr, S_OK);
4168 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4169 EXPECT_HR(hr, S_OK);
4170 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4171 test_obj_dispex(unk);
4172 IUnknown_Release(unk);
4173 IDispatchEx_Release(dispex);
4175 IMXWriter_Release(writer);
4178 static void test_mxwriter_comment(void)
4180 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4181 ISAXContentHandler *content;
4182 ISAXLexicalHandler *lexical;
4187 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4188 &IID_IMXWriter, (void**)&writer);
4189 EXPECT_HR(hr, S_OK);
4191 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4192 EXPECT_HR(hr, S_OK);
4194 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4195 EXPECT_HR(hr, S_OK);
4197 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4198 EXPECT_HR(hr, S_OK);
4200 hr = ISAXContentHandler_startDocument(content);
4201 EXPECT_HR(hr, S_OK);
4203 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4204 EXPECT_HR(hr, E_INVALIDARG);
4206 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4207 EXPECT_HR(hr, S_OK);
4209 V_VT(&dest) = VT_EMPTY;
4210 hr = IMXWriter_get_output(writer, &dest);
4211 EXPECT_HR(hr, S_OK);
4212 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4213 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4214 VariantClear(&dest);
4216 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4217 EXPECT_HR(hr, S_OK);
4219 V_VT(&dest) = VT_EMPTY;
4220 hr = IMXWriter_get_output(writer, &dest);
4221 EXPECT_HR(hr, S_OK);
4222 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4223 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4224 VariantClear(&dest);
4226 ISAXContentHandler_Release(content);
4227 ISAXLexicalHandler_Release(lexical);
4228 IMXWriter_Release(writer);
4232 static void test_mxwriter_cdata(void)
4234 ISAXContentHandler *content;
4235 ISAXLexicalHandler *lexical;
4240 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4241 &IID_IMXWriter, (void**)&writer);
4242 EXPECT_HR(hr, S_OK);
4244 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4245 EXPECT_HR(hr, S_OK);
4247 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4248 EXPECT_HR(hr, S_OK);
4250 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4251 EXPECT_HR(hr, S_OK);
4253 hr = ISAXContentHandler_startDocument(content);
4254 EXPECT_HR(hr, S_OK);
4256 hr = ISAXLexicalHandler_startCDATA(lexical);
4257 EXPECT_HR(hr, S_OK);
4259 V_VT(&dest) = VT_EMPTY;
4260 hr = IMXWriter_get_output(writer, &dest);
4261 EXPECT_HR(hr, S_OK);
4262 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4263 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4264 VariantClear(&dest);
4266 hr = ISAXLexicalHandler_startCDATA(lexical);
4267 EXPECT_HR(hr, S_OK);
4269 /* all these are escaped for text nodes */
4270 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4271 EXPECT_HR(hr, S_OK);
4273 hr = ISAXLexicalHandler_endCDATA(lexical);
4274 EXPECT_HR(hr, S_OK);
4276 V_VT(&dest) = VT_EMPTY;
4277 hr = IMXWriter_get_output(writer, &dest);
4278 EXPECT_HR(hr, S_OK);
4279 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4280 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4281 VariantClear(&dest);
4283 ISAXContentHandler_Release(content);
4284 ISAXLexicalHandler_Release(lexical);
4285 IMXWriter_Release(writer);
4289 static void test_mxwriter_pi(void)
4291 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4292 static const WCHAR dataW[] = {'d','a','t','a',0};
4293 ISAXContentHandler *content;
4298 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4299 &IID_IMXWriter, (void**)&writer);
4300 EXPECT_HR(hr, S_OK);
4302 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4303 EXPECT_HR(hr, S_OK);
4305 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4306 EXPECT_HR(hr, E_INVALIDARG);
4308 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4309 EXPECT_HR(hr, S_OK);
4311 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4312 EXPECT_HR(hr, S_OK);
4314 V_VT(&dest) = VT_EMPTY;
4315 hr = IMXWriter_get_output(writer, &dest);
4316 EXPECT_HR(hr, S_OK);
4317 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4318 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4319 VariantClear(&dest);
4321 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4322 EXPECT_HR(hr, S_OK);
4324 V_VT(&dest) = VT_EMPTY;
4325 hr = IMXWriter_get_output(writer, &dest);
4326 EXPECT_HR(hr, S_OK);
4327 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4328 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)));
4329 VariantClear(&dest);
4331 V_VT(&dest) = VT_EMPTY;
4332 hr = IMXWriter_put_output(writer, dest);
4333 EXPECT_HR(hr, S_OK);
4335 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4336 EXPECT_HR(hr, S_OK);
4338 V_VT(&dest) = VT_EMPTY;
4339 hr = IMXWriter_get_output(writer, &dest);
4340 EXPECT_HR(hr, S_OK);
4341 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4342 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4343 VariantClear(&dest);
4346 ISAXContentHandler_Release(content);
4347 IMXWriter_Release(writer);
4350 static void test_mxwriter_ignorablespaces(void)
4352 static const WCHAR dataW[] = {'d','a','t','a',0};
4353 ISAXContentHandler *content;
4358 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4359 &IID_IMXWriter, (void**)&writer);
4360 EXPECT_HR(hr, S_OK);
4362 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4363 EXPECT_HR(hr, S_OK);
4365 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4366 EXPECT_HR(hr, E_INVALIDARG);
4368 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4369 EXPECT_HR(hr, S_OK);
4371 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4372 EXPECT_HR(hr, S_OK);
4374 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4375 EXPECT_HR(hr, S_OK);
4377 V_VT(&dest) = VT_EMPTY;
4378 hr = IMXWriter_get_output(writer, &dest);
4379 EXPECT_HR(hr, S_OK);
4380 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4381 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4382 VariantClear(&dest);
4384 ISAXContentHandler_Release(content);
4385 IMXWriter_Release(writer);
4388 static void test_mxwriter_dtd(void)
4390 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4391 static const WCHAR nameW[] = {'n','a','m','e'};
4392 static const WCHAR pubW[] = {'p','u','b'};
4393 static const WCHAR sysW[] = {'s','y','s'};
4394 ISAXContentHandler *content;
4395 ISAXLexicalHandler *lexical;
4396 ISAXDeclHandler *decl;
4401 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4402 &IID_IMXWriter, (void**)&writer);
4403 EXPECT_HR(hr, S_OK);
4405 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4406 EXPECT_HR(hr, S_OK);
4408 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4409 EXPECT_HR(hr, S_OK);
4411 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4412 EXPECT_HR(hr, S_OK);
4414 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4415 EXPECT_HR(hr, S_OK);
4417 hr = ISAXContentHandler_startDocument(content);
4418 EXPECT_HR(hr, S_OK);
4420 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4421 EXPECT_HR(hr, E_INVALIDARG);
4423 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4424 EXPECT_HR(hr, E_INVALIDARG);
4426 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4427 EXPECT_HR(hr, E_INVALIDARG);
4429 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4430 EXPECT_HR(hr, E_INVALIDARG);
4432 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4433 EXPECT_HR(hr, S_OK);
4435 V_VT(&dest) = VT_EMPTY;
4436 hr = IMXWriter_get_output(writer, &dest);
4437 EXPECT_HR(hr, S_OK);
4438 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4439 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4440 VariantClear(&dest);
4442 /* system id is required if public is present */
4443 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4444 EXPECT_HR(hr, E_INVALIDARG);
4446 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4447 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4448 EXPECT_HR(hr, S_OK);
4450 V_VT(&dest) = VT_EMPTY;
4451 hr = IMXWriter_get_output(writer, &dest);
4452 EXPECT_HR(hr, S_OK);
4453 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4454 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4455 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4456 VariantClear(&dest);
4458 hr = ISAXLexicalHandler_endDTD(lexical);
4459 EXPECT_HR(hr, S_OK);
4461 hr = ISAXLexicalHandler_endDTD(lexical);
4462 EXPECT_HR(hr, S_OK);
4464 V_VT(&dest) = VT_EMPTY;
4465 hr = IMXWriter_get_output(writer, &dest);
4466 EXPECT_HR(hr, S_OK);
4467 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4468 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4469 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4470 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4471 VariantClear(&dest);
4473 /* element declaration */
4474 V_VT(&dest) = VT_EMPTY;
4475 hr = IMXWriter_put_output(writer, dest);
4476 EXPECT_HR(hr, S_OK);
4478 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4479 EXPECT_HR(hr, E_INVALIDARG);
4481 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4482 EXPECT_HR(hr, E_INVALIDARG);
4484 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4485 EXPECT_HR(hr, S_OK);
4487 V_VT(&dest) = VT_EMPTY;
4488 hr = IMXWriter_get_output(writer, &dest);
4489 EXPECT_HR(hr, S_OK);
4490 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4491 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4492 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4493 VariantClear(&dest);
4495 V_VT(&dest) = VT_EMPTY;
4496 hr = IMXWriter_put_output(writer, dest);
4497 EXPECT_HR(hr, S_OK);
4499 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4500 EXPECT_HR(hr, S_OK);
4502 V_VT(&dest) = VT_EMPTY;
4503 hr = IMXWriter_get_output(writer, &dest);
4504 EXPECT_HR(hr, S_OK);
4505 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4506 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4507 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4508 VariantClear(&dest);
4510 /* attribute declaration */
4511 V_VT(&dest) = VT_EMPTY;
4512 hr = IMXWriter_put_output(writer, dest);
4513 EXPECT_HR(hr, S_OK);
4515 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4516 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4517 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4518 EXPECT_HR(hr, S_OK);
4520 V_VT(&dest) = VT_EMPTY;
4521 hr = IMXWriter_get_output(writer, &dest);
4522 EXPECT_HR(hr, S_OK);
4523 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4524 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4525 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4526 VariantClear(&dest);
4528 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4529 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4530 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4531 EXPECT_HR(hr, S_OK);
4533 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4534 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4535 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4536 EXPECT_HR(hr, S_OK);
4538 V_VT(&dest) = VT_EMPTY;
4539 hr = IMXWriter_get_output(writer, &dest);
4540 EXPECT_HR(hr, S_OK);
4541 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4542 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4543 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4544 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4545 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4546 VariantClear(&dest);
4548 /* internal entities */
4549 V_VT(&dest) = VT_EMPTY;
4550 hr = IMXWriter_put_output(writer, dest);
4551 EXPECT_HR(hr, S_OK);
4553 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4554 EXPECT_HR(hr, E_INVALIDARG);
4556 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4557 EXPECT_HR(hr, E_INVALIDARG);
4559 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4560 EXPECT_HR(hr, S_OK);
4562 V_VT(&dest) = VT_EMPTY;
4563 hr = IMXWriter_get_output(writer, &dest);
4564 EXPECT_HR(hr, S_OK);
4565 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4566 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4567 VariantClear(&dest);
4569 ISAXContentHandler_Release(content);
4570 ISAXLexicalHandler_Release(lexical);
4571 ISAXDeclHandler_Release(decl);
4572 IMXWriter_Release(writer);
4584 } addattribute_test_t;
4586 static const addattribute_test_t addattribute_data[] = {
4587 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4588 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4589 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4590 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4592 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4593 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4594 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4595 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4597 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4598 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4599 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4600 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4602 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4603 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4604 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4605 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4610 static void test_mxattr_addAttribute(void)
4612 const addattribute_test_t *table = addattribute_data;
4615 while (table->clsid)
4617 ISAXAttributes *saxattr;
4618 IMXAttributes *mxattr;
4623 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4630 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4631 &IID_IMXAttributes, (void**)&mxattr);
4632 EXPECT_HR(hr, S_OK);
4634 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4635 EXPECT_HR(hr, S_OK);
4637 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4638 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4639 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4641 hr = ISAXAttributes_getLength(saxattr, NULL);
4642 EXPECT_HR(hr, E_POINTER);
4646 hr = ISAXAttributes_getLength(saxattr, &len);
4647 EXPECT_HR(hr, S_OK);
4648 ok(len == 0, "got %d\n", len);
4650 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4651 EXPECT_HR(hr, E_INVALIDARG);
4653 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4654 EXPECT_HR(hr, E_INVALIDARG);
4656 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4657 EXPECT_HR(hr, E_INVALIDARG);
4659 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4660 EXPECT_HR(hr, E_INVALIDARG);
4662 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4663 EXPECT_HR(hr, E_INVALIDARG);
4665 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4666 EXPECT_HR(hr, E_INVALIDARG);
4668 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4669 EXPECT_HR(hr, E_INVALIDARG);
4671 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4672 EXPECT_HR(hr, E_INVALIDARG);
4674 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4675 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4676 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4680 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4681 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4682 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4684 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4685 EXPECT_HR(hr, E_POINTER);
4687 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4688 EXPECT_HR(hr, E_POINTER);
4690 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4691 EXPECT_HR(hr, E_POINTER);
4693 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4694 EXPECT_HR(hr, E_POINTER);
4696 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4697 EXPECT_HR(hr, E_POINTER);
4699 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4700 EXPECT_HR(hr, E_POINTER);
4704 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4705 EXPECT_HR(hr, S_OK);
4706 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4708 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4711 value = (void*)0xdeadbeef;
4712 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4713 EXPECT_HR(hr, S_OK);
4717 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4719 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4723 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4724 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4727 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4728 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4729 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4731 EXPECT_HR(hr, E_POINTER);
4734 EXPECT_HR(hr, E_INVALIDARG);
4736 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4737 EXPECT_HR(hr, E_INVALIDARG);
4740 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4741 EXPECT_HR(hr, E_INVALIDARG);
4742 ok(index == -1, "%d: got wrong index %d\n", i, index);
4745 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4746 EXPECT_HR(hr, E_INVALIDARG);
4747 ok(index == -1, "%d: got wrong index %d\n", i, index);
4750 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4751 EXPECT_HR(hr, S_OK);
4752 ok(index == 0, "%d: got wrong index %d\n", i, index);
4755 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4756 EXPECT_HR(hr, E_INVALIDARG);
4757 ok(index == -1, "%d: got wrong index %d\n", i, index);
4759 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4760 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4762 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4763 EXPECT_HR(hr, E_INVALIDARG);
4765 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4766 EXPECT_HR(hr, E_INVALIDARG);
4768 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4769 EXPECT_HR(hr, E_INVALIDARG);
4771 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4772 EXPECT_HR(hr, E_INVALIDARG);
4774 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4775 EXPECT_HR(hr, E_INVALIDARG);
4777 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4778 EXPECT_HR(hr, E_INVALIDARG);
4782 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4783 EXPECT_HR(hr, E_POINTER);
4785 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4786 EXPECT_HR(hr, E_POINTER);
4788 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4789 EXPECT_HR(hr, E_POINTER);
4791 /* versions 4 and 6 crash */
4792 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4793 EXPECT_HR(hr, E_POINTER);
4795 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4796 EXPECT_HR(hr, E_POINTER);
4798 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4799 EXPECT_HR(hr, E_POINTER);
4801 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4802 EXPECT_HR(hr, E_POINTER);
4804 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4805 EXPECT_HR(hr, E_POINTER);
4807 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4808 EXPECT_HR(hr, E_POINTER);
4810 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4811 EXPECT_HR(hr, E_POINTER);
4813 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4814 strlen(table->local), NULL, NULL);
4815 EXPECT_HR(hr, E_POINTER);
4818 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4819 EXPECT_HR(hr, S_OK);
4820 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4822 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4825 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4826 _bstr_(table->local), strlen(table->local), &value, &len);
4827 EXPECT_HR(hr, S_OK);
4828 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4830 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4835 hr = ISAXAttributes_getLength(saxattr, &len);
4836 EXPECT_HR(hr, S_OK);
4837 if (table->hr == S_OK)
4838 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
4840 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
4842 ISAXAttributes_Release(saxattr);
4843 IMXAttributes_Release(mxattr);
4852 static void test_mxattr_clear(void)
4854 ISAXAttributes *saxattr;
4855 IMXAttributes *mxattr;
4860 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4861 &IID_IMXAttributes, (void**)&mxattr);
4862 EXPECT_HR(hr, S_OK);
4864 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4865 EXPECT_HR(hr, S_OK);
4867 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4868 EXPECT_HR(hr, E_INVALIDARG);
4870 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4871 EXPECT_HR(hr, E_INVALIDARG);
4873 hr = IMXAttributes_clear(mxattr);
4874 EXPECT_HR(hr, S_OK);
4876 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4877 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4878 EXPECT_HR(hr, S_OK);
4881 hr = ISAXAttributes_getLength(saxattr, &len);
4882 EXPECT_HR(hr, S_OK);
4883 ok(len == 1, "got %d\n", len);
4886 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4887 EXPECT_HR(hr, E_POINTER);
4888 ok(len == -1, "got %d\n", len);
4890 ptr = (void*)0xdeadbeef;
4891 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4892 EXPECT_HR(hr, E_POINTER);
4893 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4896 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4897 EXPECT_HR(hr, S_OK);
4898 ok(len == 5, "got %d\n", len);
4899 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4901 hr = IMXAttributes_clear(mxattr);
4902 EXPECT_HR(hr, S_OK);
4905 hr = ISAXAttributes_getLength(saxattr, &len);
4906 EXPECT_HR(hr, S_OK);
4907 ok(len == 0, "got %d\n", len);
4910 ptr = (void*)0xdeadbeef;
4911 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4912 EXPECT_HR(hr, E_INVALIDARG);
4913 ok(len == -1, "got %d\n", len);
4914 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4916 IMXAttributes_Release(mxattr);
4917 ISAXAttributes_Release(saxattr);
4921 static void test_mxattr_dispex(void)
4923 IMXAttributes *mxattr;
4924 IDispatchEx *dispex;
4928 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4929 &IID_IMXAttributes, (void**)&mxattr);
4930 EXPECT_HR(hr, S_OK);
4932 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4933 EXPECT_HR(hr, S_OK);
4934 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4935 test_obj_dispex(unk);
4936 IUnknown_Release(unk);
4937 IDispatchEx_Release(dispex);
4939 IMXAttributes_Release(mxattr);
4942 static void test_mxattr_qi(void)
4944 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4945 ISAXAttributes *saxattr;
4946 IMXAttributes *mxattr;
4949 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4950 &IID_IMXAttributes, (void**)&mxattr);
4951 EXPECT_HR(hr, S_OK);
4953 EXPECT_REF(mxattr, 1);
4954 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4955 EXPECT_HR(hr, S_OK);
4957 EXPECT_REF(mxattr, 2);
4958 EXPECT_REF(saxattr, 2);
4960 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4961 EXPECT_HR(hr, S_OK);
4963 EXPECT_REF(vbsaxattr, 3);
4964 EXPECT_REF(mxattr, 3);
4965 EXPECT_REF(saxattr, 3);
4967 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4968 EXPECT_HR(hr, S_OK);
4970 EXPECT_REF(vbsaxattr, 4);
4971 EXPECT_REF(mxattr, 4);
4972 EXPECT_REF(saxattr, 4);
4974 IMXAttributes_Release(mxattr);
4975 ISAXAttributes_Release(saxattr);
4976 IVBSAXAttributes_Release(vbsaxattr);
4977 IVBSAXAttributes_Release(vbsaxattr2);
4980 static struct msxmlsupported_data_t saxattr_support_data[] =
4982 { &CLSID_SAXAttributes, "SAXAttributes" },
4983 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4984 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4985 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4989 static void test_mxattr_localname(void)
4991 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4992 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4993 static const WCHAR uri1W[] = {'u','r','i','1',0};
4994 static const WCHAR uriW[] = {'u','r','i',0};
4996 const struct msxmlsupported_data_t *table = saxattr_support_data;
4998 while (table->clsid)
5000 ISAXAttributes *saxattr;
5001 IMXAttributes *mxattr;
5005 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5011 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5012 &IID_IMXAttributes, (void**)&mxattr);
5013 EXPECT_HR(hr, S_OK);
5015 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5016 EXPECT_HR(hr, S_OK);
5018 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5019 EXPECT_HR(hr, E_INVALIDARG);
5021 /* add some ambiguos attribute names */
5022 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5023 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5024 EXPECT_HR(hr, S_OK);
5025 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5026 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5027 EXPECT_HR(hr, S_OK);
5030 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5031 EXPECT_HR(hr, S_OK);
5032 ok(index == 0, "%s: got index %d\n", table->name, index);
5035 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5036 EXPECT_HR(hr, E_INVALIDARG);
5037 ok(index == -1, "%s: got index %d\n", table->name, index);
5040 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5041 EXPECT_HR(hr, E_INVALIDARG);
5042 ok(index == -1, "%s: got index %d\n", table->name, index);
5044 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5045 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5047 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5048 EXPECT_HR(hr, E_POINTER);
5050 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5051 EXPECT_HR(hr, E_POINTER);
5055 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5056 EXPECT_HR(hr, E_INVALIDARG);
5058 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5059 EXPECT_HR(hr, E_INVALIDARG);
5062 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5063 EXPECT_HR(hr, E_INVALIDARG);
5065 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5066 EXPECT_HR(hr, E_INVALIDARG);
5070 ISAXAttributes_Release(saxattr);
5071 IMXAttributes_Release(mxattr);
5075 START_TEST(saxreader)
5077 ISAXXMLReader *reader;
5080 hr = CoInitialize(NULL);
5081 ok(hr == S_OK, "failed to init com\n");
5083 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5084 &IID_ISAXXMLReader, (void**)&reader);
5088 skip("Failed to create SAXXMLReader instance\n");
5092 ISAXXMLReader_Release(reader);
5094 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5096 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5099 test_saxreader_properties();
5100 test_saxreader_features();
5101 test_saxreader_encoding();
5104 /* MXXMLWriter tests */
5105 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5106 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5108 test_mxwriter_handlers();
5109 test_mxwriter_startenddocument();
5110 test_mxwriter_startendelement();
5111 test_mxwriter_characters();
5112 test_mxwriter_comment();
5113 test_mxwriter_cdata();
5115 test_mxwriter_ignorablespaces();
5116 test_mxwriter_dtd();
5117 test_mxwriter_properties();
5118 test_mxwriter_flush();
5119 test_mxwriter_stream();
5120 test_mxwriter_encoding();
5121 test_mxwriter_dispex();
5124 win_skip("MXXMLWriter not supported\n");
5126 /* SAXAttributes tests */
5127 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5128 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5131 test_mxattr_addAttribute();
5132 test_mxattr_clear();
5133 test_mxattr_localname();
5134 test_mxattr_dispex();
5137 skip("SAXAttributes not supported\n");