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 struct msxmlsupported_data_t
56 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
60 if (table->clsid == clsid) return table->supported;
66 static BSTR alloc_str_from_narrow(const char *str)
68 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
69 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
70 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
74 static BSTR alloced_bstrs[512];
75 static int alloced_bstrs_count;
77 static BSTR _bstr_(const char *str)
79 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
80 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
81 return alloced_bstrs[alloced_bstrs_count++];
84 static void free_bstrs(void)
87 for (i = 0; i < alloced_bstrs_count; i++)
88 SysFreeString(alloced_bstrs[i]);
89 alloced_bstrs_count = 0;
92 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, int todo, int *failcount)
97 len = SysStringLen(str);
104 ok_(file, line) (!str, "got %p, expected null str\n", str);
107 ok_(file, line) (!str, "got %p, expected null str\n", str);
113 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
116 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
120 lenexp = strlen(expected);
121 if (lenexp != len && todo)
125 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
128 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
130 /* exit earlier on length mismatch */
131 if (lenexp != len) return;
133 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
135 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
140 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
141 wine_dbgstr_wn(str, len), expected);
144 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
145 wine_dbgstr_wn(str, len), expected);
150 CH_PUTDOCUMENTLOCATOR,
153 CH_STARTPREFIXMAPPING,
158 CH_IGNORABLEWHITESPACE,
159 CH_PROCESSINGINSTRUCTION,
167 static const char *event_names[EVENT_LAST] = {
169 "putDocumentLocator",
172 "startPrefixMapping",
177 "ignorableWhitespace",
178 "processingIntruction",
185 struct attribute_entry {
191 /* used for actual call data only, null for expected call data */
207 /* allocated once at startElement callback */
208 struct attribute_entry *attributes;
211 /* used for actual call data only, null for expected call data */
221 struct call_entry *sequence;
224 #define CONTENT_HANDLER_INDEX 0
225 #define NUM_CALL_SEQUENCES 1
226 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
228 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
230 memset(call, 0, sizeof(*call));
231 ISAXLocator_getLineNumber(locator, &call->line);
232 ISAXLocator_getColumnNumber(locator, &call->column);
235 static void add_call(struct call_sequence **seq, int sequence_index,
236 const struct call_entry *call)
238 struct call_sequence *call_seq = seq[sequence_index];
240 if (!call_seq->sequence)
243 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
244 call_seq->size * sizeof (struct call_entry));
247 if (call_seq->count == call_seq->size)
250 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
252 call_seq->size * sizeof (struct call_entry));
255 assert(call_seq->sequence);
257 call_seq->sequence[call_seq->count].id = call->id;
258 call_seq->sequence[call_seq->count].line = call->line;
259 call_seq->sequence[call_seq->count].column = call->column;
260 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
261 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
262 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
263 call_seq->sequence[call_seq->count].ret = call->ret;
264 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
265 call_seq->sequence[call_seq->count].attributes = call->attributes;
270 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
274 struct call_sequence *call_seq = seg[sequence_index];
276 for (i = 0; i < call_seq->count; i++)
280 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
282 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
283 SysFreeString(call_seq->sequence[i].attributes[j].localW);
284 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
287 SysFreeString(call_seq->sequence[i].arg1W);
288 SysFreeString(call_seq->sequence[i].arg2W);
289 SysFreeString(call_seq->sequence[i].arg3W);
292 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
293 call_seq->sequence = NULL;
294 call_seq->count = call_seq->size = 0;
297 static inline void flush_sequences(struct call_sequence **seq, int n)
300 for (i = 0; i < n; i++)
301 flush_sequence(seq, i);
304 static const char *get_event_name(CH event)
306 return event_names[event];
309 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
310 int todo, const char *file, int line, int *failcount)
314 /* attribute count is not stored for expected data */
315 if (expected->attributes)
317 struct attribute_entry *ptr = expected->attributes;
318 while (ptr->uri) { lenexp++; ptr++; };
321 /* check count first and exit earlier */
322 if (actual->attr_count != lenexp && todo)
326 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
327 context, get_event_name(actual->id), lenexp, actual->attr_count);
330 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
331 context, get_event_name(actual->id), lenexp, actual->attr_count);
333 if (actual->attr_count != lenexp) return;
335 /* now compare all attributes strings */
336 for (i = 0; i < actual->attr_count; i++)
338 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
339 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
340 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
341 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
345 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
346 const struct call_entry *expected, const char *context, int todo,
347 const char *file, int line)
349 struct call_sequence *call_seq = seq[sequence_index];
350 static const struct call_entry end_of_sequence = { CH_ENDTEST };
351 const struct call_entry *actual, *sequence;
354 add_call(seq, sequence_index, &end_of_sequence);
356 sequence = call_seq->sequence;
359 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
361 if (expected->id == actual->id)
363 /* always test position data */
364 if (expected->line != actual->line && todo)
369 ok_(file, line) (FALSE,
370 "%s: in event %s expecting line %d got %d\n",
371 context, get_event_name(actual->id), expected->line, actual->line);
376 ok_(file, line) (expected->line == actual->line,
377 "%s: in event %s expecting line %d got %d\n",
378 context, get_event_name(actual->id), expected->line, actual->line);
381 if (expected->column != actual->column && todo)
386 ok_(file, line) (FALSE,
387 "%s: in event %s expecting column %d got %d\n",
388 context, get_event_name(actual->id), expected->column, actual->column);
393 ok_(file, line) (expected->column == actual->column,
394 "%s: in event %s expecting column %d got %d\n",
395 context, get_event_name(actual->id), expected->column, actual->column);
400 case CH_PUTDOCUMENTLOCATOR:
401 case CH_STARTDOCUMENT:
404 case CH_STARTPREFIXMAPPING:
406 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
407 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
409 case CH_ENDPREFIXMAPPING:
411 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
413 case CH_STARTELEMENT:
414 /* compare attributes */
415 compare_attributes(actual, expected, context, todo, file, line, &failcount);
418 /* uri, localname, qname */
419 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
420 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
421 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
424 case CH_IGNORABLEWHITESPACE:
426 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
428 case CH_PROCESSINGINSTRUCTION:
430 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
431 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
433 case CH_SKIPPEDENTITY:
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
438 /* test return value only */
439 if (expected->ret != actual->ret && todo)
442 ok_(file, line) (FALSE,
443 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
444 context, get_event_name(actual->id), expected->ret, actual->ret);
447 ok_(file, line) (expected->ret == actual->ret,
448 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
449 context, get_event_name(actual->id), expected->ret, actual->ret);
452 case EG_IGNORABLEWARNING:
454 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
464 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
465 context, get_event_name(expected->id), get_event_name(actual->id));
468 flush_sequence(seq, sequence_index);
473 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
474 context, get_event_name(expected->id), get_event_name(actual->id));
484 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
487 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
488 context, get_event_name(expected->id), get_event_name(actual->id));
492 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
494 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
495 context, get_event_name(expected->id), get_event_name(actual->id));
498 if (todo && !failcount) /* succeeded yet marked todo */
502 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
506 flush_sequence(seq, sequence_index);
509 #define ok_sequence(seq, index, exp, contx, todo) \
510 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
512 static void init_call_sequences(struct call_sequence **seq, int n)
516 for (i = 0; i < n; i++)
517 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
520 static const WCHAR szSimpleXML[] = {
521 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
522 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
523 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
524 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
525 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
528 static const WCHAR carriage_ret_test[] = {
529 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
530 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
531 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
532 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
533 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
536 static const WCHAR szUtf16XML[] = {
537 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
538 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
539 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
542 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
544 static const CHAR szUtf8XML[] =
545 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
547 static const char utf8xml2[] =
548 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
550 static const CHAR testXML[] =
551 "<?xml version=\"1.0\" ?>\n"
553 " <Number>1234</Number>\n"
554 " <Name>Captain Ahab</Name>\n"
557 static const char test_attributes[] =
558 "<?xml version=\"1.0\" ?>\n"
559 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
560 "<node1 xmlns:p=\"test\" />"
563 static struct call_entry content_handler_test1[] = {
564 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
565 { CH_STARTDOCUMENT, 0, 0, S_OK },
566 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
567 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
568 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
569 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
570 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
571 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
572 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
573 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
574 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
575 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
576 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
577 { CH_ENDDOCUMENT, 0, 0, S_OK},
581 /* applies to versions 4 and 6 */
582 static struct call_entry content_handler_test1_alternate[] = {
583 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
584 { CH_STARTDOCUMENT, 1, 22, S_OK },
585 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
586 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
587 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
588 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
589 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
590 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
591 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
592 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
593 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
594 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
595 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_ENDDOCUMENT, 6, 0, S_OK },
600 static struct call_entry content_handler_test2[] = {
601 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
602 { CH_STARTDOCUMENT, 0, 0, S_OK },
603 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
604 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
605 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
606 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
607 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
608 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
609 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
610 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
611 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
612 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
613 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
614 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
615 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
616 { CH_ENDDOCUMENT, 0, 0, S_OK },
620 static struct call_entry content_handler_test2_alternate[] = {
621 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
622 { CH_STARTDOCUMENT, 1, 21, S_OK },
623 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
624 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
625 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
626 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
627 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
628 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
629 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
630 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
631 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
632 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
633 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
634 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
635 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
636 { CH_ENDDOCUMENT, 6, 0, S_OK },
640 static struct call_entry content_handler_testerror[] = {
641 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
642 { EH_FATALERROR, 0, 0, E_FAIL },
646 static struct call_entry content_handler_testerror_alternate[] = {
647 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
648 { EH_FATALERROR, 1, 0, E_FAIL },
652 static struct call_entry content_handler_test_callback_rets[] = {
653 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
654 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
655 { EH_FATALERROR, 0, 0, S_FALSE },
659 static struct call_entry content_handler_test_callback_rets_alt[] = {
660 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
661 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
662 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
663 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
664 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
665 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
666 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
667 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
668 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
669 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
670 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
671 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
672 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
673 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
677 static struct attribute_entry ch_attributes1[] = {
678 { "", "", "xmlns:test", "prefix_test" },
679 { "", "", "xmlns", "prefix" },
680 { "prefix_test", "arg1", "test:arg1", "arg1" },
681 { "", "arg2", "arg2", "arg2" },
682 { "prefix_test", "ar3", "test:ar3", "arg3" },
686 static struct attribute_entry ch_attributes2[] = {
687 { "", "", "xmlns:p", "test" },
691 static struct call_entry content_handler_test_attributes[] = {
692 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
693 { CH_STARTDOCUMENT, 0, 0, S_OK },
694 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
695 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
696 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
697 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
698 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
699 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
700 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
701 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
702 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
703 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
704 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
705 { CH_ENDDOCUMENT, 0, 0 },
709 static struct attribute_entry ch_attributes_alt_4[] = {
710 { "prefix_test", "arg1", "test:arg1", "arg1" },
711 { "", "arg2", "arg2", "arg2" },
712 { "prefix_test", "ar3", "test:ar3", "arg3" },
713 { "", "", "xmlns:test", "prefix_test" },
714 { "", "", "xmlns", "prefix" },
718 static struct call_entry content_handler_test_attributes_alternate_4[] = {
719 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
720 { CH_STARTDOCUMENT, 1, 22, S_OK },
721 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
722 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
723 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
724 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
725 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
726 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
727 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
728 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
729 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
730 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
731 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
732 { CH_ENDDOCUMENT, 4, 0, S_OK },
736 /* 'namespace' feature switched off */
737 static struct attribute_entry ch_attributes_alt_no_ns[] = {
738 { "", "", "xmlns:test", "prefix_test" },
739 { "", "", "xmlns", "prefix" },
740 { "", "", "test:arg1", "arg1" },
741 { "", "", "arg2", "arg2" },
742 { "", "", "test:ar3", "arg3" },
746 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
747 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
748 { CH_STARTDOCUMENT, 1, 22, S_OK },
749 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
750 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
751 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
752 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
753 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
754 { CH_ENDDOCUMENT, 4, 0, S_OK },
758 static struct attribute_entry ch_attributes_alt_6[] = {
759 { "prefix_test", "arg1", "test:arg1", "arg1" },
760 { "", "arg2", "arg2", "arg2" },
761 { "prefix_test", "ar3", "test:ar3", "arg3" },
762 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
763 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
767 static struct attribute_entry ch_attributes2_6[] = {
768 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
772 static struct call_entry content_handler_test_attributes_alternate_6[] = {
773 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
774 { CH_STARTDOCUMENT, 1, 22, S_OK },
775 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
776 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
777 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
778 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
779 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
780 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
781 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
782 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
783 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
784 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
785 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
786 { CH_ENDDOCUMENT, 4, 0, S_OK },
790 /* 'namespaces' is on, 'namespace-prefixes' if off */
791 static struct attribute_entry ch_attributes_no_prefix[] = {
792 { "prefix_test", "arg1", "test:arg1", "arg1" },
793 { "", "arg2", "arg2", "arg2" },
794 { "prefix_test", "ar3", "test:ar3", "arg3" },
798 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
799 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
800 { CH_STARTDOCUMENT, 1, 22, S_OK },
801 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
802 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
803 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
804 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
805 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
806 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
807 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
808 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
809 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
810 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
811 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
812 { CH_ENDDOCUMENT, 4, 0, S_OK },
816 static struct call_entry content_handler_test_attributes_no_prefix[] = {
817 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
818 { CH_STARTDOCUMENT, 0, 0, S_OK },
819 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
820 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
821 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
822 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
823 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
824 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
825 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
826 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
827 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
828 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
829 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
830 { CH_ENDDOCUMENT, 0, 0 },
834 static struct attribute_entry xmlspace_attrs[] = {
835 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
839 static struct call_entry xmlspaceattr_test[] = {
840 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
841 { CH_STARTDOCUMENT, 0, 0, S_OK },
842 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
843 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
844 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
845 { CH_ENDDOCUMENT, 0, 0, S_OK },
849 static struct call_entry xmlspaceattr_test_alternate[] = {
850 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
851 { CH_STARTDOCUMENT, 1, 39, S_OK },
852 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
853 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
854 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
855 { CH_ENDDOCUMENT, 1, 83, S_OK },
859 static const char xmlspace_attr[] =
860 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
861 "<a xml:space=\"preserve\"> Some text data </a>";
863 static struct call_entry *expectCall;
864 static ISAXLocator *locator;
865 static ISAXXMLReader *g_reader;
868 static void set_expected_seq(struct call_entry *expected)
870 expectCall = expected;
873 /* to be called once on each tested callback return */
874 static HRESULT get_expected_ret(void)
876 HRESULT hr = expectCall->ret;
877 if (expectCall->id != CH_ENDTEST) expectCall++;
881 static HRESULT WINAPI contentHandler_QueryInterface(
882 ISAXContentHandler* iface,
888 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
894 return E_NOINTERFACE;
900 static ULONG WINAPI contentHandler_AddRef(
901 ISAXContentHandler* iface)
906 static ULONG WINAPI contentHandler_Release(
907 ISAXContentHandler* iface)
912 static HRESULT WINAPI contentHandler_putDocumentLocator(
913 ISAXContentHandler* iface,
914 ISAXLocator *pLocator)
916 struct call_entry call;
921 memset(&call, 0, sizeof(call));
922 init_call_entry(locator, &call);
923 call.id = CH_PUTDOCUMENTLOCATOR;
924 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
926 if (msxml_version >= 6) {
927 ISAXAttributes *attr, *attr1;
928 IMXAttributes *mxattr;
930 EXPECT_REF(pLocator, 1);
931 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
933 EXPECT_REF(pLocator, 2);
934 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
936 EXPECT_REF(pLocator, 3);
937 ok(attr == attr1, "got %p, %p\n", attr, attr1);
939 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
940 EXPECT_HR(hr, E_NOINTERFACE);
942 ISAXAttributes_Release(attr);
943 ISAXAttributes_Release(attr1);
946 return get_expected_ret();
949 static ISAXAttributes *test_attr_ptr;
950 static HRESULT WINAPI contentHandler_startDocument(
951 ISAXContentHandler* iface)
953 struct call_entry call;
955 init_call_entry(locator, &call);
956 call.id = CH_STARTDOCUMENT;
957 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
959 test_attr_ptr = NULL;
961 return get_expected_ret();
964 static HRESULT WINAPI contentHandler_endDocument(
965 ISAXContentHandler* iface)
967 struct call_entry call;
969 init_call_entry(locator, &call);
970 call.id = CH_ENDDOCUMENT;
971 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
973 return get_expected_ret();
976 static HRESULT WINAPI contentHandler_startPrefixMapping(
977 ISAXContentHandler* iface,
978 const WCHAR *prefix, int prefix_len,
979 const WCHAR *uri, int uri_len)
981 struct call_entry call;
983 init_call_entry(locator, &call);
984 call.id = CH_STARTPREFIXMAPPING;
985 call.arg1W = SysAllocStringLen(prefix, prefix_len);
986 call.arg2W = SysAllocStringLen(uri, uri_len);
987 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
989 return get_expected_ret();
992 static HRESULT WINAPI contentHandler_endPrefixMapping(
993 ISAXContentHandler* iface,
994 const WCHAR *prefix, int len)
996 struct call_entry call;
998 init_call_entry(locator, &call);
999 call.id = CH_ENDPREFIXMAPPING;
1000 call.arg1W = SysAllocStringLen(prefix, len);
1001 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1003 return get_expected_ret();
1006 static HRESULT WINAPI contentHandler_startElement(
1007 ISAXContentHandler* iface,
1008 const WCHAR *uri, int uri_len,
1009 const WCHAR *localname, int local_len,
1010 const WCHAR *qname, int qname_len,
1011 ISAXAttributes *saxattr)
1013 struct call_entry call;
1014 IMXAttributes *mxattr;
1018 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1019 EXPECT_HR(hr, E_NOINTERFACE);
1021 init_call_entry(locator, &call);
1022 call.id = CH_STARTELEMENT;
1023 call.arg1W = SysAllocStringLen(uri, uri_len);
1024 call.arg2W = SysAllocStringLen(localname, local_len);
1025 call.arg3W = SysAllocStringLen(qname, qname_len);
1028 test_attr_ptr = saxattr;
1029 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1031 /* store actual attributes */
1033 hr = ISAXAttributes_getLength(saxattr, &len);
1034 EXPECT_HR(hr, S_OK);
1041 struct attribute_entry *attr;
1042 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1045 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1046 EXPECT_HR(hr, S_OK);
1048 for (i = 0; i < len; i++)
1053 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1054 &localname, &local_len, &qname, &qname_len);
1055 EXPECT_HR(hr, S_OK);
1057 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1058 EXPECT_HR(hr, S_OK);
1060 /* if 'namespaces' switched off uri and local name contains garbage */
1061 if (v == VARIANT_FALSE && msxml_version > 0)
1063 attr[i].uriW = SysAllocStringLen(NULL, 0);
1064 attr[i].localW = SysAllocStringLen(NULL, 0);
1068 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1069 attr[i].localW = SysAllocStringLen(localname, local_len);
1072 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1073 attr[i].valueW = SysAllocStringLen(value, value_len);
1076 call.attributes = attr;
1077 call.attr_count = len;
1080 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1082 return get_expected_ret();
1085 static HRESULT WINAPI contentHandler_endElement(
1086 ISAXContentHandler* iface,
1087 const WCHAR *uri, int uri_len,
1088 const WCHAR *localname, int local_len,
1089 const WCHAR *qname, int qname_len)
1091 struct call_entry call;
1093 init_call_entry(locator, &call);
1094 call.id = CH_ENDELEMENT;
1095 call.arg1W = SysAllocStringLen(uri, uri_len);
1096 call.arg2W = SysAllocStringLen(localname, local_len);
1097 call.arg3W = SysAllocStringLen(qname, qname_len);
1098 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1100 return get_expected_ret();
1103 static HRESULT WINAPI contentHandler_characters(
1104 ISAXContentHandler* iface,
1108 struct call_entry call;
1110 init_call_entry(locator, &call);
1111 call.id = CH_CHARACTERS;
1112 call.arg1W = SysAllocStringLen(chars, len);
1113 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1115 return get_expected_ret();
1118 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1119 ISAXContentHandler* iface,
1120 const WCHAR *chars, int len)
1122 struct call_entry call;
1124 init_call_entry(locator, &call);
1125 call.id = CH_IGNORABLEWHITESPACE;
1126 call.arg1W = SysAllocStringLen(chars, len);
1127 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1129 return get_expected_ret();
1132 static HRESULT WINAPI contentHandler_processingInstruction(
1133 ISAXContentHandler* iface,
1134 const WCHAR *target, int target_len,
1135 const WCHAR *data, int data_len)
1137 struct call_entry call;
1139 init_call_entry(locator, &call);
1140 call.id = CH_PROCESSINGINSTRUCTION;
1141 call.arg1W = SysAllocStringLen(target, target_len);
1142 call.arg2W = SysAllocStringLen(data, data_len);
1143 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1145 return get_expected_ret();
1148 static HRESULT WINAPI contentHandler_skippedEntity(
1149 ISAXContentHandler* iface,
1150 const WCHAR *name, int len)
1152 struct call_entry call;
1154 init_call_entry(locator, &call);
1155 call.id = CH_SKIPPEDENTITY;
1156 call.arg1W = SysAllocStringLen(name, len);
1158 return get_expected_ret();
1161 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1163 contentHandler_QueryInterface,
1164 contentHandler_AddRef,
1165 contentHandler_Release,
1166 contentHandler_putDocumentLocator,
1167 contentHandler_startDocument,
1168 contentHandler_endDocument,
1169 contentHandler_startPrefixMapping,
1170 contentHandler_endPrefixMapping,
1171 contentHandler_startElement,
1172 contentHandler_endElement,
1173 contentHandler_characters,
1174 contentHandler_ignorableWhitespace,
1175 contentHandler_processingInstruction,
1176 contentHandler_skippedEntity
1179 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1181 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1182 ISAXErrorHandler* iface,
1188 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1194 return E_NOINTERFACE;
1200 static ULONG WINAPI isaxerrorHandler_AddRef(
1201 ISAXErrorHandler* iface)
1206 static ULONG WINAPI isaxerrorHandler_Release(
1207 ISAXErrorHandler* iface)
1212 static HRESULT WINAPI isaxerrorHandler_error(
1213 ISAXErrorHandler* iface,
1214 ISAXLocator *pLocator,
1215 const WCHAR *pErrorMessage,
1216 HRESULT hrErrorCode)
1218 ok(0, "unexpected call\n");
1222 static HRESULT WINAPI isaxerrorHandler_fatalError(
1223 ISAXErrorHandler* iface,
1224 ISAXLocator *pLocator,
1225 const WCHAR *message,
1228 struct call_entry call;
1230 init_call_entry(locator, &call);
1231 call.id = EH_FATALERROR;
1234 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1240 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1241 ISAXErrorHandler* iface,
1242 ISAXLocator *pLocator,
1243 const WCHAR *pErrorMessage,
1244 HRESULT hrErrorCode)
1246 ok(0, "unexpected call\n");
1250 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1252 isaxerrorHandler_QueryInterface,
1253 isaxerrorHandler_AddRef,
1254 isaxerrorHandler_Release,
1255 isaxerrorHandler_error,
1256 isaxerrorHandler_fatalError,
1257 isaxerrorHanddler_ignorableWarning
1260 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1262 static HRESULT WINAPI isaxattributes_QueryInterface(
1263 ISAXAttributes* iface,
1269 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1275 return E_NOINTERFACE;
1281 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1286 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1291 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1297 static HRESULT WINAPI isaxattributes_getURI(
1298 ISAXAttributes* iface,
1303 ok(0, "unexpected call\n");
1307 static HRESULT WINAPI isaxattributes_getLocalName(
1308 ISAXAttributes* iface,
1310 const WCHAR **pLocalName,
1311 int *pLocalNameLength)
1313 ok(0, "unexpected call\n");
1317 static HRESULT WINAPI isaxattributes_getQName(
1318 ISAXAttributes* iface,
1320 const WCHAR **QName,
1323 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1324 {'a','t','t','r','2','j','u','n','k',0},
1325 {'a','t','t','r','3',0}};
1326 static const int attrqnamelen[] = {7, 5, 5};
1328 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1330 *QName = attrqnamesW[index];
1331 *QNameLength = attrqnamelen[index];
1336 static HRESULT WINAPI isaxattributes_getName(
1337 ISAXAttributes* iface,
1341 const WCHAR ** pLocalName,
1342 int * pLocalNameSize,
1343 const WCHAR ** pQName,
1346 ok(0, "unexpected call\n");
1350 static HRESULT WINAPI isaxattributes_getIndexFromName(
1351 ISAXAttributes* iface,
1354 const WCHAR * pLocalName,
1355 int cocalNameLength,
1358 ok(0, "unexpected call\n");
1362 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1363 ISAXAttributes* iface,
1364 const WCHAR * pQName,
1368 ok(0, "unexpected call\n");
1372 static HRESULT WINAPI isaxattributes_getType(
1373 ISAXAttributes* iface,
1375 const WCHAR ** pType,
1378 ok(0, "unexpected call\n");
1382 static HRESULT WINAPI isaxattributes_getTypeFromName(
1383 ISAXAttributes* iface,
1386 const WCHAR * pLocalName,
1388 const WCHAR ** pType,
1391 ok(0, "unexpected call\n");
1395 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1396 ISAXAttributes* iface,
1397 const WCHAR * pQName,
1399 const WCHAR ** pType,
1402 ok(0, "unexpected call\n");
1406 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1407 const WCHAR **value, int *nValue)
1409 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1410 {'a','2','j','u','n','k',0},
1411 {'<','&','"','>',0}};
1412 static const int attrvalueslen[] = {2, 2, 4};
1414 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1416 *value = attrvaluesW[index];
1417 *nValue = attrvalueslen[index];
1422 static HRESULT WINAPI isaxattributes_getValueFromName(
1423 ISAXAttributes* iface,
1426 const WCHAR * pLocalName,
1428 const WCHAR ** pValue,
1431 ok(0, "unexpected call\n");
1435 static HRESULT WINAPI isaxattributes_getValueFromQName(
1436 ISAXAttributes* iface,
1437 const WCHAR * pQName,
1439 const WCHAR ** pValue,
1442 ok(0, "unexpected call\n");
1446 static const ISAXAttributesVtbl SAXAttributesVtbl =
1448 isaxattributes_QueryInterface,
1449 isaxattributes_AddRef,
1450 isaxattributes_Release,
1451 isaxattributes_getLength,
1452 isaxattributes_getURI,
1453 isaxattributes_getLocalName,
1454 isaxattributes_getQName,
1455 isaxattributes_getName,
1456 isaxattributes_getIndexFromName,
1457 isaxattributes_getIndexFromQName,
1458 isaxattributes_getType,
1459 isaxattributes_getTypeFromName,
1460 isaxattributes_getTypeFromQName,
1461 isaxattributes_getValue,
1462 isaxattributes_getValueFromName,
1463 isaxattributes_getValueFromQName
1466 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1468 static int handler_addrefcalled;
1470 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **ppvObject)
1474 if(IsEqualGUID(riid, &IID_IUnknown) ||
1475 IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1481 return E_NOINTERFACE;
1487 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1489 handler_addrefcalled++;
1493 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1498 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1499 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1500 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1502 ok(0, "call not expected\n");
1506 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1508 ok(0, "call not expected\n");
1512 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1513 const WCHAR * pName, int nName)
1515 ok(0, "call not expected\n");
1519 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1520 const WCHAR * pName, int nName)
1522 ok(0, "call not expected\n");
1526 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1528 ok(0, "call not expected\n");
1532 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1534 ok(0, "call not expected\n");
1538 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1539 const WCHAR * pChars, int nChars)
1541 ok(0, "call not expected\n");
1545 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1547 isaxlexical_QueryInterface,
1549 isaxlexical_Release,
1550 isaxlexical_startDTD,
1552 isaxlexical_startEntity,
1553 isaxlexical_endEntity,
1554 isaxlexical_startCDATA,
1555 isaxlexical_endCDATA,
1559 static ISAXLexicalHandler saxlexicalhandler = { &SAXLexicalHandlerVtbl };
1561 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **ppvObject)
1565 if(IsEqualGUID(riid, &IID_IUnknown) ||
1566 IsEqualGUID(riid, &IID_ISAXDeclHandler))
1572 return E_NOINTERFACE;
1578 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1580 handler_addrefcalled++;
1584 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1589 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1590 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1592 ok(0, "call not expected\n");
1596 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1597 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1598 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1599 int nValueDefault, const WCHAR * pValue, int nValue)
1601 ok(0, "call not expected\n");
1605 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1606 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1608 ok(0, "call not expected\n");
1612 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1613 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1614 const WCHAR * pSystemId, int nSystemId)
1616 ok(0, "call not expected\n");
1620 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1622 isaxdecl_QueryInterface,
1625 isaxdecl_elementDecl,
1626 isaxdecl_attributeDecl,
1627 isaxdecl_internalEntityDecl,
1628 isaxdecl_externalEntityDecl
1631 static ISAXDeclHandler saxdeclhandler = { &SAXDeclHandlerVtbl };
1633 typedef struct mxwriter_write_test_t {
1639 } mxwriter_write_test;
1641 typedef struct mxwriter_stream_test_t {
1643 const char *encoding;
1644 mxwriter_write_test expected_writes[4];
1645 } mxwriter_stream_test;
1647 static const mxwriter_write_test *current_write_test;
1648 static DWORD current_stream_test_index;
1650 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1654 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1657 return E_NOINTERFACE;
1662 static ULONG WINAPI istream_AddRef(IStream *iface)
1667 static ULONG WINAPI istream_Release(IStream *iface)
1672 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1674 ok(0, "unexpected call\n");
1678 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1682 ok(pv != NULL, "pv == NULL\n");
1684 if(current_write_test->last) {
1685 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1689 fail = current_write_test->fail_write;
1691 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1692 current_write_test->cb, cb, current_stream_test_index);
1695 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1697 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1699 ++current_write_test;
1704 return fail ? E_FAIL : S_OK;
1707 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1708 ULARGE_INTEGER *plibNewPosition)
1710 ok(0, "unexpected call\n");
1714 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1716 ok(0, "unexpected call\n");
1720 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1721 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1723 ok(0, "unexpected call\n");
1727 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1729 ok(0, "unexpected call\n");
1733 static HRESULT WINAPI istream_Revert(IStream *iface)
1735 ok(0, "unexpected call\n");
1739 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1740 ULARGE_INTEGER cb, DWORD dwLockType)
1742 ok(0, "unexpected call\n");
1746 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1747 ULARGE_INTEGER cb, DWORD dwLockType)
1749 ok(0, "unexpected call\n");
1753 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1755 ok(0, "unexpected call\n");
1759 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1761 ok(0, "unexpected call\n");
1765 static const IStreamVtbl StreamVtbl = {
1766 istream_QueryInterface,
1777 istream_UnlockRegion,
1782 static IStream mxstream = { &StreamVtbl };
1784 static struct msxmlsupported_data_t reader_support_data[] =
1786 { &CLSID_SAXXMLReader, "SAXReader" },
1787 { &CLSID_SAXXMLReader30, "SAXReader30" },
1788 { &CLSID_SAXXMLReader40, "SAXReader40" },
1789 { &CLSID_SAXXMLReader60, "SAXReader60" },
1793 static void test_saxreader(void)
1795 const struct msxmlsupported_data_t *table = reader_support_data;
1797 ISAXXMLReader *reader = NULL;
1799 ISAXContentHandler *content;
1800 ISAXErrorHandler *lpErrorHandler;
1802 SAFEARRAYBOUND SADim[1];
1805 ULARGE_INTEGER size;
1809 static const CHAR testXmlA[] = "test.xml";
1810 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1811 IXMLDOMDocument *doc;
1814 while (table->clsid)
1816 struct call_entry *test_seq;
1819 if (!is_clsid_supported(table->clsid, reader_support_data))
1825 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1826 EXPECT_HR(hr, S_OK);
1829 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1831 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1836 /* crashes on old versions */
1837 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1838 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1840 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1841 EXPECT_HR(hr, E_POINTER);
1843 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1844 EXPECT_HR(hr, E_POINTER);
1847 hr = ISAXXMLReader_getContentHandler(reader, &content);
1848 EXPECT_HR(hr, S_OK);
1849 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1851 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1852 EXPECT_HR(hr, S_OK);
1853 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1855 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1856 EXPECT_HR(hr, S_OK);
1858 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1859 EXPECT_HR(hr, S_OK);
1861 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1862 EXPECT_HR(hr, S_OK);
1864 hr = ISAXXMLReader_getContentHandler(reader, &content);
1865 EXPECT_HR(hr, S_OK);
1866 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1868 V_VT(&var) = VT_BSTR;
1869 V_BSTR(&var) = SysAllocString(szSimpleXML);
1871 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1872 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1873 test_seq = content_handler_test1_alternate;
1875 test_seq = content_handler_test1;
1876 set_expected_seq(test_seq);
1877 hr = ISAXXMLReader_parse(reader, var);
1878 EXPECT_HR(hr, S_OK);
1879 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1883 SADim[0].lLbound = 0;
1884 SADim[0].cElements = sizeof(testXML)-1;
1885 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1886 SafeArrayAccessData(sa, (void**)&ptr);
1887 memcpy(ptr, testXML, sizeof(testXML)-1);
1888 SafeArrayUnaccessData(sa);
1889 V_VT(&var) = VT_ARRAY|VT_UI1;
1892 set_expected_seq(test_seq);
1893 hr = ISAXXMLReader_parse(reader, var);
1894 EXPECT_HR(hr, S_OK);
1895 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1897 SafeArrayDestroy(sa);
1899 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1900 size.QuadPart = strlen(testXML);
1901 IStream_SetSize(stream, size);
1902 IStream_Write(stream, testXML, strlen(testXML), &written);
1904 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1905 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1906 V_UNKNOWN(&var) = (IUnknown*)stream;
1908 set_expected_seq(test_seq);
1909 hr = ISAXXMLReader_parse(reader, var);
1910 EXPECT_HR(hr, S_OK);
1911 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
1913 IStream_Release(stream);
1915 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1916 size.QuadPart = strlen(test_attributes);
1917 IStream_SetSize(stream, size);
1918 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
1920 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1921 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1922 V_UNKNOWN(&var) = (IUnknown*)stream;
1924 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1925 test_seq = content_handler_test_attributes_alternate_4;
1926 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1927 test_seq = content_handler_test_attributes_alternate_6;
1929 test_seq = content_handler_test_attributes;
1931 set_expected_seq(test_seq);
1932 hr = ISAXXMLReader_parse(reader, var);
1933 EXPECT_HR(hr, S_OK);
1935 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1936 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1937 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
1939 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
1941 IStream_Release(stream);
1943 V_VT(&var) = VT_BSTR;
1944 V_BSTR(&var) = SysAllocString(carriage_ret_test);
1946 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1947 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1948 test_seq = content_handler_test2_alternate;
1950 test_seq = content_handler_test2;
1952 set_expected_seq(test_seq);
1953 hr = ISAXXMLReader_parse(reader, var);
1954 EXPECT_HR(hr, S_OK);
1955 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
1960 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1961 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
1962 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
1965 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1966 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1967 test_seq = content_handler_test1_alternate;
1969 test_seq = content_handler_test1;
1970 set_expected_seq(test_seq);
1971 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1972 EXPECT_HR(hr, S_OK);
1973 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
1976 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1977 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1978 test_seq = content_handler_testerror_alternate;
1980 test_seq = content_handler_testerror;
1981 set_expected_seq(test_seq);
1982 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1983 EXPECT_HR(hr, E_FAIL);
1984 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
1986 /* callback ret values */
1987 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1988 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1990 test_seq = content_handler_test_callback_rets_alt;
1991 set_expected_seq(test_seq);
1992 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1993 EXPECT_HR(hr, S_OK);
1997 test_seq = content_handler_test_callback_rets;
1998 set_expected_seq(test_seq);
1999 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2000 EXPECT_HR(hr, S_FALSE);
2002 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2004 DeleteFileA(testXmlA);
2006 /* parse from IXMLDOMDocument */
2007 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2008 &IID_IXMLDOMDocument, (void**)&doc);
2009 EXPECT_HR(hr, S_OK);
2011 str = SysAllocString(szSimpleXML);
2012 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2013 EXPECT_HR(hr, S_OK);
2016 V_VT(&var) = VT_UNKNOWN;
2017 V_UNKNOWN(&var) = (IUnknown*)doc;
2019 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2020 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2021 test_seq = content_handler_test2_alternate;
2023 test_seq = content_handler_test2;
2025 set_expected_seq(test_seq);
2026 hr = ISAXXMLReader_parse(reader, var);
2027 EXPECT_HR(hr, S_OK);
2028 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2029 IXMLDOMDocument_Release(doc);
2031 /* xml:space test */
2032 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2033 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2035 test_seq = xmlspaceattr_test_alternate;
2038 test_seq = xmlspaceattr_test;
2040 set_expected_seq(test_seq);
2041 V_VT(&var) = VT_BSTR;
2042 V_BSTR(&var) = _bstr_(xmlspace_attr);
2043 hr = ISAXXMLReader_parse(reader, var);
2044 EXPECT_HR(hr, S_OK);
2046 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2047 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2049 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2052 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2054 /* switch off 'namespaces' feature */
2055 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2056 EXPECT_HR(hr, S_OK);
2058 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2059 size.QuadPart = strlen(test_attributes);
2060 IStream_SetSize(stream, size);
2061 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2063 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2064 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
2065 V_UNKNOWN(&var) = (IUnknown*)stream;
2067 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2068 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2070 test_seq = content_handler_test_attributes_alt_no_ns;
2073 test_seq = content_handler_test_attributes;
2075 set_expected_seq(test_seq);
2076 hr = ISAXXMLReader_parse(reader, var);
2077 EXPECT_HR(hr, S_OK);
2078 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2079 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2080 EXPECT_HR(hr, S_OK);
2082 /* switch off 'namespace-prefixes' feature */
2083 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2084 EXPECT_HR(hr, S_OK);
2086 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2087 size.QuadPart = strlen(test_attributes);
2088 IStream_SetSize(stream, size);
2089 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2091 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2092 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
2093 V_UNKNOWN(&var) = (IUnknown*)stream;
2095 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2096 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2098 test_seq = content_handler_test_attributes_alt_no_prefix;
2101 test_seq = content_handler_test_attributes_no_prefix;
2103 set_expected_seq(test_seq);
2104 hr = ISAXXMLReader_parse(reader, var);
2105 EXPECT_HR(hr, S_OK);
2106 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2108 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2109 EXPECT_HR(hr, S_OK);
2111 ISAXXMLReader_Release(reader);
2118 struct saxreader_props_test_t
2120 const char *prop_name;
2124 static const struct saxreader_props_test_t props_test_data[] = {
2125 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&saxlexicalhandler },
2126 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&saxdeclhandler },
2130 static void test_saxreader_properties(void)
2132 const struct saxreader_props_test_t *ptr = props_test_data;
2133 ISAXXMLReader *reader;
2136 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2137 &IID_ISAXXMLReader, (void**)&reader);
2138 EXPECT_HR(hr, S_OK);
2140 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2141 EXPECT_HR(hr, E_POINTER);
2143 while (ptr->prop_name)
2147 V_VT(&v) = VT_EMPTY;
2148 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2149 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2150 EXPECT_HR(hr, S_OK);
2151 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2152 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2154 V_VT(&v) = VT_UNKNOWN;
2155 V_UNKNOWN(&v) = ptr->iface;
2156 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2157 EXPECT_HR(hr, S_OK);
2159 V_VT(&v) = VT_EMPTY;
2160 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2161 handler_addrefcalled = 0;
2162 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2163 EXPECT_HR(hr, S_OK);
2164 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2165 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2166 ok(handler_addrefcalled == 1, "AddRef called %d times\n", handler_addrefcalled);
2169 V_VT(&v) = VT_EMPTY;
2170 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2171 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2172 EXPECT_HR(hr, S_OK);
2174 V_VT(&v) = VT_EMPTY;
2175 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2176 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2177 EXPECT_HR(hr, S_OK);
2178 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2179 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2181 V_VT(&v) = VT_UNKNOWN;
2182 V_UNKNOWN(&v) = ptr->iface;
2183 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2184 EXPECT_HR(hr, S_OK);
2186 /* only VT_EMPTY seems to be valid to reset property */
2188 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2189 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2190 EXPECT_HR(hr, E_INVALIDARG);
2192 V_VT(&v) = VT_EMPTY;
2193 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2194 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2195 EXPECT_HR(hr, S_OK);
2196 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2197 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2200 V_VT(&v) = VT_UNKNOWN;
2201 V_UNKNOWN(&v) = NULL;
2202 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2203 EXPECT_HR(hr, S_OK);
2205 V_VT(&v) = VT_EMPTY;
2206 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2207 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2208 EXPECT_HR(hr, S_OK);
2209 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2210 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2215 ISAXXMLReader_Release(reader);
2219 struct feature_ns_entry_t {
2223 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2226 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2227 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2228 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2229 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2230 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2234 static const char *feature_names[] = {
2235 "http://xml.org/sax/features/namespaces",
2236 "http://xml.org/sax/features/namespace-prefixes",
2240 static void test_saxreader_features(void)
2242 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2243 ISAXXMLReader *reader;
2251 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2254 win_skip("can't create %s instance\n", entry->clsid);
2259 name = feature_names;
2263 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2264 EXPECT_HR(hr, S_OK);
2265 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2268 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2269 EXPECT_HR(hr, S_OK);
2272 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2273 EXPECT_HR(hr, S_OK);
2274 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2276 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2277 EXPECT_HR(hr, S_OK);
2279 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2280 EXPECT_HR(hr, S_OK);
2281 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2283 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2284 EXPECT_HR(hr, S_OK);
2286 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2287 EXPECT_HR(hr, S_OK);
2288 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2293 ISAXXMLReader_Release(reader);
2299 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2300 static const CHAR UTF8BOMTest[] =
2301 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2304 struct enc_test_entry_t {
2312 static const struct enc_test_entry_t encoding_test_data[] = {
2313 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2314 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2315 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2316 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2320 static void test_saxreader_encoding(void)
2322 const struct enc_test_entry_t *entry = encoding_test_data;
2323 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2324 static const CHAR testXmlA[] = "test.xml";
2328 ISAXXMLReader *reader;
2334 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2337 win_skip("can't create %s instance\n", entry->clsid);
2342 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2343 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2344 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2347 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2349 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2351 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2353 DeleteFileA(testXmlA);
2355 /* try BSTR input with no BOM or '<?xml' instruction */
2356 V_VT(&input) = VT_BSTR;
2357 V_BSTR(&input) = _bstr_("<element></element>");
2358 hr = ISAXXMLReader_parse(reader, input);
2359 EXPECT_HR(hr, S_OK);
2361 ISAXXMLReader_Release(reader);
2368 static void test_mxwriter_handlers(void)
2370 ISAXContentHandler *handler;
2371 IMXWriter *writer, *writer2;
2372 ISAXDeclHandler *decl;
2373 ISAXLexicalHandler *lh;
2376 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2377 &IID_IMXWriter, (void**)&writer);
2378 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2380 EXPECT_REF(writer, 1);
2382 /* ISAXContentHandler */
2383 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2384 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2385 EXPECT_REF(writer, 2);
2386 EXPECT_REF(handler, 2);
2388 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2389 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2390 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2391 EXPECT_REF(writer, 3);
2392 EXPECT_REF(writer2, 3);
2393 IMXWriter_Release(writer2);
2394 ISAXContentHandler_Release(handler);
2396 /* ISAXLexicalHandler */
2397 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2398 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2399 EXPECT_REF(writer, 2);
2402 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2403 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2404 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2405 EXPECT_REF(writer, 3);
2406 EXPECT_REF(writer2, 3);
2407 IMXWriter_Release(writer2);
2408 ISAXLexicalHandler_Release(lh);
2410 /* ISAXDeclHandler */
2411 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2412 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2413 EXPECT_REF(writer, 2);
2416 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2417 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2418 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2419 EXPECT_REF(writer, 3);
2420 EXPECT_REF(writer2, 3);
2421 IMXWriter_Release(writer2);
2422 ISAXDeclHandler_Release(decl);
2424 IMXWriter_Release(writer);
2428 static struct msxmlsupported_data_t mxwriter_support_data[] =
2430 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2431 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2432 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2433 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2437 static struct msxmlsupported_data_t mxattributes_support_data[] =
2439 { &CLSID_SAXAttributes, "SAXAttributes" },
2440 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2441 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2442 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2446 struct mxwriter_props_t
2450 VARIANT_BOOL disable_escape;
2451 VARIANT_BOOL indent;
2452 VARIANT_BOOL omitdecl;
2453 VARIANT_BOOL standalone;
2454 const char *encoding;
2457 static const struct mxwriter_props_t mxwriter_default_props[] =
2459 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2460 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2461 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2462 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2466 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2470 while (table->clsid)
2477 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2484 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2485 &IID_IMXWriter, (void**)&writer);
2486 EXPECT_HR(hr, S_OK);
2489 hr = IMXWriter_get_byteOrderMark(writer, &b);
2490 EXPECT_HR(hr, S_OK);
2491 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2493 b = !table->disable_escape;
2494 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2495 EXPECT_HR(hr, S_OK);
2496 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2497 table->disable_escape);
2500 hr = IMXWriter_get_indent(writer, &b);
2501 EXPECT_HR(hr, S_OK);
2502 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2504 b = !table->omitdecl;
2505 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2506 EXPECT_HR(hr, S_OK);
2507 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2509 b = !table->standalone;
2510 hr = IMXWriter_get_standalone(writer, &b);
2511 EXPECT_HR(hr, S_OK);
2512 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2514 hr = IMXWriter_get_encoding(writer, &encoding);
2515 EXPECT_HR(hr, S_OK);
2516 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2517 i, wine_dbgstr_w(encoding), table->encoding);
2518 SysFreeString(encoding);
2520 IMXWriter_Release(writer);
2527 static void test_mxwriter_properties(void)
2529 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2530 static const WCHAR emptyW[] = {0};
2531 static const WCHAR testW[] = {'t','e','s','t',0};
2532 ISAXContentHandler *content;
2539 test_mxwriter_default_properties(mxwriter_default_props);
2541 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2542 &IID_IMXWriter, (void**)&writer);
2543 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2545 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2546 ok(hr == E_POINTER, "got %08x\n", hr);
2548 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2549 ok(hr == E_POINTER, "got %08x\n", hr);
2551 hr = IMXWriter_get_indent(writer, NULL);
2552 ok(hr == E_POINTER, "got %08x\n", hr);
2554 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2555 ok(hr == E_POINTER, "got %08x\n", hr);
2557 hr = IMXWriter_get_standalone(writer, NULL);
2558 ok(hr == E_POINTER, "got %08x\n", hr);
2561 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2562 ok(hr == S_OK, "got %08x\n", hr);
2565 hr = IMXWriter_get_standalone(writer, &b);
2566 ok(hr == S_OK, "got %08x\n", hr);
2567 ok(b == VARIANT_TRUE, "got %d\n", b);
2569 hr = IMXWriter_get_encoding(writer, NULL);
2570 EXPECT_HR(hr, E_POINTER);
2572 /* UTF-16 is a default setting apparently */
2573 str = (void*)0xdeadbeef;
2574 hr = IMXWriter_get_encoding(writer, &str);
2575 EXPECT_HR(hr, S_OK);
2576 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2578 str2 = (void*)0xdeadbeef;
2579 hr = IMXWriter_get_encoding(writer, &str2);
2580 ok(hr == S_OK, "got %08x\n", hr);
2581 ok(str != str2, "expected newly allocated, got same %p\n", str);
2583 SysFreeString(str2);
2586 /* put empty string */
2587 str = SysAllocString(emptyW);
2588 hr = IMXWriter_put_encoding(writer, str);
2589 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2592 str = (void*)0xdeadbeef;
2593 hr = IMXWriter_get_encoding(writer, &str);
2594 EXPECT_HR(hr, S_OK);
2595 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2598 /* invalid encoding name */
2599 str = SysAllocString(testW);
2600 hr = IMXWriter_put_encoding(writer, str);
2601 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2604 /* test case sensivity */
2605 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2606 EXPECT_HR(hr, S_OK);
2607 str = (void*)0xdeadbeef;
2608 hr = IMXWriter_get_encoding(writer, &str);
2609 EXPECT_HR(hr, S_OK);
2610 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2613 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2614 EXPECT_HR(hr, S_OK);
2615 str = (void*)0xdeadbeef;
2616 hr = IMXWriter_get_encoding(writer, &str);
2617 EXPECT_HR(hr, S_OK);
2618 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2621 /* how it affects document creation */
2622 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2623 EXPECT_HR(hr, S_OK);
2625 hr = ISAXContentHandler_startDocument(content);
2626 EXPECT_HR(hr, S_OK);
2627 hr = ISAXContentHandler_endDocument(content);
2628 EXPECT_HR(hr, S_OK);
2630 V_VT(&dest) = VT_EMPTY;
2631 hr = IMXWriter_get_output(writer, &dest);
2632 EXPECT_HR(hr, S_OK);
2633 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2634 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2635 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2636 VariantClear(&dest);
2637 ISAXContentHandler_Release(content);
2639 hr = IMXWriter_get_version(writer, NULL);
2640 ok(hr == E_POINTER, "got %08x\n", hr);
2641 /* default version is 'surprisingly' 1.0 */
2642 hr = IMXWriter_get_version(writer, &str);
2643 ok(hr == S_OK, "got %08x\n", hr);
2644 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2647 /* store version string as is */
2648 hr = IMXWriter_put_version(writer, NULL);
2649 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2651 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2652 ok(hr == S_OK, "got %08x\n", hr);
2654 hr = IMXWriter_put_version(writer, _bstr_(""));
2655 ok(hr == S_OK, "got %08x\n", hr);
2656 hr = IMXWriter_get_version(writer, &str);
2657 ok(hr == S_OK, "got %08x\n", hr);
2658 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2661 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2662 ok(hr == S_OK, "got %08x\n", hr);
2663 hr = IMXWriter_get_version(writer, &str);
2664 ok(hr == S_OK, "got %08x\n", hr);
2665 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2668 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2669 ok(hr == S_OK, "got %08x\n", hr);
2670 hr = IMXWriter_get_version(writer, &str);
2671 ok(hr == S_OK, "got %08x\n", hr);
2672 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2675 IMXWriter_Release(writer);
2679 static void test_mxwriter_flush(void)
2681 ISAXContentHandler *content;
2684 ULARGE_INTEGER pos2;
2689 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2690 &IID_IMXWriter, (void**)&writer);
2691 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2693 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2694 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2695 EXPECT_REF(stream, 1);
2697 /* detach when nothing was attached */
2698 V_VT(&dest) = VT_EMPTY;
2699 hr = IMXWriter_put_output(writer, dest);
2700 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2703 V_VT(&dest) = VT_UNKNOWN;
2704 V_UNKNOWN(&dest) = (IUnknown*)stream;
2705 hr = IMXWriter_put_output(writer, dest);
2706 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2707 todo_wine EXPECT_REF(stream, 3);
2709 /* detach setting VT_EMPTY destination */
2710 V_VT(&dest) = VT_EMPTY;
2711 hr = IMXWriter_put_output(writer, dest);
2712 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2713 EXPECT_REF(stream, 1);
2715 V_VT(&dest) = VT_UNKNOWN;
2716 V_UNKNOWN(&dest) = (IUnknown*)stream;
2717 hr = IMXWriter_put_output(writer, dest);
2718 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2720 /* flush() doesn't detach a stream */
2721 hr = IMXWriter_flush(writer);
2722 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2723 todo_wine EXPECT_REF(stream, 3);
2726 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2727 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2728 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2730 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2731 ok(hr == S_OK, "got %08x\n", hr);
2733 hr = ISAXContentHandler_startDocument(content);
2734 ok(hr == S_OK, "got %08x\n", hr);
2737 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2738 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2739 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2741 /* already started */
2742 hr = ISAXContentHandler_startDocument(content);
2743 ok(hr == S_OK, "got %08x\n", hr);
2745 hr = ISAXContentHandler_endDocument(content);
2746 ok(hr == S_OK, "got %08x\n", hr);
2748 /* flushed on endDocument() */
2750 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2751 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2752 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2754 ISAXContentHandler_Release(content);
2755 IStream_Release(stream);
2756 IMXWriter_Release(writer);
2759 static void test_mxwriter_startenddocument(void)
2761 ISAXContentHandler *content;
2766 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2767 &IID_IMXWriter, (void**)&writer);
2768 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2770 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2771 ok(hr == S_OK, "got %08x\n", hr);
2773 hr = ISAXContentHandler_startDocument(content);
2774 ok(hr == S_OK, "got %08x\n", hr);
2776 hr = ISAXContentHandler_endDocument(content);
2777 ok(hr == S_OK, "got %08x\n", hr);
2779 V_VT(&dest) = VT_EMPTY;
2780 hr = IMXWriter_get_output(writer, &dest);
2781 ok(hr == S_OK, "got %08x\n", hr);
2782 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2783 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2784 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2785 VariantClear(&dest);
2787 /* now try another startDocument */
2788 hr = ISAXContentHandler_startDocument(content);
2789 ok(hr == S_OK, "got %08x\n", hr);
2790 /* and get duplicated prolog */
2791 V_VT(&dest) = VT_EMPTY;
2792 hr = IMXWriter_get_output(writer, &dest);
2793 ok(hr == S_OK, "got %08x\n", hr);
2794 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2795 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
2796 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2797 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2798 VariantClear(&dest);
2800 ISAXContentHandler_Release(content);
2801 IMXWriter_Release(writer);
2803 /* now with omitted declaration */
2804 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2805 &IID_IMXWriter, (void**)&writer);
2806 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2808 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2809 ok(hr == S_OK, "got %08x\n", hr);
2811 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2812 ok(hr == S_OK, "got %08x\n", hr);
2814 hr = ISAXContentHandler_startDocument(content);
2815 ok(hr == S_OK, "got %08x\n", hr);
2817 hr = ISAXContentHandler_endDocument(content);
2818 ok(hr == S_OK, "got %08x\n", hr);
2820 V_VT(&dest) = VT_EMPTY;
2821 hr = IMXWriter_get_output(writer, &dest);
2822 ok(hr == S_OK, "got %08x\n", hr);
2823 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2824 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2825 VariantClear(&dest);
2827 ISAXContentHandler_Release(content);
2828 IMXWriter_Release(writer);
2840 struct writer_startendelement_t {
2842 enum startendtype type;
2844 const char *local_name;
2848 ISAXAttributes *attr;
2851 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\">";
2852 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\"/>";
2854 static const struct writer_startendelement_t writer_startendelement[] = {
2856 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2857 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2858 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2859 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
2860 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2862 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2863 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2864 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
2865 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2866 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2868 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2869 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
2870 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2871 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2872 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2874 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
2875 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2876 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2877 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2878 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2880 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2881 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2882 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2883 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
2884 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2886 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2887 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2888 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2889 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2890 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2892 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2893 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2894 /* endElement tests */
2895 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2896 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2897 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2899 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
2900 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2901 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2902 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2903 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
2905 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2906 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2907 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2908 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
2909 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2911 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2912 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2913 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
2914 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2915 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2917 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2918 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2919 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2920 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2921 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2923 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
2924 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2925 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2926 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2927 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2929 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2930 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2931 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2932 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2934 /* with attributes */
2935 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2937 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2938 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2939 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2940 /* empty elements */
2941 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2942 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2944 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2945 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2946 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
2947 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
2948 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
2950 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
2954 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
2956 while (table->clsid)
2961 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
2962 if (hr == S_OK) IUnknown_Release(unk);
2964 table->supported = hr == S_OK;
2965 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
2971 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
2975 while (table->clsid)
2977 ISAXContentHandler *content;
2981 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2988 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2989 &IID_IMXWriter, (void**)&writer);
2990 EXPECT_HR(hr, S_OK);
2992 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2993 EXPECT_HR(hr, S_OK);
2995 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2996 EXPECT_HR(hr, S_OK);
2998 hr = ISAXContentHandler_startDocument(content);
2999 EXPECT_HR(hr, S_OK);
3001 if (table->type == StartElement)
3003 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3004 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3005 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3007 else if (table->type == EndElement)
3009 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3010 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3011 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3015 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3016 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3017 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3018 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3019 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3020 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3028 V_VT(&dest) = VT_EMPTY;
3029 hr = IMXWriter_get_output(writer, &dest);
3030 EXPECT_HR(hr, S_OK);
3031 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3032 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3033 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3034 VariantClear(&dest);
3037 ISAXContentHandler_Release(content);
3038 IMXWriter_Release(writer);
3047 static void test_mxwriter_startendelement(void)
3049 ISAXContentHandler *content;
3054 test_mxwriter_startendelement_batch(writer_startendelement);
3056 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3057 &IID_IMXWriter, (void**)&writer);
3058 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3060 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3061 ok(hr == S_OK, "got %08x\n", hr);
3063 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3064 ok(hr == S_OK, "got %08x\n", hr);
3066 hr = ISAXContentHandler_startDocument(content);
3067 ok(hr == S_OK, "got %08x\n", hr);
3069 /* all string pointers should be not null */
3070 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3071 ok(hr == S_OK, "got %08x\n", hr);
3073 V_VT(&dest) = VT_EMPTY;
3074 hr = IMXWriter_get_output(writer, &dest);
3075 ok(hr == S_OK, "got %08x\n", hr);
3076 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3077 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3078 VariantClear(&dest);
3080 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3081 ok(hr == S_OK, "got %08x\n", hr);
3083 V_VT(&dest) = VT_EMPTY;
3084 hr = IMXWriter_get_output(writer, &dest);
3085 ok(hr == S_OK, "got %08x\n", hr);
3086 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3087 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3088 VariantClear(&dest);
3090 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3091 EXPECT_HR(hr, E_INVALIDARG);
3093 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3094 EXPECT_HR(hr, E_INVALIDARG);
3096 /* only local name is an error too */
3097 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3098 EXPECT_HR(hr, E_INVALIDARG);
3100 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3101 EXPECT_HR(hr, S_OK);
3103 V_VT(&dest) = VT_EMPTY;
3104 hr = IMXWriter_get_output(writer, &dest);
3105 EXPECT_HR(hr, S_OK);
3106 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3107 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3108 VariantClear(&dest);
3110 hr = ISAXContentHandler_endDocument(content);
3111 EXPECT_HR(hr, S_OK);
3113 V_VT(&dest) = VT_EMPTY;
3114 hr = IMXWriter_put_output(writer, dest);
3115 EXPECT_HR(hr, S_OK);
3117 V_VT(&dest) = VT_EMPTY;
3118 hr = IMXWriter_get_output(writer, &dest);
3119 EXPECT_HR(hr, S_OK);
3120 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3121 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3122 VariantClear(&dest);
3124 hr = ISAXContentHandler_startDocument(content);
3125 EXPECT_HR(hr, S_OK);
3127 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3128 EXPECT_HR(hr, S_OK);
3130 V_VT(&dest) = VT_EMPTY;
3131 hr = IMXWriter_get_output(writer, &dest);
3132 EXPECT_HR(hr, S_OK);
3133 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3134 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3135 VariantClear(&dest);
3137 ISAXContentHandler_endDocument(content);
3138 IMXWriter_flush(writer);
3140 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3141 EXPECT_HR(hr, S_OK);
3142 V_VT(&dest) = VT_EMPTY;
3143 hr = IMXWriter_get_output(writer, &dest);
3144 EXPECT_HR(hr, S_OK);
3145 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3146 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3147 VariantClear(&dest);
3149 ISAXContentHandler_Release(content);
3150 IMXWriter_Release(writer);
3154 struct writer_characters_t {
3160 static const struct writer_characters_t writer_characters[] = {
3161 { &CLSID_MXXMLWriter, "< > & \"", "< > & \"" },
3162 { &CLSID_MXXMLWriter30, "< > & \"", "< > & \"" },
3163 { &CLSID_MXXMLWriter40, "< > & \"", "< > & \"" },
3164 { &CLSID_MXXMLWriter60, "< > & \"", "< > & \"" },
3168 static void test_mxwriter_characters(void)
3170 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3171 const struct writer_characters_t *table = writer_characters;
3172 ISAXContentHandler *content;
3178 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3179 &IID_IMXWriter, (void**)&writer);
3180 EXPECT_HR(hr, S_OK);
3182 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3183 EXPECT_HR(hr, S_OK);
3185 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3186 EXPECT_HR(hr, S_OK);
3188 hr = ISAXContentHandler_startDocument(content);
3189 EXPECT_HR(hr, S_OK);
3191 hr = ISAXContentHandler_characters(content, NULL, 0);
3192 EXPECT_HR(hr, E_INVALIDARG);
3194 hr = ISAXContentHandler_characters(content, chardataW, 0);
3195 EXPECT_HR(hr, S_OK);
3197 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3198 EXPECT_HR(hr, S_OK);
3200 V_VT(&dest) = VT_EMPTY;
3201 hr = IMXWriter_get_output(writer, &dest);
3202 EXPECT_HR(hr, S_OK);
3203 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3204 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3205 VariantClear(&dest);
3207 hr = ISAXContentHandler_endDocument(content);
3208 EXPECT_HR(hr, S_OK);
3210 ISAXContentHandler_Release(content);
3211 IMXWriter_Release(writer);
3213 /* try empty characters data to see if element is closed */
3214 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3215 &IID_IMXWriter, (void**)&writer);
3216 EXPECT_HR(hr, S_OK);
3218 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3219 EXPECT_HR(hr, S_OK);
3221 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3222 EXPECT_HR(hr, S_OK);
3224 hr = ISAXContentHandler_startDocument(content);
3225 EXPECT_HR(hr, S_OK);
3227 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3228 EXPECT_HR(hr, S_OK);
3230 hr = ISAXContentHandler_characters(content, chardataW, 0);
3231 EXPECT_HR(hr, S_OK);
3233 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3234 EXPECT_HR(hr, S_OK);
3236 V_VT(&dest) = VT_EMPTY;
3237 hr = IMXWriter_get_output(writer, &dest);
3238 EXPECT_HR(hr, S_OK);
3239 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3240 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3241 VariantClear(&dest);
3243 ISAXContentHandler_Release(content);
3244 IMXWriter_Release(writer);
3247 while (table->clsid)
3249 ISAXContentHandler *content;
3253 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3260 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3261 &IID_IMXWriter, (void**)&writer);
3262 EXPECT_HR(hr, S_OK);
3264 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3265 EXPECT_HR(hr, S_OK);
3267 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3268 EXPECT_HR(hr, S_OK);
3270 hr = ISAXContentHandler_startDocument(content);
3271 EXPECT_HR(hr, S_OK);
3273 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3274 EXPECT_HR(hr, S_OK);
3281 V_VT(&dest) = VT_EMPTY;
3282 hr = IMXWriter_get_output(writer, &dest);
3283 EXPECT_HR(hr, S_OK);
3284 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3285 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3286 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3287 VariantClear(&dest);
3297 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3299 VARIANT_TRUE,"UTF-16",
3301 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3302 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3307 VARIANT_FALSE,"UTF-16",
3309 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3314 VARIANT_TRUE,"UTF-8",
3316 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3317 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3318 * and the writer is released.
3325 VARIANT_TRUE,"utf-8",
3327 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3328 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3329 * and the writer is released.
3336 VARIANT_TRUE,"UTF-16",
3338 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3339 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3344 VARIANT_TRUE,"UTF-16",
3346 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3347 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3353 static void test_mxwriter_stream(void)
3356 ISAXContentHandler *content;
3361 ULARGE_INTEGER pos2;
3362 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3364 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3365 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3367 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3368 &IID_IMXWriter, (void**)&writer);
3369 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3371 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3372 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3374 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3375 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3377 V_VT(&dest) = VT_UNKNOWN;
3378 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3379 hr = IMXWriter_put_output(writer, dest);
3380 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3381 VariantClear(&dest);
3383 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3384 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3386 current_write_test = test->expected_writes;
3388 hr = ISAXContentHandler_startDocument(content);
3389 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3391 hr = ISAXContentHandler_endDocument(content);
3392 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3394 ISAXContentHandler_Release(content);
3395 IMXWriter_Release(writer);
3397 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3398 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3401 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3402 &IID_IMXWriter, (void**)&writer);
3403 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3405 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3406 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3408 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3409 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3411 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3412 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3414 V_VT(&dest) = VT_UNKNOWN;
3415 V_UNKNOWN(&dest) = (IUnknown*)stream;
3416 hr = IMXWriter_put_output(writer, dest);
3417 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3419 hr = ISAXContentHandler_startDocument(content);
3420 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3422 /* Setting output of the mxwriter causes the current output to be flushed,
3423 * and the writer to start over.
3425 V_VT(&dest) = VT_EMPTY;
3426 hr = IMXWriter_put_output(writer, dest);
3427 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3430 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3431 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3432 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3434 hr = ISAXContentHandler_startDocument(content);
3435 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3437 hr = ISAXContentHandler_endDocument(content);
3438 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3440 V_VT(&dest) = VT_EMPTY;
3441 hr = IMXWriter_get_output(writer, &dest);
3442 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3443 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3444 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3445 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3446 VariantClear(&dest);
3448 /* test when BOM is written to output stream */
3449 V_VT(&dest) = VT_EMPTY;
3450 hr = IMXWriter_put_output(writer, dest);
3451 EXPECT_HR(hr, S_OK);
3454 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3455 EXPECT_HR(hr, S_OK);
3457 V_VT(&dest) = VT_UNKNOWN;
3458 V_UNKNOWN(&dest) = (IUnknown*)stream;
3459 hr = IMXWriter_put_output(writer, dest);
3460 EXPECT_HR(hr, S_OK);
3462 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3463 EXPECT_HR(hr, S_OK);
3465 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3466 EXPECT_HR(hr, S_OK);
3468 hr = ISAXContentHandler_startDocument(content);
3469 EXPECT_HR(hr, S_OK);
3473 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3474 EXPECT_HR(hr, S_OK);
3475 ok(pos2.QuadPart == 2, "got wrong position\n");
3477 ISAXContentHandler_Release(content);
3478 IMXWriter_Release(writer);
3483 static void test_mxwriter_encoding(void)
3485 ISAXContentHandler *content;
3494 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3495 &IID_IMXWriter, (void**)&writer);
3496 EXPECT_HR(hr, S_OK);
3498 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3499 EXPECT_HR(hr, S_OK);
3501 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3502 EXPECT_HR(hr, S_OK);
3504 hr = ISAXContentHandler_startDocument(content);
3505 EXPECT_HR(hr, S_OK);
3507 hr = ISAXContentHandler_endDocument(content);
3508 EXPECT_HR(hr, S_OK);
3510 /* The content is always re-encoded to UTF-16 when the output is
3511 * retrieved as a BSTR.
3513 V_VT(&dest) = VT_EMPTY;
3514 hr = IMXWriter_get_output(writer, &dest);
3515 EXPECT_HR(hr, S_OK);
3516 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3517 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3518 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3519 VariantClear(&dest);
3521 /* switch encoding when something is written already */
3522 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3523 EXPECT_HR(hr, S_OK);
3525 V_VT(&dest) = VT_UNKNOWN;
3526 V_UNKNOWN(&dest) = (IUnknown*)stream;
3527 hr = IMXWriter_put_output(writer, dest);
3528 EXPECT_HR(hr, S_OK);
3530 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3531 EXPECT_HR(hr, S_OK);
3533 /* write empty element */
3534 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3535 EXPECT_HR(hr, S_OK);
3537 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3538 EXPECT_HR(hr, S_OK);
3541 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3542 EXPECT_HR(hr, S_OK);
3544 hr = IMXWriter_flush(writer);
3545 EXPECT_HR(hr, S_OK);
3547 hr = GetHGlobalFromStream(stream, &g);
3548 EXPECT_HR(hr, S_OK);
3550 ptr = GlobalLock(g);
3551 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3554 /* so output is unaffected, encoding name is stored however */
3555 hr = IMXWriter_get_encoding(writer, &s);
3556 EXPECT_HR(hr, S_OK);
3557 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3560 IStream_Release(stream);
3562 ISAXContentHandler_Release(content);
3563 IMXWriter_Release(writer);
3568 static void test_obj_dispex(IUnknown *obj)
3570 static const WCHAR starW[] = {'*',0};
3571 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
3572 IDispatchEx *dispex;
3579 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
3580 EXPECT_HR(hr, S_OK);
3581 if (FAILED(hr)) return;
3584 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
3585 EXPECT_HR(hr, S_OK);
3586 ok(ticnt == 1, "ticnt=%u\n", ticnt);
3588 name = SysAllocString(starW);
3589 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
3590 EXPECT_HR(hr, E_NOTIMPL);
3591 SysFreeString(name);
3593 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
3594 EXPECT_HR(hr, E_NOTIMPL);
3597 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
3598 EXPECT_HR(hr, E_NOTIMPL);
3599 ok(props == 0, "expected 0 got %d\n", props);
3601 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
3602 EXPECT_HR(hr, E_NOTIMPL);
3603 if (SUCCEEDED(hr)) SysFreeString(name);
3605 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
3606 EXPECT_HR(hr, E_NOTIMPL);
3608 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
3609 EXPECT_HR(hr, E_NOTIMPL);
3610 if (hr == S_OK && unk) IUnknown_Release(unk);
3612 IDispatchEx_Release(dispex);
3615 static void test_dispex(void)
3617 IVBSAXXMLReader *vbreader;
3618 ISAXXMLReader *reader;
3622 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
3623 &IID_ISAXXMLReader, (void**)&reader);
3624 EXPECT_HR(hr, S_OK);
3626 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
3627 EXPECT_HR(hr, S_OK);
3628 test_obj_dispex(unk);
3629 IUnknown_Release(unk);
3631 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
3632 EXPECT_HR(hr, S_OK);
3633 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
3634 EXPECT_HR(hr, S_OK);
3635 test_obj_dispex(unk);
3636 IUnknown_Release(unk);
3637 IVBSAXXMLReader_Release(vbreader);
3639 ISAXXMLReader_Release(reader);
3642 static void test_mxwriter_dispex(void)
3644 IDispatchEx *dispex;
3649 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3650 &IID_IMXWriter, (void**)&writer);
3651 EXPECT_HR(hr, S_OK);
3653 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
3654 EXPECT_HR(hr, S_OK);
3655 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
3656 test_obj_dispex(unk);
3657 IUnknown_Release(unk);
3658 IDispatchEx_Release(dispex);
3660 IMXWriter_Release(writer);
3663 static void test_mxwriter_comment(void)
3665 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
3666 ISAXContentHandler *content;
3667 ISAXLexicalHandler *lexical;
3672 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3673 &IID_IMXWriter, (void**)&writer);
3674 EXPECT_HR(hr, S_OK);
3676 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3677 EXPECT_HR(hr, S_OK);
3679 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3680 EXPECT_HR(hr, S_OK);
3682 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3683 EXPECT_HR(hr, S_OK);
3685 hr = ISAXContentHandler_startDocument(content);
3686 EXPECT_HR(hr, S_OK);
3688 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
3689 EXPECT_HR(hr, E_INVALIDARG);
3691 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
3692 EXPECT_HR(hr, S_OK);
3694 V_VT(&dest) = VT_EMPTY;
3695 hr = IMXWriter_get_output(writer, &dest);
3696 EXPECT_HR(hr, S_OK);
3697 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3698 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3699 VariantClear(&dest);
3701 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
3702 EXPECT_HR(hr, S_OK);
3704 V_VT(&dest) = VT_EMPTY;
3705 hr = IMXWriter_get_output(writer, &dest);
3706 EXPECT_HR(hr, S_OK);
3707 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3708 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3709 VariantClear(&dest);
3711 ISAXContentHandler_Release(content);
3712 ISAXLexicalHandler_Release(lexical);
3713 IMXWriter_Release(writer);
3717 static void test_mxwriter_cdata(void)
3719 ISAXContentHandler *content;
3720 ISAXLexicalHandler *lexical;
3725 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3726 &IID_IMXWriter, (void**)&writer);
3727 EXPECT_HR(hr, S_OK);
3729 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3730 EXPECT_HR(hr, S_OK);
3732 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3733 EXPECT_HR(hr, S_OK);
3735 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3736 EXPECT_HR(hr, S_OK);
3738 hr = ISAXContentHandler_startDocument(content);
3739 EXPECT_HR(hr, S_OK);
3741 hr = ISAXLexicalHandler_startCDATA(lexical);
3742 EXPECT_HR(hr, S_OK);
3744 V_VT(&dest) = VT_EMPTY;
3745 hr = IMXWriter_get_output(writer, &dest);
3746 EXPECT_HR(hr, S_OK);
3747 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3748 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3749 VariantClear(&dest);
3751 hr = ISAXLexicalHandler_startCDATA(lexical);
3752 EXPECT_HR(hr, S_OK);
3754 /* all these are escaped for text nodes */
3755 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
3756 EXPECT_HR(hr, S_OK);
3758 hr = ISAXLexicalHandler_endCDATA(lexical);
3759 EXPECT_HR(hr, S_OK);
3761 V_VT(&dest) = VT_EMPTY;
3762 hr = IMXWriter_get_output(writer, &dest);
3763 EXPECT_HR(hr, S_OK);
3764 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3765 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3766 VariantClear(&dest);
3768 ISAXContentHandler_Release(content);
3769 ISAXLexicalHandler_Release(lexical);
3770 IMXWriter_Release(writer);
3774 static void test_mxwriter_pi(void)
3776 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
3777 static const WCHAR dataW[] = {'d','a','t','a',0};
3778 ISAXContentHandler *content;
3783 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3784 &IID_IMXWriter, (void**)&writer);
3785 EXPECT_HR(hr, S_OK);
3787 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3788 EXPECT_HR(hr, S_OK);
3790 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
3791 EXPECT_HR(hr, E_INVALIDARG);
3793 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
3794 EXPECT_HR(hr, S_OK);
3796 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
3797 EXPECT_HR(hr, S_OK);
3799 V_VT(&dest) = VT_EMPTY;
3800 hr = IMXWriter_get_output(writer, &dest);
3801 EXPECT_HR(hr, S_OK);
3802 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3803 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3804 VariantClear(&dest);
3806 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
3807 EXPECT_HR(hr, S_OK);
3809 V_VT(&dest) = VT_EMPTY;
3810 hr = IMXWriter_get_output(writer, &dest);
3811 EXPECT_HR(hr, S_OK);
3812 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3813 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)));
3814 VariantClear(&dest);
3816 V_VT(&dest) = VT_EMPTY;
3817 hr = IMXWriter_put_output(writer, dest);
3818 EXPECT_HR(hr, S_OK);
3820 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
3821 EXPECT_HR(hr, S_OK);
3823 V_VT(&dest) = VT_EMPTY;
3824 hr = IMXWriter_get_output(writer, &dest);
3825 EXPECT_HR(hr, S_OK);
3826 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3827 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3828 VariantClear(&dest);
3831 ISAXContentHandler_Release(content);
3832 IMXWriter_Release(writer);
3835 static void test_mxwriter_ignorablespaces(void)
3837 static const WCHAR dataW[] = {'d','a','t','a',0};
3838 ISAXContentHandler *content;
3843 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3844 &IID_IMXWriter, (void**)&writer);
3845 EXPECT_HR(hr, S_OK);
3847 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3848 EXPECT_HR(hr, S_OK);
3850 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
3851 EXPECT_HR(hr, E_INVALIDARG);
3853 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
3854 EXPECT_HR(hr, S_OK);
3856 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
3857 EXPECT_HR(hr, S_OK);
3859 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
3860 EXPECT_HR(hr, S_OK);
3862 V_VT(&dest) = VT_EMPTY;
3863 hr = IMXWriter_get_output(writer, &dest);
3864 EXPECT_HR(hr, S_OK);
3865 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3866 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3867 VariantClear(&dest);
3869 ISAXContentHandler_Release(content);
3870 IMXWriter_Release(writer);
3873 static void test_mxwriter_dtd(void)
3875 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
3876 static const WCHAR nameW[] = {'n','a','m','e'};
3877 static const WCHAR pubW[] = {'p','u','b'};
3878 static const WCHAR sysW[] = {'s','y','s'};
3879 ISAXContentHandler *content;
3880 ISAXLexicalHandler *lexical;
3881 ISAXDeclHandler *decl;
3886 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3887 &IID_IMXWriter, (void**)&writer);
3888 EXPECT_HR(hr, S_OK);
3890 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3891 EXPECT_HR(hr, S_OK);
3893 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3894 EXPECT_HR(hr, S_OK);
3896 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
3897 EXPECT_HR(hr, S_OK);
3899 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3900 EXPECT_HR(hr, S_OK);
3902 hr = ISAXContentHandler_startDocument(content);
3903 EXPECT_HR(hr, S_OK);
3905 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
3906 EXPECT_HR(hr, E_INVALIDARG);
3908 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3909 EXPECT_HR(hr, E_INVALIDARG);
3911 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
3912 EXPECT_HR(hr, E_INVALIDARG);
3914 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3915 EXPECT_HR(hr, E_INVALIDARG);
3917 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
3918 EXPECT_HR(hr, S_OK);
3920 V_VT(&dest) = VT_EMPTY;
3921 hr = IMXWriter_get_output(writer, &dest);
3922 EXPECT_HR(hr, S_OK);
3923 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3924 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3925 VariantClear(&dest);
3927 /* system id is required if public is present */
3928 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3929 EXPECT_HR(hr, E_INVALIDARG);
3931 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
3932 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3933 EXPECT_HR(hr, S_OK);
3935 V_VT(&dest) = VT_EMPTY;
3936 hr = IMXWriter_get_output(writer, &dest);
3937 EXPECT_HR(hr, S_OK);
3938 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3939 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3940 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3941 VariantClear(&dest);
3943 hr = ISAXLexicalHandler_endDTD(lexical);
3944 EXPECT_HR(hr, S_OK);
3946 hr = ISAXLexicalHandler_endDTD(lexical);
3947 EXPECT_HR(hr, S_OK);
3949 V_VT(&dest) = VT_EMPTY;
3950 hr = IMXWriter_get_output(writer, &dest);
3951 EXPECT_HR(hr, S_OK);
3952 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3953 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3954 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
3955 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3956 VariantClear(&dest);
3958 /* element declaration */
3959 V_VT(&dest) = VT_EMPTY;
3960 hr = IMXWriter_put_output(writer, dest);
3961 EXPECT_HR(hr, S_OK);
3963 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
3964 EXPECT_HR(hr, E_INVALIDARG);
3966 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
3967 EXPECT_HR(hr, E_INVALIDARG);
3969 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
3970 EXPECT_HR(hr, S_OK);
3972 V_VT(&dest) = VT_EMPTY;
3973 hr = IMXWriter_get_output(writer, &dest);
3974 EXPECT_HR(hr, S_OK);
3975 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3976 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
3977 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3978 VariantClear(&dest);
3980 V_VT(&dest) = VT_EMPTY;
3981 hr = IMXWriter_put_output(writer, dest);
3982 EXPECT_HR(hr, S_OK);
3984 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
3985 EXPECT_HR(hr, S_OK);
3987 V_VT(&dest) = VT_EMPTY;
3988 hr = IMXWriter_get_output(writer, &dest);
3989 EXPECT_HR(hr, S_OK);
3990 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3991 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
3992 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3993 VariantClear(&dest);
3995 ISAXContentHandler_Release(content);
3996 ISAXLexicalHandler_Release(lexical);
3997 ISAXDeclHandler_Release(decl);
3998 IMXWriter_Release(writer);
4010 } addattribute_test_t;
4012 static const addattribute_test_t addattribute_data[] = {
4013 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4014 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4015 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4016 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4018 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4019 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4020 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4021 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4023 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4024 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4025 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4026 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4028 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4029 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4030 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4031 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4036 static void test_mxattr_addAttribute(void)
4038 const addattribute_test_t *table = addattribute_data;
4041 while (table->clsid)
4043 ISAXAttributes *saxattr;
4044 IMXAttributes *mxattr;
4049 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4056 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4057 &IID_IMXAttributes, (void**)&mxattr);
4058 EXPECT_HR(hr, S_OK);
4060 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4061 EXPECT_HR(hr, S_OK);
4063 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4064 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4065 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4067 hr = ISAXAttributes_getLength(saxattr, NULL);
4068 EXPECT_HR(hr, E_POINTER);
4072 hr = ISAXAttributes_getLength(saxattr, &len);
4073 EXPECT_HR(hr, S_OK);
4074 ok(len == 0, "got %d\n", len);
4076 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4077 EXPECT_HR(hr, E_INVALIDARG);
4079 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4080 EXPECT_HR(hr, E_INVALIDARG);
4082 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4083 EXPECT_HR(hr, E_INVALIDARG);
4085 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4086 EXPECT_HR(hr, E_INVALIDARG);
4088 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4089 EXPECT_HR(hr, E_INVALIDARG);
4091 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4092 EXPECT_HR(hr, E_INVALIDARG);
4094 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4095 EXPECT_HR(hr, E_INVALIDARG);
4097 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4098 EXPECT_HR(hr, E_INVALIDARG);
4100 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4101 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4102 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4106 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4107 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4108 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4110 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4111 EXPECT_HR(hr, E_POINTER);
4113 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4114 EXPECT_HR(hr, E_POINTER);
4116 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4117 EXPECT_HR(hr, E_POINTER);
4119 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4120 EXPECT_HR(hr, E_POINTER);
4122 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4123 EXPECT_HR(hr, E_POINTER);
4125 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4126 EXPECT_HR(hr, E_POINTER);
4130 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4131 EXPECT_HR(hr, S_OK);
4132 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4134 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4137 value = (void*)0xdeadbeef;
4138 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4139 EXPECT_HR(hr, S_OK);
4143 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4145 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4149 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4150 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4153 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4154 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4155 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4157 EXPECT_HR(hr, E_POINTER);
4160 EXPECT_HR(hr, E_INVALIDARG);
4162 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4163 EXPECT_HR(hr, E_INVALIDARG);
4166 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4167 EXPECT_HR(hr, E_INVALIDARG);
4168 ok(index == -1, "%d: got wrong index %d\n", i, index);
4171 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4172 EXPECT_HR(hr, E_INVALIDARG);
4173 ok(index == -1, "%d: got wrong index %d\n", i, index);
4176 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4177 EXPECT_HR(hr, S_OK);
4178 ok(index == 0, "%d: got wrong index %d\n", i, index);
4181 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4182 EXPECT_HR(hr, E_INVALIDARG);
4183 ok(index == -1, "%d: got wrong index %d\n", i, index);
4185 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4186 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4188 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4189 EXPECT_HR(hr, E_INVALIDARG);
4191 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4192 EXPECT_HR(hr, E_INVALIDARG);
4194 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4195 EXPECT_HR(hr, E_INVALIDARG);
4199 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4200 EXPECT_HR(hr, E_POINTER);
4202 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4203 EXPECT_HR(hr, E_POINTER);
4205 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4206 EXPECT_HR(hr, E_POINTER);
4208 /* versions 4 and 6 crash */
4209 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4210 EXPECT_HR(hr, E_POINTER);
4212 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4213 EXPECT_HR(hr, E_POINTER);
4216 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4217 EXPECT_HR(hr, S_OK);
4221 hr = ISAXAttributes_getLength(saxattr, &len);
4222 EXPECT_HR(hr, S_OK);
4223 if (table->hr == S_OK)
4224 ok(len == 1, "%d: got %d length, expected 0\n", i, len);
4226 ok(len == 0, "%d: got %d length, expected 1\n", i, len);
4228 ISAXAttributes_Release(saxattr);
4229 IMXAttributes_Release(mxattr);
4238 static void test_mxattr_clear(void)
4240 ISAXAttributes *saxattr;
4241 IMXAttributes *mxattr;
4246 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4247 &IID_IMXAttributes, (void**)&mxattr);
4248 EXPECT_HR(hr, S_OK);
4250 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4251 EXPECT_HR(hr, S_OK);
4253 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4254 EXPECT_HR(hr, E_INVALIDARG);
4256 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4257 EXPECT_HR(hr, E_INVALIDARG);
4259 hr = IMXAttributes_clear(mxattr);
4260 EXPECT_HR(hr, S_OK);
4262 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4263 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4264 EXPECT_HR(hr, S_OK);
4267 hr = ISAXAttributes_getLength(saxattr, &len);
4268 EXPECT_HR(hr, S_OK);
4269 ok(len == 1, "got %d\n", len);
4272 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4273 EXPECT_HR(hr, E_POINTER);
4274 ok(len == -1, "got %d\n", len);
4276 ptr = (void*)0xdeadbeef;
4277 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4278 EXPECT_HR(hr, E_POINTER);
4279 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4282 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4283 EXPECT_HR(hr, S_OK);
4284 ok(len == 5, "got %d\n", len);
4285 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4287 hr = IMXAttributes_clear(mxattr);
4288 EXPECT_HR(hr, S_OK);
4291 hr = ISAXAttributes_getLength(saxattr, &len);
4292 EXPECT_HR(hr, S_OK);
4293 ok(len == 0, "got %d\n", len);
4296 ptr = (void*)0xdeadbeef;
4297 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4298 EXPECT_HR(hr, E_INVALIDARG);
4299 ok(len == -1, "got %d\n", len);
4300 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4302 IMXAttributes_Release(mxattr);
4303 ISAXAttributes_Release(saxattr);
4307 static void test_mxattr_dispex(void)
4309 IMXAttributes *mxattr;
4310 IDispatchEx *dispex;
4314 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4315 &IID_IMXAttributes, (void**)&mxattr);
4316 EXPECT_HR(hr, S_OK);
4318 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4319 EXPECT_HR(hr, S_OK);
4320 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4321 test_obj_dispex(unk);
4322 IUnknown_Release(unk);
4323 IDispatchEx_Release(dispex);
4325 IMXAttributes_Release(mxattr);
4328 static void test_mxattr_qi(void)
4330 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4331 ISAXAttributes *saxattr;
4332 IMXAttributes *mxattr;
4335 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4336 &IID_IMXAttributes, (void**)&mxattr);
4337 EXPECT_HR(hr, S_OK);
4339 EXPECT_REF(mxattr, 1);
4340 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4341 EXPECT_HR(hr, S_OK);
4343 EXPECT_REF(mxattr, 2);
4344 EXPECT_REF(saxattr, 2);
4346 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4347 EXPECT_HR(hr, S_OK);
4349 EXPECT_REF(vbsaxattr, 3);
4350 EXPECT_REF(mxattr, 3);
4351 EXPECT_REF(saxattr, 3);
4353 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4354 EXPECT_HR(hr, S_OK);
4356 EXPECT_REF(vbsaxattr, 4);
4357 EXPECT_REF(mxattr, 4);
4358 EXPECT_REF(saxattr, 4);
4360 IMXAttributes_Release(mxattr);
4361 ISAXAttributes_Release(saxattr);
4362 IVBSAXAttributes_Release(vbsaxattr);
4363 IVBSAXAttributes_Release(vbsaxattr2);
4366 static struct msxmlsupported_data_t saxattr_support_data[] =
4368 { &CLSID_SAXAttributes, "SAXAttributes" },
4369 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4370 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4371 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4375 static void test_mxattr_localname(void)
4377 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4378 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4379 static const WCHAR uri1W[] = {'u','r','i','1',0};
4380 static const WCHAR uriW[] = {'u','r','i',0};
4382 const struct msxmlsupported_data_t *table = saxattr_support_data;
4384 while (table->clsid)
4386 ISAXAttributes *saxattr;
4387 IMXAttributes *mxattr;
4391 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4397 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4398 &IID_IMXAttributes, (void**)&mxattr);
4399 EXPECT_HR(hr, S_OK);
4401 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4402 EXPECT_HR(hr, S_OK);
4404 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4405 EXPECT_HR(hr, E_INVALIDARG);
4407 /* add some ambiguos attribute names */
4408 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4409 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4410 EXPECT_HR(hr, S_OK);
4411 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4412 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4413 EXPECT_HR(hr, S_OK);
4416 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4417 EXPECT_HR(hr, S_OK);
4418 ok(index == 0, "%s: got index %d\n", table->name, index);
4421 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4422 EXPECT_HR(hr, E_INVALIDARG);
4423 ok(index == -1, "%s: got index %d\n", table->name, index);
4426 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4427 EXPECT_HR(hr, E_INVALIDARG);
4428 ok(index == -1, "%s: got index %d\n", table->name, index);
4430 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4431 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4433 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4434 EXPECT_HR(hr, E_POINTER);
4436 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4437 EXPECT_HR(hr, E_POINTER);
4441 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4442 EXPECT_HR(hr, E_INVALIDARG);
4444 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4445 EXPECT_HR(hr, E_INVALIDARG);
4448 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
4449 EXPECT_HR(hr, E_INVALIDARG);
4451 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
4452 EXPECT_HR(hr, E_INVALIDARG);
4456 ISAXAttributes_Release(saxattr);
4457 IMXAttributes_Release(mxattr);
4461 START_TEST(saxreader)
4463 ISAXXMLReader *reader;
4466 hr = CoInitialize(NULL);
4467 ok(hr == S_OK, "failed to init com\n");
4469 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4470 &IID_ISAXXMLReader, (void**)&reader);
4474 skip("Failed to create SAXXMLReader instance\n");
4478 ISAXXMLReader_Release(reader);
4480 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4482 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
4485 test_saxreader_properties();
4486 test_saxreader_features();
4487 test_saxreader_encoding();
4490 /* MXXMLWriter tests */
4491 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
4492 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
4494 test_mxwriter_handlers();
4495 test_mxwriter_startenddocument();
4496 test_mxwriter_startendelement();
4497 test_mxwriter_characters();
4498 test_mxwriter_comment();
4499 test_mxwriter_cdata();
4501 test_mxwriter_ignorablespaces();
4502 test_mxwriter_dtd();
4503 test_mxwriter_properties();
4504 test_mxwriter_flush();
4505 test_mxwriter_stream();
4506 test_mxwriter_encoding();
4507 test_mxwriter_dispex();
4510 win_skip("MXXMLWriter not supported\n");
4512 /* SAXAttributes tests */
4513 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
4514 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
4517 test_mxattr_addAttribute();
4518 test_mxattr_clear();
4519 test_mxattr_localname();
4520 test_mxattr_dispex();
4523 skip("SAXAttributes not supported\n");