ntdll: Use an __ms_va_list in sscanf (Clang).
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blob75354c594a1c28b55df78f3a951a3ed2154634dc
1 /*
2 * SAXReader/MXWriter tests
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
6 * Copyright 2012 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define CONST_VTABLE
26 #include <stdio.h>
27 #include <assert.h>
29 #include "windows.h"
30 #include "ole2.h"
31 #include "msxml2.h"
32 #include "msxml2did.h"
33 #include "ocidl.h"
34 #include "dispex.h"
36 #include "wine/test.h"
38 static const WCHAR emptyW[] = {0};
40 #define EXPECT_HR(hr,hr_exp) \
41 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
43 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
44 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
46 ULONG rc = IUnknown_AddRef(obj);
47 IUnknown_Release(obj);
48 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
51 static LONG get_refcount(void *iface)
53 IUnknown *unk = iface;
54 LONG ref;
56 ref = IUnknown_AddRef(unk);
57 IUnknown_Release(unk);
58 return ref-1;
61 struct msxmlsupported_data_t
63 const GUID *clsid;
64 const char *name;
65 BOOL supported;
68 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
70 while (table->clsid)
72 if (table->clsid == clsid) return table->supported;
73 table++;
75 return FALSE;
78 static BSTR alloc_str_from_narrow(const char *str)
80 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
81 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
82 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
83 return ret;
86 static BSTR alloced_bstrs[512];
87 static int alloced_bstrs_count;
89 static BSTR _bstr_(const char *str)
91 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
92 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
93 return alloced_bstrs[alloced_bstrs_count++];
96 static void free_bstrs(void)
98 int i;
99 for (i = 0; i < alloced_bstrs_count; i++)
100 SysFreeString(alloced_bstrs[i]);
101 alloced_bstrs_count = 0;
104 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, BOOL todo, int *failcount)
106 int len, lenexp, cmp;
107 WCHAR buf[1024];
109 len = SysStringLen(str);
111 if (!expected) {
112 if (str && todo)
114 (*failcount)++;
115 todo_wine
116 ok_(file, line) (!str, "got %p, expected null str\n", str);
118 else
119 ok_(file, line) (!str, "got %p, expected null str\n", str);
121 if (len && todo)
123 (*failcount)++;
124 todo_wine
125 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
127 else
128 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
129 return;
132 lenexp = strlen(expected);
133 if (lenexp != len && todo)
135 (*failcount)++;
136 todo_wine
137 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
139 else
140 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
142 /* exit earlier on length mismatch */
143 if (lenexp != len) return;
145 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
147 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
148 if (cmp && todo)
150 (*failcount)++;
151 todo_wine
152 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
153 wine_dbgstr_wn(str, len), expected);
155 else
156 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
157 wine_dbgstr_wn(str, len), expected);
160 typedef enum _CH {
161 CH_ENDTEST,
162 CH_PUTDOCUMENTLOCATOR,
163 CH_STARTDOCUMENT,
164 CH_ENDDOCUMENT,
165 CH_STARTPREFIXMAPPING,
166 CH_ENDPREFIXMAPPING,
167 CH_STARTELEMENT,
168 CH_ENDELEMENT,
169 CH_CHARACTERS,
170 CH_IGNORABLEWHITESPACE,
171 CH_PROCESSINGINSTRUCTION,
172 CH_SKIPPEDENTITY,
173 LH_STARTCDATA,
174 LH_ENDCDATA,
175 EH_ERROR,
176 EH_FATALERROR,
177 EH_IGNORABLEWARNING,
178 EVENT_LAST
179 } CH;
181 static const char *event_names[EVENT_LAST] = {
182 "endtest",
183 "putDocumentLocator",
184 "startDocument",
185 "endDocument",
186 "startPrefixMapping",
187 "endPrefixMapping",
188 "startElement",
189 "endElement",
190 "characters",
191 "ignorableWhitespace",
192 "processingInstruction",
193 "skippedEntity",
194 "startCDATA",
195 "endCDATA",
196 "error",
197 "fatalError",
198 "ignorableWarning"
201 struct attribute_entry {
202 const char *uri;
203 const char *local;
204 const char *qname;
205 const char *value;
207 /* used for actual call data only, null for expected call data */
208 BSTR uriW;
209 BSTR localW;
210 BSTR qnameW;
211 BSTR valueW;
214 struct call_entry {
215 CH id;
216 int line;
217 int column;
218 HRESULT ret;
219 const char *arg1;
220 const char *arg2;
221 const char *arg3;
223 /* allocated once at startElement callback */
224 struct attribute_entry *attributes;
225 int attr_count;
227 /* used for actual call data only, null for expected call data */
228 BSTR arg1W;
229 BSTR arg2W;
230 BSTR arg3W;
233 struct call_sequence
235 int count;
236 int size;
237 struct call_entry *sequence;
240 #define CONTENT_HANDLER_INDEX 0
241 #define NUM_CALL_SEQUENCES 1
242 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
244 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
246 memset(call, 0, sizeof(*call));
247 ISAXLocator_getLineNumber(locator, &call->line);
248 ISAXLocator_getColumnNumber(locator, &call->column);
251 static void add_call(struct call_sequence **seq, int sequence_index,
252 const struct call_entry *call)
254 struct call_sequence *call_seq = seq[sequence_index];
256 if (!call_seq->sequence)
258 call_seq->size = 10;
259 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
260 call_seq->size * sizeof (struct call_entry));
263 if (call_seq->count == call_seq->size)
265 call_seq->size *= 2;
266 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
267 call_seq->sequence,
268 call_seq->size * sizeof (struct call_entry));
271 assert(call_seq->sequence);
273 call_seq->sequence[call_seq->count].id = call->id;
274 call_seq->sequence[call_seq->count].line = call->line;
275 call_seq->sequence[call_seq->count].column = call->column;
276 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
277 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
278 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
279 call_seq->sequence[call_seq->count].ret = call->ret;
280 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
281 call_seq->sequence[call_seq->count].attributes = call->attributes;
283 call_seq->count++;
286 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
288 int i;
290 struct call_sequence *call_seq = seg[sequence_index];
292 for (i = 0; i < call_seq->count; i++)
294 int j;
296 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
298 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
299 SysFreeString(call_seq->sequence[i].attributes[j].localW);
300 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
303 SysFreeString(call_seq->sequence[i].arg1W);
304 SysFreeString(call_seq->sequence[i].arg2W);
305 SysFreeString(call_seq->sequence[i].arg3W);
308 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
309 call_seq->sequence = NULL;
310 call_seq->count = call_seq->size = 0;
313 static const char *get_event_name(CH event)
315 return event_names[event];
318 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
319 BOOL todo, const char *file, int line, int *failcount)
321 int i, lenexp = 0;
323 /* attribute count is not stored for expected data */
324 if (expected->attributes)
326 struct attribute_entry *ptr = expected->attributes;
327 while (ptr->uri) { lenexp++; ptr++; };
330 /* check count first and exit earlier */
331 if (actual->attr_count != lenexp && todo)
333 (*failcount)++;
334 todo_wine
335 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
336 context, get_event_name(actual->id), lenexp, actual->attr_count);
338 else
339 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
340 context, get_event_name(actual->id), lenexp, actual->attr_count);
342 if (actual->attr_count != lenexp) return;
344 /* now compare all attributes strings */
345 for (i = 0; i < actual->attr_count; i++)
347 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
348 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
349 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
350 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
354 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
355 const struct call_entry *expected, const char *context, BOOL todo,
356 const char *file, int line)
358 struct call_sequence *call_seq = seq[sequence_index];
359 static const struct call_entry end_of_sequence = { CH_ENDTEST };
360 const struct call_entry *actual, *sequence;
361 int failcount = 0;
363 add_call(seq, sequence_index, &end_of_sequence);
365 sequence = call_seq->sequence;
366 actual = sequence;
368 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
370 if (expected->id == actual->id)
372 if (expected->line != -1)
374 /* always test position data */
375 if (expected->line != actual->line && todo)
377 todo_wine
379 failcount++;
380 ok_(file, line) (FALSE,
381 "%s: in event %s expecting line %d got %d\n",
382 context, get_event_name(actual->id), expected->line, actual->line);
385 else
387 ok_(file, line) (expected->line == actual->line,
388 "%s: in event %s expecting line %d got %d\n",
389 context, get_event_name(actual->id), expected->line, actual->line);
394 if (expected->column != -1)
396 if (expected->column != actual->column && todo)
398 todo_wine
400 failcount++;
401 ok_(file, line) (FALSE,
402 "%s: in event %s expecting column %d got %d\n",
403 context, get_event_name(actual->id), expected->column, actual->column);
406 else
408 ok_(file, line) (expected->column == actual->column,
409 "%s: in event %s expecting column %d got %d\n",
410 context, get_event_name(actual->id), expected->column, actual->column);
414 switch (actual->id)
416 case CH_PUTDOCUMENTLOCATOR:
417 case CH_STARTDOCUMENT:
418 case CH_ENDDOCUMENT:
419 case LH_STARTCDATA:
420 case LH_ENDCDATA:
421 break;
422 case CH_STARTPREFIXMAPPING:
423 /* prefix, uri */
424 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
425 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
426 break;
427 case CH_ENDPREFIXMAPPING:
428 /* prefix */
429 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
430 break;
431 case CH_STARTELEMENT:
432 /* compare attributes */
433 compare_attributes(actual, expected, context, todo, file, line, &failcount);
434 /* fallthrough */
435 case CH_ENDELEMENT:
436 /* uri, localname, qname */
437 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
438 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
439 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
440 break;
441 case CH_CHARACTERS:
442 case CH_IGNORABLEWHITESPACE:
443 /* char data */
444 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
445 break;
446 case CH_PROCESSINGINSTRUCTION:
447 /* target, data */
448 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
449 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
450 break;
451 case CH_SKIPPEDENTITY:
452 /* name */
453 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
454 break;
455 case EH_FATALERROR:
456 /* test return value only */
457 if (expected->ret != actual->ret && todo)
459 failcount++;
460 ok_(file, line) (FALSE,
461 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
462 context, get_event_name(actual->id), expected->ret, actual->ret);
464 else
465 ok_(file, line) (expected->ret == actual->ret,
466 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
467 context, get_event_name(actual->id), expected->ret, actual->ret);
468 break;
469 case EH_ERROR:
470 case EH_IGNORABLEWARNING:
471 default:
472 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
474 expected++;
475 actual++;
477 else if (todo)
479 failcount++;
480 todo_wine
482 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
483 context, get_event_name(expected->id), get_event_name(actual->id));
486 flush_sequence(seq, sequence_index);
487 return;
489 else
491 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
492 context, get_event_name(expected->id), get_event_name(actual->id));
493 expected++;
494 actual++;
498 if (todo)
500 todo_wine
502 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
504 failcount++;
505 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
506 context, get_event_name(expected->id), get_event_name(actual->id));
510 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
512 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
513 context, get_event_name(expected->id), get_event_name(actual->id));
516 if (todo && !failcount) /* succeeded yet marked todo */
518 todo_wine
520 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
524 flush_sequence(seq, sequence_index);
527 #define ok_sequence(seq, index, exp, contx, todo) \
528 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
530 static void init_call_sequences(struct call_sequence **seq, int n)
532 int i;
534 for (i = 0; i < n; i++)
535 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
538 static const WCHAR szSimpleXML[] = {
539 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
540 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
541 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
542 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
543 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
546 static const WCHAR carriage_ret_test[] = {
547 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
548 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
549 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
550 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
551 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
554 static const WCHAR szUtf16XML[] = {
555 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
556 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
557 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
560 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
562 static const CHAR szUtf8XML[] =
563 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
565 static const char utf8xml2[] =
566 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
568 static const char testXML[] =
569 "<?xml version=\"1.0\" ?>\n"
570 "<BankAccount>\n"
571 " <Number>1234</Number>\n"
572 " <Name>Captain Ahab</Name>\n"
573 "</BankAccount>\n";
575 static const char test_attributes[] =
576 "<?xml version=\"1.0\" ?>\n"
577 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
578 "<node1 xmlns:p=\"test\" />"
579 "</document>\n";
581 static const char test_cdata_xml[] =
582 "<?xml version=\"1.0\" ?>"
583 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
585 static const char test2_cdata_xml[] =
586 "<?xml version=\"1.0\" ?>"
587 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
589 static const char test3_cdata_xml[] =
590 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
592 static struct call_entry content_handler_test1[] = {
593 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
594 { CH_STARTDOCUMENT, 0, 0, S_OK },
595 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
597 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
598 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
599 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
600 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
601 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
602 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
603 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
604 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
605 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
606 { CH_ENDDOCUMENT, 0, 0, S_OK},
607 { CH_ENDTEST }
610 /* applies to versions 4 and 6 */
611 static struct call_entry content_handler_test1_alternate[] = {
612 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
613 { CH_STARTDOCUMENT, 1, 22, S_OK },
614 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
615 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
616 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
617 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
618 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
619 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
620 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
621 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
622 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
623 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
624 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
625 { CH_ENDDOCUMENT, 6, 0, S_OK },
626 { CH_ENDTEST }
629 static struct call_entry content_handler_test2[] = {
630 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
631 { CH_STARTDOCUMENT, 0, 0, S_OK },
632 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
633 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
634 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
635 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
636 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
637 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
638 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
639 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
640 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
641 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
642 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
643 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
644 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
645 { CH_ENDDOCUMENT, 0, 0, S_OK },
646 { CH_ENDTEST }
649 static struct call_entry content_handler_test2_alternate[] = {
650 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
651 { CH_STARTDOCUMENT, 1, 21, S_OK },
652 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
653 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
654 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
655 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
656 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
657 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
658 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
659 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
660 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
661 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
662 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
663 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
664 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
665 { CH_ENDDOCUMENT, 6, 0, S_OK },
666 { CH_ENDTEST }
669 static struct call_entry content_handler_testerror[] = {
670 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
671 { EH_FATALERROR, 0, 0, E_FAIL },
672 { CH_ENDTEST }
675 static struct call_entry content_handler_testerror_alternate[] = {
676 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
677 { EH_FATALERROR, 1, 0, E_FAIL },
678 { CH_ENDTEST }
681 static struct call_entry content_handler_test_callback_rets[] = {
682 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
683 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
684 { EH_FATALERROR, 0, 0, S_FALSE },
685 { CH_ENDTEST }
688 static struct call_entry content_handler_test_callback_rets_alt[] = {
689 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
690 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
691 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
692 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
693 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
694 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
695 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
696 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
697 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
698 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
699 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
700 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
701 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
702 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
703 { CH_ENDTEST }
706 static struct attribute_entry ch_attributes1[] = {
707 { "", "", "xmlns:test", "prefix_test" },
708 { "", "", "xmlns", "prefix" },
709 { "prefix_test", "arg1", "test:arg1", "arg1" },
710 { "", "arg2", "arg2", "arg2" },
711 { "prefix_test", "ar3", "test:ar3", "arg3" },
712 { NULL }
715 static struct attribute_entry ch_attributes2[] = {
716 { "", "", "xmlns:p", "test" },
717 { NULL }
720 static struct call_entry content_handler_test_attributes[] = {
721 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
722 { CH_STARTDOCUMENT, 0, 0, S_OK },
723 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
724 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
725 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
726 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
727 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
728 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
729 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
730 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
731 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
732 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
733 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
734 { CH_ENDDOCUMENT, 0, 0 },
735 { CH_ENDTEST }
738 static struct attribute_entry ch_attributes_alt_4[] = {
739 { "prefix_test", "arg1", "test:arg1", "arg1" },
740 { "", "arg2", "arg2", "arg2" },
741 { "prefix_test", "ar3", "test:ar3", "arg3" },
742 { "", "", "xmlns:test", "prefix_test" },
743 { "", "", "xmlns", "prefix" },
744 { NULL }
747 static struct call_entry content_handler_test_attributes_alternate_4[] = {
748 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
749 { CH_STARTDOCUMENT, 1, 22, S_OK },
750 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
751 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
752 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
753 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
754 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
755 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
756 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
757 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
758 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
759 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
760 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
761 { CH_ENDDOCUMENT, 4, 0, S_OK },
762 { CH_ENDTEST }
765 /* 'namespace' feature switched off */
766 static struct attribute_entry ch_attributes_alt_no_ns[] = {
767 { "", "", "xmlns:test", "prefix_test" },
768 { "", "", "xmlns", "prefix" },
769 { "", "", "test:arg1", "arg1" },
770 { "", "", "arg2", "arg2" },
771 { "", "", "test:ar3", "arg3" },
772 { NULL }
775 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
776 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
777 { CH_STARTDOCUMENT, 1, 22, S_OK },
778 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
779 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
780 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
781 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
782 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
783 { CH_ENDDOCUMENT, 4, 0, S_OK },
784 { CH_ENDTEST }
787 static struct attribute_entry ch_attributes_alt_6[] = {
788 { "prefix_test", "arg1", "test:arg1", "arg1" },
789 { "", "arg2", "arg2", "arg2" },
790 { "prefix_test", "ar3", "test:ar3", "arg3" },
791 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
792 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
793 { NULL }
796 static struct attribute_entry ch_attributes2_6[] = {
797 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
798 { NULL }
801 static struct call_entry content_handler_test_attributes_alternate_6[] = {
802 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
803 { CH_STARTDOCUMENT, 1, 22, S_OK },
804 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
805 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
806 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
807 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
808 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
809 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
810 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
811 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
812 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
813 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
814 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
815 { CH_ENDDOCUMENT, 4, 0, S_OK },
816 { CH_ENDTEST }
819 /* 'namespaces' is on, 'namespace-prefixes' if off */
820 static struct attribute_entry ch_attributes_no_prefix[] = {
821 { "prefix_test", "arg1", "test:arg1", "arg1" },
822 { "", "arg2", "arg2", "arg2" },
823 { "prefix_test", "ar3", "test:ar3", "arg3" },
824 { NULL }
827 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
828 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
829 { CH_STARTDOCUMENT, 1, 22, S_OK },
830 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
831 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
832 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
833 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
834 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
835 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
836 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
837 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
838 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
839 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
840 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
841 { CH_ENDDOCUMENT, 4, 0, S_OK },
842 { CH_ENDTEST }
845 static struct call_entry content_handler_test_attributes_no_prefix[] = {
846 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
847 { CH_STARTDOCUMENT, 0, 0, S_OK },
848 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
849 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
850 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
851 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
852 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
853 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
854 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
855 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
856 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
857 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
858 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
859 { CH_ENDDOCUMENT, 0, 0 },
860 { CH_ENDTEST }
863 static struct attribute_entry xmlspace_attrs[] = {
864 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
865 { NULL }
868 static struct call_entry xmlspaceattr_test[] = {
869 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
870 { CH_STARTDOCUMENT, 0, 0, S_OK },
871 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
872 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
873 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
874 { CH_ENDDOCUMENT, 0, 0, S_OK },
875 { CH_ENDTEST }
878 static struct call_entry xmlspaceattr_test_alternate[] = {
879 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
880 { CH_STARTDOCUMENT, 1, 39, S_OK },
881 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
882 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
883 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
884 { CH_ENDDOCUMENT, 1, 83, S_OK },
885 { CH_ENDTEST }
888 /* attribute value normalization test */
889 static const char attribute_normalize[] =
890 "<?xml version=\"1.0\" ?>\n"
891 "<a attr1=\" \r \n \tattr_value &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
893 static struct attribute_entry attribute_norm_attrs[] = {
894 { "", "attr1", "attr1", " attr_value A & & " },
895 { NULL }
898 static struct call_entry attribute_norm[] = {
899 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
900 { CH_STARTDOCUMENT, 0, 0, S_OK },
901 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
902 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
903 { CH_ENDDOCUMENT, 0, 0, S_OK },
904 { CH_ENDTEST }
907 static struct call_entry attribute_norm_alt[] = {
908 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
909 { CH_STARTDOCUMENT, 1, 22, S_OK },
910 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
911 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
912 { CH_ENDDOCUMENT, 9, 0, S_OK },
913 { CH_ENDTEST }
916 static struct call_entry cdata_test[] = {
917 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
918 { CH_STARTDOCUMENT, 0, 0, S_OK },
919 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
920 { LH_STARTCDATA, 1, 35, S_OK },
921 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
922 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
923 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
924 { LH_ENDCDATA, 1, 49, S_OK },
925 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
926 { CH_ENDDOCUMENT, 0, 0, S_OK },
927 { CH_ENDTEST }
930 static struct call_entry cdata_test2[] = {
931 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
932 { CH_STARTDOCUMENT, 0, 0, S_OK },
933 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
934 { LH_STARTCDATA, 1, 35, S_OK },
935 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
936 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
937 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
938 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
939 { LH_ENDCDATA, 1, 52, S_OK },
940 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
941 { CH_ENDDOCUMENT, 0, 0, S_OK },
942 { CH_ENDTEST }
945 static struct call_entry cdata_test3[] = {
946 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
947 { CH_STARTDOCUMENT, 0, 0, S_OK },
948 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
949 { LH_STARTCDATA, 1, 35, S_OK },
950 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
951 { LH_ENDCDATA, 1, 35, S_OK },
952 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
953 { CH_ENDDOCUMENT, 0, 0, S_OK },
954 { CH_ENDTEST }
957 /* this is what MSXML6 does */
958 static struct call_entry cdata_test_alt[] = {
959 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
960 { CH_STARTDOCUMENT, 1, 22, S_OK },
961 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
962 { LH_STARTCDATA, 1, 34, S_OK },
963 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
964 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
965 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
966 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
967 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
968 { LH_ENDCDATA, 6, 3, S_OK },
969 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
970 { CH_ENDDOCUMENT, 6, 7, S_OK },
971 { CH_ENDTEST }
974 static struct call_entry cdata_test2_alt[] = {
975 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
976 { CH_STARTDOCUMENT, 1, 22, S_OK },
977 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
978 { LH_STARTCDATA, 1, 34, S_OK },
979 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
980 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
981 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
982 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
983 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
984 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
985 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
986 { LH_ENDCDATA, 8, 3, S_OK },
987 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
988 { CH_ENDDOCUMENT, 8, 7, S_OK },
989 { CH_ENDTEST }
992 static struct call_entry cdata_test3_alt[] = {
993 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
994 { CH_STARTDOCUMENT, 1, 22, S_OK },
995 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
996 { LH_STARTCDATA, 1, 34, S_OK },
997 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
998 { LH_ENDCDATA, 1, 51, S_OK },
999 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
1000 { CH_ENDDOCUMENT, 1, 55, S_OK },
1001 { CH_ENDTEST }
1004 static struct attribute_entry read_test_attrs[] = {
1005 { "", "attr", "attr", "val" },
1006 { NULL }
1009 static struct call_entry read_test_seq[] = {
1010 { CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK },
1011 { CH_STARTDOCUMENT, -1, -1, S_OK },
1012 { CH_STARTELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1013 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1014 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1015 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1016 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1017 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1018 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1019 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1020 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1021 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1022 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1023 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1024 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1025 { CH_ENDELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1026 { CH_ENDDOCUMENT, -1, -1, S_OK},
1027 { CH_ENDTEST }
1030 static const char xmlspace_attr[] =
1031 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1032 "<a xml:space=\"preserve\"> Some text data </a>";
1034 static struct call_entry *expectCall;
1035 static ISAXLocator *locator;
1036 static ISAXXMLReader *g_reader;
1037 int msxml_version;
1039 static void set_expected_seq(struct call_entry *expected)
1041 expectCall = expected;
1044 /* to be called once on each tested callback return */
1045 static HRESULT get_expected_ret(void)
1047 HRESULT hr = expectCall->ret;
1048 if (expectCall->id != CH_ENDTEST) expectCall++;
1049 return hr;
1052 static HRESULT WINAPI contentHandler_QueryInterface(
1053 ISAXContentHandler* iface,
1054 REFIID riid,
1055 void **ppvObject)
1057 *ppvObject = NULL;
1059 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1061 *ppvObject = iface;
1063 else
1065 return E_NOINTERFACE;
1068 return S_OK;
1071 static ULONG WINAPI contentHandler_AddRef(
1072 ISAXContentHandler* iface)
1074 return 2;
1077 static ULONG WINAPI contentHandler_Release(
1078 ISAXContentHandler* iface)
1080 return 1;
1083 static HRESULT WINAPI contentHandler_putDocumentLocator(
1084 ISAXContentHandler* iface,
1085 ISAXLocator *pLocator)
1087 struct call_entry call;
1088 IUnknown *unk;
1089 HRESULT hr;
1091 locator = pLocator;
1093 init_call_entry(locator, &call);
1094 call.id = CH_PUTDOCUMENTLOCATOR;
1095 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1097 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
1098 EXPECT_HR(hr, E_NOINTERFACE);
1100 if (msxml_version >= 6) {
1101 ISAXAttributes *attr, *attr1;
1102 IMXAttributes *mxattr;
1104 EXPECT_REF(pLocator, 1);
1105 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1106 EXPECT_HR(hr, S_OK);
1107 EXPECT_REF(pLocator, 2);
1108 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1109 EXPECT_HR(hr, S_OK);
1110 EXPECT_REF(pLocator, 3);
1111 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1113 hr = ISAXAttributes_QueryInterface(attr, &IID_IVBSAXAttributes, (void**)&unk);
1114 EXPECT_HR(hr, E_NOINTERFACE);
1116 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk);
1117 EXPECT_HR(hr, E_NOINTERFACE);
1119 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1120 EXPECT_HR(hr, E_NOINTERFACE);
1122 ISAXAttributes_Release(attr);
1123 ISAXAttributes_Release(attr1);
1126 return get_expected_ret();
1129 static ISAXAttributes *test_attr_ptr;
1130 static HRESULT WINAPI contentHandler_startDocument(
1131 ISAXContentHandler* iface)
1133 struct call_entry call;
1135 init_call_entry(locator, &call);
1136 call.id = CH_STARTDOCUMENT;
1137 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1139 test_attr_ptr = NULL;
1141 return get_expected_ret();
1144 static HRESULT WINAPI contentHandler_endDocument(
1145 ISAXContentHandler* iface)
1147 struct call_entry call;
1149 init_call_entry(locator, &call);
1150 call.id = CH_ENDDOCUMENT;
1151 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1153 return get_expected_ret();
1156 static HRESULT WINAPI contentHandler_startPrefixMapping(
1157 ISAXContentHandler* iface,
1158 const WCHAR *prefix, int prefix_len,
1159 const WCHAR *uri, int uri_len)
1161 struct call_entry call;
1163 init_call_entry(locator, &call);
1164 call.id = CH_STARTPREFIXMAPPING;
1165 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1166 call.arg2W = SysAllocStringLen(uri, uri_len);
1167 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1169 return get_expected_ret();
1172 static HRESULT WINAPI contentHandler_endPrefixMapping(
1173 ISAXContentHandler* iface,
1174 const WCHAR *prefix, int len)
1176 struct call_entry call;
1178 init_call_entry(locator, &call);
1179 call.id = CH_ENDPREFIXMAPPING;
1180 call.arg1W = SysAllocStringLen(prefix, len);
1181 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1183 return get_expected_ret();
1186 static HRESULT WINAPI contentHandler_startElement(
1187 ISAXContentHandler* iface,
1188 const WCHAR *uri, int uri_len,
1189 const WCHAR *localname, int local_len,
1190 const WCHAR *qname, int qname_len,
1191 ISAXAttributes *saxattr)
1193 struct call_entry call;
1194 IMXAttributes *mxattr;
1195 HRESULT hr;
1196 int len;
1198 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1199 EXPECT_HR(hr, E_NOINTERFACE);
1201 init_call_entry(locator, &call);
1202 call.id = CH_STARTELEMENT;
1203 call.arg1W = SysAllocStringLen(uri, uri_len);
1204 call.arg2W = SysAllocStringLen(localname, local_len);
1205 call.arg3W = SysAllocStringLen(qname, qname_len);
1207 if(!test_attr_ptr)
1208 test_attr_ptr = saxattr;
1209 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1211 /* store actual attributes */
1212 len = 0;
1213 hr = ISAXAttributes_getLength(saxattr, &len);
1214 EXPECT_HR(hr, S_OK);
1216 if (len)
1218 VARIANT_BOOL v;
1219 int i;
1221 struct attribute_entry *attr;
1222 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1224 v = VARIANT_TRUE;
1225 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1226 EXPECT_HR(hr, S_OK);
1228 for (i = 0; i < len; i++)
1230 const WCHAR *value;
1231 int value_len;
1233 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1234 &localname, &local_len, &qname, &qname_len);
1235 EXPECT_HR(hr, S_OK);
1237 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1238 EXPECT_HR(hr, S_OK);
1240 /* if 'namespaces' switched off uri and local name contains garbage */
1241 if (v == VARIANT_FALSE && msxml_version > 0)
1243 attr[i].uriW = SysAllocStringLen(NULL, 0);
1244 attr[i].localW = SysAllocStringLen(NULL, 0);
1246 else
1248 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1249 attr[i].localW = SysAllocStringLen(localname, local_len);
1252 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1253 attr[i].valueW = SysAllocStringLen(value, value_len);
1256 call.attributes = attr;
1257 call.attr_count = len;
1260 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1262 return get_expected_ret();
1265 static HRESULT WINAPI contentHandler_endElement(
1266 ISAXContentHandler* iface,
1267 const WCHAR *uri, int uri_len,
1268 const WCHAR *localname, int local_len,
1269 const WCHAR *qname, int qname_len)
1271 struct call_entry call;
1273 init_call_entry(locator, &call);
1274 call.id = CH_ENDELEMENT;
1275 call.arg1W = SysAllocStringLen(uri, uri_len);
1276 call.arg2W = SysAllocStringLen(localname, local_len);
1277 call.arg3W = SysAllocStringLen(qname, qname_len);
1278 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1280 return get_expected_ret();
1283 static HRESULT WINAPI contentHandler_characters(
1284 ISAXContentHandler* iface,
1285 const WCHAR *chars,
1286 int len)
1288 struct call_entry call;
1290 init_call_entry(locator, &call);
1291 call.id = CH_CHARACTERS;
1292 call.arg1W = SysAllocStringLen(chars, len);
1293 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1295 return get_expected_ret();
1298 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1299 ISAXContentHandler* iface,
1300 const WCHAR *chars, int len)
1302 struct call_entry call;
1304 init_call_entry(locator, &call);
1305 call.id = CH_IGNORABLEWHITESPACE;
1306 call.arg1W = SysAllocStringLen(chars, len);
1307 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1309 return get_expected_ret();
1312 static HRESULT WINAPI contentHandler_processingInstruction(
1313 ISAXContentHandler* iface,
1314 const WCHAR *target, int target_len,
1315 const WCHAR *data, int data_len)
1317 struct call_entry call;
1319 init_call_entry(locator, &call);
1320 call.id = CH_PROCESSINGINSTRUCTION;
1321 call.arg1W = SysAllocStringLen(target, target_len);
1322 call.arg2W = SysAllocStringLen(data, data_len);
1323 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1325 return get_expected_ret();
1328 static HRESULT WINAPI contentHandler_skippedEntity(
1329 ISAXContentHandler* iface,
1330 const WCHAR *name, int len)
1332 struct call_entry call;
1334 init_call_entry(locator, &call);
1335 call.id = CH_SKIPPEDENTITY;
1336 call.arg1W = SysAllocStringLen(name, len);
1337 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1339 return get_expected_ret();
1342 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1344 contentHandler_QueryInterface,
1345 contentHandler_AddRef,
1346 contentHandler_Release,
1347 contentHandler_putDocumentLocator,
1348 contentHandler_startDocument,
1349 contentHandler_endDocument,
1350 contentHandler_startPrefixMapping,
1351 contentHandler_endPrefixMapping,
1352 contentHandler_startElement,
1353 contentHandler_endElement,
1354 contentHandler_characters,
1355 contentHandler_ignorableWhitespace,
1356 contentHandler_processingInstruction,
1357 contentHandler_skippedEntity
1360 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1362 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1363 ISAXErrorHandler* iface,
1364 REFIID riid,
1365 void **ppvObject)
1367 *ppvObject = NULL;
1369 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1371 *ppvObject = iface;
1373 else
1375 return E_NOINTERFACE;
1378 return S_OK;
1381 static ULONG WINAPI isaxerrorHandler_AddRef(
1382 ISAXErrorHandler* iface)
1384 return 2;
1387 static ULONG WINAPI isaxerrorHandler_Release(
1388 ISAXErrorHandler* iface)
1390 return 1;
1393 static HRESULT WINAPI isaxerrorHandler_error(
1394 ISAXErrorHandler* iface,
1395 ISAXLocator *pLocator,
1396 const WCHAR *pErrorMessage,
1397 HRESULT hrErrorCode)
1399 ok(0, "unexpected call\n");
1400 return S_OK;
1403 static HRESULT WINAPI isaxerrorHandler_fatalError(
1404 ISAXErrorHandler* iface,
1405 ISAXLocator *pLocator,
1406 const WCHAR *message,
1407 HRESULT hr)
1409 struct call_entry call;
1411 init_call_entry(locator, &call);
1412 call.id = EH_FATALERROR;
1413 call.ret = hr;
1415 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1417 get_expected_ret();
1418 return S_OK;
1421 static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
1422 ISAXErrorHandler* iface,
1423 ISAXLocator *pLocator,
1424 const WCHAR *pErrorMessage,
1425 HRESULT hrErrorCode)
1427 ok(0, "unexpected call\n");
1428 return S_OK;
1431 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1433 isaxerrorHandler_QueryInterface,
1434 isaxerrorHandler_AddRef,
1435 isaxerrorHandler_Release,
1436 isaxerrorHandler_error,
1437 isaxerrorHandler_fatalError,
1438 isaxerrorHandler_ignorableWarning
1441 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1443 static HRESULT WINAPI isaxattributes_QueryInterface(
1444 ISAXAttributes* iface,
1445 REFIID riid,
1446 void **ppvObject)
1448 *ppvObject = NULL;
1450 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1452 *ppvObject = iface;
1454 else
1456 return E_NOINTERFACE;
1459 return S_OK;
1462 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1464 return 2;
1467 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1469 return 1;
1472 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1474 *length = 3;
1475 return S_OK;
1478 static HRESULT WINAPI isaxattributes_getURI(
1479 ISAXAttributes* iface,
1480 int nIndex,
1481 const WCHAR **pUrl,
1482 int *pUriSize)
1484 ok(0, "unexpected call\n");
1485 return E_NOTIMPL;
1488 static HRESULT WINAPI isaxattributes_getLocalName(
1489 ISAXAttributes* iface,
1490 int nIndex,
1491 const WCHAR **pLocalName,
1492 int *pLocalNameLength)
1494 ok(0, "unexpected call\n");
1495 return E_NOTIMPL;
1498 static HRESULT WINAPI isaxattributes_getQName(
1499 ISAXAttributes* iface,
1500 int index,
1501 const WCHAR **QName,
1502 int *QNameLength)
1504 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1505 {'a','t','t','r','2','j','u','n','k',0},
1506 {'a','t','t','r','3',0}};
1507 static const int attrqnamelen[] = {7, 5, 5};
1509 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1511 if (index >= 0 && index <= 2) {
1512 *QName = attrqnamesW[index];
1513 *QNameLength = attrqnamelen[index];
1514 } else {
1515 *QName = NULL;
1516 *QNameLength = 0;
1519 return S_OK;
1522 static HRESULT WINAPI isaxattributes_getName(
1523 ISAXAttributes* iface,
1524 int nIndex,
1525 const WCHAR **pUri,
1526 int * pUriLength,
1527 const WCHAR ** pLocalName,
1528 int * pLocalNameSize,
1529 const WCHAR ** pQName,
1530 int * pQNameLength)
1532 ok(0, "unexpected call\n");
1533 return E_NOTIMPL;
1536 static HRESULT WINAPI isaxattributes_getIndexFromName(
1537 ISAXAttributes* iface,
1538 const WCHAR * pUri,
1539 int cUriLength,
1540 const WCHAR * pLocalName,
1541 int cocalNameLength,
1542 int * index)
1544 ok(0, "unexpected call\n");
1545 return E_NOTIMPL;
1548 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1549 ISAXAttributes* iface,
1550 const WCHAR * pQName,
1551 int nQNameLength,
1552 int * index)
1554 ok(0, "unexpected call\n");
1555 return E_NOTIMPL;
1558 static HRESULT WINAPI isaxattributes_getType(
1559 ISAXAttributes* iface,
1560 int nIndex,
1561 const WCHAR ** pType,
1562 int * pTypeLength)
1564 ok(0, "unexpected call\n");
1565 return E_NOTIMPL;
1568 static HRESULT WINAPI isaxattributes_getTypeFromName(
1569 ISAXAttributes* iface,
1570 const WCHAR * pUri,
1571 int nUri,
1572 const WCHAR * pLocalName,
1573 int nLocalName,
1574 const WCHAR ** pType,
1575 int * nType)
1577 ok(0, "unexpected call\n");
1578 return E_NOTIMPL;
1581 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1582 ISAXAttributes* iface,
1583 const WCHAR * pQName,
1584 int nQName,
1585 const WCHAR ** pType,
1586 int * nType)
1588 ok(0, "unexpected call\n");
1589 return E_NOTIMPL;
1592 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1593 const WCHAR **value, int *nValue)
1595 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1596 {'a','2','j','u','n','k',0},
1597 {'<','&','"','>','\'',0}};
1598 static const int attrvalueslen[] = {2, 2, 5};
1600 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1602 if (index >= 0 && index <= 2) {
1603 *value = attrvaluesW[index];
1604 *nValue = attrvalueslen[index];
1605 } else {
1606 *value = NULL;
1607 *nValue = 0;
1610 return S_OK;
1613 static HRESULT WINAPI isaxattributes_getValueFromName(
1614 ISAXAttributes* iface,
1615 const WCHAR * pUri,
1616 int nUri,
1617 const WCHAR * pLocalName,
1618 int nLocalName,
1619 const WCHAR ** pValue,
1620 int * nValue)
1622 ok(0, "unexpected call\n");
1623 return E_NOTIMPL;
1626 static HRESULT WINAPI isaxattributes_getValueFromQName(
1627 ISAXAttributes* iface,
1628 const WCHAR * pQName,
1629 int nQName,
1630 const WCHAR ** pValue,
1631 int * nValue)
1633 ok(0, "unexpected call\n");
1634 return E_NOTIMPL;
1637 static const ISAXAttributesVtbl SAXAttributesVtbl =
1639 isaxattributes_QueryInterface,
1640 isaxattributes_AddRef,
1641 isaxattributes_Release,
1642 isaxattributes_getLength,
1643 isaxattributes_getURI,
1644 isaxattributes_getLocalName,
1645 isaxattributes_getQName,
1646 isaxattributes_getName,
1647 isaxattributes_getIndexFromName,
1648 isaxattributes_getIndexFromQName,
1649 isaxattributes_getType,
1650 isaxattributes_getTypeFromName,
1651 isaxattributes_getTypeFromQName,
1652 isaxattributes_getValue,
1653 isaxattributes_getValueFromName,
1654 isaxattributes_getValueFromQName
1657 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1659 struct saxlexicalhandler
1661 ISAXLexicalHandler ISAXLexicalHandler_iface;
1662 LONG ref;
1664 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1667 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1669 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1672 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1674 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1676 *out = NULL;
1678 if (IsEqualGUID(riid, &IID_IUnknown))
1680 *out = iface;
1681 ok(0, "got unexpected IID_IUnknown query\n");
1683 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1685 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1686 *out = iface;
1689 if (*out)
1690 ISAXLexicalHandler_AddRef(iface);
1691 else
1692 return E_NOINTERFACE;
1694 return S_OK;
1697 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1699 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1700 return InterlockedIncrement(&handler->ref);
1703 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1705 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1706 return InterlockedDecrement(&handler->ref);
1709 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1710 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1711 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1713 ok(0, "call not expected\n");
1714 return E_NOTIMPL;
1717 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1719 ok(0, "call not expected\n");
1720 return E_NOTIMPL;
1723 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1724 const WCHAR * pName, int nName)
1726 ok(0, "call not expected\n");
1727 return E_NOTIMPL;
1730 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1731 const WCHAR * pName, int nName)
1733 ok(0, "call not expected\n");
1734 return E_NOTIMPL;
1737 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1739 struct call_entry call;
1741 init_call_entry(locator, &call);
1742 call.id = LH_STARTCDATA;
1743 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1745 return get_expected_ret();
1748 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1750 struct call_entry call;
1752 init_call_entry(locator, &call);
1753 call.id = LH_ENDCDATA;
1754 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1756 return get_expected_ret();
1759 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1760 const WCHAR * pChars, int nChars)
1762 ok(0, "call not expected\n");
1763 return E_NOTIMPL;
1766 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1768 isaxlexical_QueryInterface,
1769 isaxlexical_AddRef,
1770 isaxlexical_Release,
1771 isaxlexical_startDTD,
1772 isaxlexical_endDTD,
1773 isaxlexical_startEntity,
1774 isaxlexical_endEntity,
1775 isaxlexical_startCDATA,
1776 isaxlexical_endCDATA,
1777 isaxlexical_comment
1780 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1782 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1783 handler->ref = 1;
1784 handler->qi_hr = hr;
1787 struct saxdeclhandler
1789 ISAXDeclHandler ISAXDeclHandler_iface;
1790 LONG ref;
1792 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1795 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1797 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1800 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1802 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1804 *out = NULL;
1806 if (IsEqualGUID(riid, &IID_IUnknown))
1808 *out = iface;
1809 ok(0, "got unexpected IID_IUnknown query\n");
1811 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1813 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1814 *out = iface;
1817 if (*out)
1818 ISAXDeclHandler_AddRef(iface);
1819 else
1820 return E_NOINTERFACE;
1822 return S_OK;
1825 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1827 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1828 return InterlockedIncrement(&handler->ref);
1831 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1833 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1834 return InterlockedDecrement(&handler->ref);
1837 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1838 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1840 ok(0, "call not expected\n");
1841 return E_NOTIMPL;
1844 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1845 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1846 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1847 int nValueDefault, const WCHAR * pValue, int nValue)
1849 ok(0, "call not expected\n");
1850 return E_NOTIMPL;
1853 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1854 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1856 ok(0, "call not expected\n");
1857 return E_NOTIMPL;
1860 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1861 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1862 const WCHAR * pSystemId, int nSystemId)
1864 ok(0, "call not expected\n");
1865 return E_NOTIMPL;
1868 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1870 isaxdecl_QueryInterface,
1871 isaxdecl_AddRef,
1872 isaxdecl_Release,
1873 isaxdecl_elementDecl,
1874 isaxdecl_attributeDecl,
1875 isaxdecl_internalEntityDecl,
1876 isaxdecl_externalEntityDecl
1879 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1881 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1882 handler->ref = 1;
1883 handler->qi_hr = hr;
1886 typedef struct mxwriter_write_test_t {
1887 BOOL last;
1888 const BYTE *data;
1889 DWORD cb;
1890 BOOL null_written;
1891 BOOL fail_write;
1892 } mxwriter_write_test;
1894 typedef struct mxwriter_stream_test_t {
1895 VARIANT_BOOL bom;
1896 const char *encoding;
1897 mxwriter_write_test expected_writes[4];
1898 } mxwriter_stream_test;
1900 static const mxwriter_write_test *current_write_test;
1901 static DWORD current_stream_test_index;
1903 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1905 *ppvObject = NULL;
1907 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1908 *ppvObject = iface;
1909 else
1910 return E_NOINTERFACE;
1912 return S_OK;
1915 static ULONG WINAPI istream_AddRef(IStream *iface)
1917 return 2;
1920 static ULONG WINAPI istream_Release(IStream *iface)
1922 return 1;
1925 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1927 ok(0, "unexpected call\n");
1928 return E_NOTIMPL;
1931 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1933 ok(0, "unexpected call\n");
1934 return E_NOTIMPL;
1937 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1938 ULARGE_INTEGER *plibNewPosition)
1940 ok(0, "unexpected call\n");
1941 return E_NOTIMPL;
1944 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1946 ok(0, "unexpected call\n");
1947 return E_NOTIMPL;
1950 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1951 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1953 ok(0, "unexpected call\n");
1954 return E_NOTIMPL;
1957 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1959 ok(0, "unexpected call\n");
1960 return E_NOTIMPL;
1963 static HRESULT WINAPI istream_Revert(IStream *iface)
1965 ok(0, "unexpected call\n");
1966 return E_NOTIMPL;
1969 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1970 ULARGE_INTEGER cb, DWORD dwLockType)
1972 ok(0, "unexpected call\n");
1973 return E_NOTIMPL;
1976 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1977 ULARGE_INTEGER cb, DWORD dwLockType)
1979 ok(0, "unexpected call\n");
1980 return E_NOTIMPL;
1983 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1985 return E_NOTIMPL;
1988 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1990 ok(0, "unexpected call\n");
1991 return E_NOTIMPL;
1994 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1996 BOOL fail = FALSE;
1998 ok(pv != NULL, "pv == NULL\n");
2000 if(current_write_test->last) {
2001 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
2002 return E_FAIL;
2005 fail = current_write_test->fail_write;
2007 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
2008 current_write_test->cb, cb, current_stream_test_index);
2010 if(!pcbWritten)
2011 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
2012 else
2013 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
2015 ++current_write_test;
2017 if(pcbWritten)
2018 *pcbWritten = cb;
2020 return fail ? E_FAIL : S_OK;
2023 static const IStreamVtbl mxstreamVtbl = {
2024 istream_QueryInterface,
2025 istream_AddRef,
2026 istream_Release,
2027 istream_Read,
2028 mxstream_Write,
2029 istream_Seek,
2030 istream_SetSize,
2031 istream_CopyTo,
2032 istream_Commit,
2033 istream_Revert,
2034 istream_LockRegion,
2035 istream_UnlockRegion,
2036 istream_Stat,
2037 istream_Clone
2040 static IStream mxstream = { &mxstreamVtbl };
2042 static int read_cnt;
2044 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
2046 static const char *ret_str;
2048 if(!read_cnt)
2049 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
2050 else if(read_cnt < 5)
2051 ret_str = "<elem attr=\"val\">text</elem>";
2052 else if(read_cnt == 5)
2053 ret_str = "</rootelem>\n";
2054 else
2055 ret_str = "";
2057 read_cnt++;
2058 strcpy(pv, ret_str);
2059 *pcbRead = strlen(ret_str);
2060 return S_OK;
2063 static const IStreamVtbl instreamVtbl = {
2064 istream_QueryInterface,
2065 istream_AddRef,
2066 istream_Release,
2067 instream_Read,
2068 istream_Write,
2069 istream_Seek,
2070 istream_SetSize,
2071 istream_CopyTo,
2072 istream_Commit,
2073 istream_Revert,
2074 istream_LockRegion,
2075 istream_UnlockRegion,
2076 istream_Stat,
2077 istream_Clone
2080 static IStream instream = { &instreamVtbl };
2082 static struct msxmlsupported_data_t reader_support_data[] =
2084 { &CLSID_SAXXMLReader, "SAXReader" },
2085 { &CLSID_SAXXMLReader30, "SAXReader30" },
2086 { &CLSID_SAXXMLReader40, "SAXReader40" },
2087 { &CLSID_SAXXMLReader60, "SAXReader60" },
2088 { NULL }
2091 static struct saxlexicalhandler lexicalhandler;
2092 static struct saxdeclhandler declhandler;
2094 static IStream *create_test_stream(const char *data, int len)
2096 ULARGE_INTEGER size;
2097 LARGE_INTEGER pos;
2098 IStream *stream;
2099 ULONG written;
2101 if (len == -1) len = strlen(data);
2102 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2103 size.QuadPart = len;
2104 IStream_SetSize(stream, size);
2105 IStream_Write(stream, data, len, &written);
2106 pos.QuadPart = 0;
2107 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2109 return stream;
2112 static void test_saxreader(void)
2114 const struct msxmlsupported_data_t *table = reader_support_data;
2115 HRESULT hr;
2116 ISAXXMLReader *reader = NULL;
2117 VARIANT var;
2118 ISAXContentHandler *content;
2119 ISAXErrorHandler *lpErrorHandler;
2120 SAFEARRAY *sa;
2121 SAFEARRAYBOUND SADim[1];
2122 char *ptr = NULL;
2123 IStream *stream;
2124 ULONG written;
2125 HANDLE file;
2126 static const CHAR testXmlA[] = "test.xml";
2127 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2128 IXMLDOMDocument *doc;
2129 char seqname[50];
2130 VARIANT_BOOL v;
2132 while (table->clsid)
2134 struct call_entry *test_seq;
2135 ISAXEntityResolver *resolver;
2136 BSTR str;
2138 if (!is_clsid_supported(table->clsid, reader_support_data))
2140 table++;
2141 continue;
2144 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2145 EXPECT_HR(hr, S_OK);
2146 g_reader = reader;
2148 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2149 msxml_version = 4;
2150 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2151 msxml_version = 6;
2152 else
2153 msxml_version = 0;
2155 /* crashes on old versions */
2156 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2157 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2159 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2160 EXPECT_HR(hr, E_POINTER);
2162 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2163 EXPECT_HR(hr, E_POINTER);
2166 hr = ISAXXMLReader_getContentHandler(reader, &content);
2167 EXPECT_HR(hr, S_OK);
2168 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2170 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2171 EXPECT_HR(hr, S_OK);
2172 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2174 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2175 EXPECT_HR(hr, S_OK);
2177 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2178 EXPECT_HR(hr, S_OK);
2180 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2181 EXPECT_HR(hr, S_OK);
2183 hr = ISAXXMLReader_getContentHandler(reader, &content);
2184 EXPECT_HR(hr, S_OK);
2185 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2187 V_VT(&var) = VT_BSTR;
2188 V_BSTR(&var) = SysAllocString(szSimpleXML);
2190 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2191 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2192 test_seq = content_handler_test1_alternate;
2193 else
2194 test_seq = content_handler_test1;
2195 set_expected_seq(test_seq);
2196 hr = ISAXXMLReader_parse(reader, var);
2197 EXPECT_HR(hr, S_OK);
2198 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2200 VariantClear(&var);
2202 SADim[0].lLbound = 0;
2203 SADim[0].cElements = sizeof(testXML)-1;
2204 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2205 SafeArrayAccessData(sa, (void**)&ptr);
2206 memcpy(ptr, testXML, sizeof(testXML)-1);
2207 SafeArrayUnaccessData(sa);
2208 V_VT(&var) = VT_ARRAY|VT_UI1;
2209 V_ARRAY(&var) = sa;
2211 set_expected_seq(test_seq);
2212 hr = ISAXXMLReader_parse(reader, var);
2213 EXPECT_HR(hr, S_OK);
2214 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2216 SafeArrayDestroy(sa);
2218 stream = create_test_stream(testXML, -1);
2219 V_VT(&var) = VT_UNKNOWN;
2220 V_UNKNOWN(&var) = (IUnknown*)stream;
2222 set_expected_seq(test_seq);
2223 hr = ISAXXMLReader_parse(reader, var);
2224 EXPECT_HR(hr, S_OK);
2225 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2227 IStream_Release(stream);
2229 stream = create_test_stream(test_attributes, -1);
2230 V_VT(&var) = VT_UNKNOWN;
2231 V_UNKNOWN(&var) = (IUnknown*)stream;
2233 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2234 test_seq = content_handler_test_attributes_alternate_4;
2235 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2236 test_seq = content_handler_test_attributes_alternate_6;
2237 else
2238 test_seq = content_handler_test_attributes;
2240 set_expected_seq(test_seq);
2241 hr = ISAXXMLReader_parse(reader, var);
2242 EXPECT_HR(hr, S_OK);
2244 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2245 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2246 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2247 else
2248 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2250 IStream_Release(stream);
2252 V_VT(&var) = VT_UNKNOWN;
2253 V_UNKNOWN(&var) = (IUnknown*)&instream;
2255 test_seq = read_test_seq;
2256 read_cnt = 0;
2257 set_expected_seq(test_seq);
2258 hr = ISAXXMLReader_parse(reader, var);
2259 EXPECT_HR(hr, S_OK);
2260 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
2261 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
2263 V_VT(&var) = VT_BSTR;
2264 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2266 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2267 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2268 test_seq = content_handler_test2_alternate;
2269 else
2270 test_seq = content_handler_test2;
2272 set_expected_seq(test_seq);
2273 hr = ISAXXMLReader_parse(reader, var);
2274 EXPECT_HR(hr, S_OK);
2275 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2277 VariantClear(&var);
2279 /* from file url */
2280 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2281 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2282 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2283 CloseHandle(file);
2285 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2286 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2287 test_seq = content_handler_test1_alternate;
2288 else
2289 test_seq = content_handler_test1;
2290 set_expected_seq(test_seq);
2291 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2292 EXPECT_HR(hr, S_OK);
2293 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2295 /* error handler */
2296 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2297 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2298 test_seq = content_handler_testerror_alternate;
2299 else
2300 test_seq = content_handler_testerror;
2301 set_expected_seq(test_seq);
2302 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2303 EXPECT_HR(hr, E_FAIL);
2304 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2306 /* callback ret values */
2307 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2308 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2310 test_seq = content_handler_test_callback_rets_alt;
2311 set_expected_seq(test_seq);
2312 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2313 EXPECT_HR(hr, S_OK);
2315 else
2317 test_seq = content_handler_test_callback_rets;
2318 set_expected_seq(test_seq);
2319 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2320 EXPECT_HR(hr, S_FALSE);
2322 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2324 DeleteFileA(testXmlA);
2326 /* parse from IXMLDOMDocument */
2327 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2328 &IID_IXMLDOMDocument, (void**)&doc);
2329 EXPECT_HR(hr, S_OK);
2331 str = SysAllocString(szSimpleXML);
2332 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2333 EXPECT_HR(hr, S_OK);
2334 SysFreeString(str);
2336 V_VT(&var) = VT_UNKNOWN;
2337 V_UNKNOWN(&var) = (IUnknown*)doc;
2339 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2340 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2341 test_seq = content_handler_test2_alternate;
2342 else
2343 test_seq = content_handler_test2;
2345 set_expected_seq(test_seq);
2346 hr = ISAXXMLReader_parse(reader, var);
2347 EXPECT_HR(hr, S_OK);
2348 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2349 IXMLDOMDocument_Release(doc);
2351 /* xml:space test */
2352 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2353 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2355 test_seq = xmlspaceattr_test_alternate;
2357 else
2358 test_seq = xmlspaceattr_test;
2360 set_expected_seq(test_seq);
2361 V_VT(&var) = VT_BSTR;
2362 V_BSTR(&var) = _bstr_(xmlspace_attr);
2363 hr = ISAXXMLReader_parse(reader, var);
2364 EXPECT_HR(hr, S_OK);
2366 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2367 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2369 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2371 else
2372 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2374 /* switch off 'namespaces' feature */
2375 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2376 EXPECT_HR(hr, S_OK);
2378 stream = create_test_stream(test_attributes, -1);
2379 V_VT(&var) = VT_UNKNOWN;
2380 V_UNKNOWN(&var) = (IUnknown*)stream;
2382 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2383 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2385 test_seq = content_handler_test_attributes_alt_no_ns;
2387 else
2388 test_seq = content_handler_test_attributes;
2390 set_expected_seq(test_seq);
2391 hr = ISAXXMLReader_parse(reader, var);
2392 EXPECT_HR(hr, S_OK);
2393 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2394 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2395 EXPECT_HR(hr, S_OK);
2397 /* switch off 'namespace-prefixes' feature */
2398 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2399 EXPECT_HR(hr, S_OK);
2401 stream = create_test_stream(test_attributes, -1);
2402 V_VT(&var) = VT_UNKNOWN;
2403 V_UNKNOWN(&var) = (IUnknown*)stream;
2405 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2406 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2408 test_seq = content_handler_test_attributes_alt_no_prefix;
2410 else
2411 test_seq = content_handler_test_attributes_no_prefix;
2413 set_expected_seq(test_seq);
2414 hr = ISAXXMLReader_parse(reader, var);
2415 EXPECT_HR(hr, S_OK);
2416 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2418 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2419 EXPECT_HR(hr, S_OK);
2421 /* attribute normalization */
2422 stream = create_test_stream(attribute_normalize, -1);
2423 V_VT(&var) = VT_UNKNOWN;
2424 V_UNKNOWN(&var) = (IUnknown*)stream;
2426 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2427 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2429 test_seq = attribute_norm_alt;
2431 else
2432 test_seq = attribute_norm;
2434 set_expected_seq(test_seq);
2435 hr = ISAXXMLReader_parse(reader, var);
2436 EXPECT_HR(hr, S_OK);
2437 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2438 IStream_Release(stream);
2440 resolver = (void*)0xdeadbeef;
2441 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2442 ok(hr == S_OK, "got 0x%08x\n", hr);
2443 ok(resolver == NULL, "got %p\n", resolver);
2445 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2446 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2448 /* CDATA sections */
2449 init_saxlexicalhandler(&lexicalhandler, S_OK);
2451 V_VT(&var) = VT_UNKNOWN;
2452 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2453 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2454 ok(hr == S_OK, "got 0x%08x\n", hr);
2456 stream = create_test_stream(test_cdata_xml, -1);
2457 V_VT(&var) = VT_UNKNOWN;
2458 V_UNKNOWN(&var) = (IUnknown*)stream;
2460 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2461 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2462 test_seq = cdata_test_alt;
2463 else
2464 test_seq = cdata_test;
2466 set_expected_seq(test_seq);
2467 hr = ISAXXMLReader_parse(reader, var);
2468 ok(hr == S_OK, "got 0x%08x\n", hr);
2469 sprintf(seqname, "%s: cdata test", table->name);
2470 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2472 IStream_Release(stream);
2474 /* 2. CDATA sections */
2475 stream = create_test_stream(test2_cdata_xml, -1);
2476 V_VT(&var) = VT_UNKNOWN;
2477 V_UNKNOWN(&var) = (IUnknown*)stream;
2479 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2480 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2481 test_seq = cdata_test2_alt;
2482 else
2483 test_seq = cdata_test2;
2485 set_expected_seq(test_seq);
2486 hr = ISAXXMLReader_parse(reader, var);
2487 ok(hr == S_OK, "got 0x%08x\n", hr);
2488 sprintf(seqname, "%s: cdata test 2", table->name);
2489 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2491 IStream_Release(stream);
2493 /* 3. CDATA sections */
2494 stream = create_test_stream(test3_cdata_xml, -1);
2495 V_VT(&var) = VT_UNKNOWN;
2496 V_UNKNOWN(&var) = (IUnknown*)stream;
2498 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2499 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2500 test_seq = cdata_test3_alt;
2501 else
2502 test_seq = cdata_test3;
2504 set_expected_seq(test_seq);
2505 hr = ISAXXMLReader_parse(reader, var);
2506 ok(hr == S_OK, "got 0x%08x\n", hr);
2507 sprintf(seqname, "%s: cdata test 3", table->name);
2508 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2510 IStream_Release(stream);
2512 ISAXXMLReader_Release(reader);
2513 table++;
2516 free_bstrs();
2519 struct saxreader_props_test_t
2521 const char *prop_name;
2522 IUnknown *iface;
2525 static const struct saxreader_props_test_t props_test_data[] = {
2526 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2527 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2528 { 0 }
2531 static void test_saxreader_properties(void)
2533 const struct saxreader_props_test_t *ptr = props_test_data;
2534 ISAXXMLReader *reader;
2535 HRESULT hr;
2536 VARIANT v;
2537 BSTR str;
2539 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2540 &IID_ISAXXMLReader, (void**)&reader);
2541 EXPECT_HR(hr, S_OK);
2543 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2544 EXPECT_HR(hr, E_POINTER);
2546 while (ptr->prop_name)
2548 VARIANT varref;
2549 LONG ref;
2551 init_saxlexicalhandler(&lexicalhandler, S_OK);
2552 init_saxdeclhandler(&declhandler, S_OK);
2554 V_VT(&v) = VT_EMPTY;
2555 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2556 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2557 EXPECT_HR(hr, S_OK);
2558 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2559 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2561 /* VT_UNKNOWN */
2562 V_VT(&v) = VT_UNKNOWN;
2563 V_UNKNOWN(&v) = ptr->iface;
2564 ref = get_refcount(ptr->iface);
2565 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2566 EXPECT_HR(hr, S_OK);
2567 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2569 /* VT_DISPATCH */
2570 V_VT(&v) = VT_DISPATCH;
2571 V_UNKNOWN(&v) = ptr->iface;
2572 ref = get_refcount(ptr->iface);
2573 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2574 EXPECT_HR(hr, S_OK);
2575 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2577 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2578 V_VT(&varref) = VT_UNKNOWN;
2579 V_UNKNOWN(&varref) = ptr->iface;
2581 V_VT(&v) = VT_VARIANT|VT_BYREF;
2582 V_VARIANTREF(&v) = &varref;
2583 ref = get_refcount(ptr->iface);
2584 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2585 EXPECT_HR(hr, S_OK);
2586 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2588 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2589 V_VT(&varref) = VT_DISPATCH;
2590 V_UNKNOWN(&varref) = ptr->iface;
2592 V_VT(&v) = VT_VARIANT|VT_BYREF;
2593 V_VARIANTREF(&v) = &varref;
2594 ref = get_refcount(ptr->iface);
2595 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2596 EXPECT_HR(hr, S_OK);
2597 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2599 V_VT(&v) = VT_EMPTY;
2600 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2602 ref = get_refcount(ptr->iface);
2603 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2604 EXPECT_HR(hr, S_OK);
2605 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2606 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2607 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2608 VariantClear(&v);
2610 V_VT(&v) = VT_EMPTY;
2611 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2612 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2613 EXPECT_HR(hr, S_OK);
2615 V_VT(&v) = VT_EMPTY;
2616 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2617 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2618 EXPECT_HR(hr, S_OK);
2619 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2620 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2622 V_VT(&v) = VT_UNKNOWN;
2623 V_UNKNOWN(&v) = ptr->iface;
2624 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2625 EXPECT_HR(hr, S_OK);
2627 /* only VT_EMPTY seems to be valid to reset property */
2628 V_VT(&v) = VT_I4;
2629 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2630 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2631 EXPECT_HR(hr, E_INVALIDARG);
2633 V_VT(&v) = VT_EMPTY;
2634 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2635 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2636 EXPECT_HR(hr, S_OK);
2637 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2638 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2639 VariantClear(&v);
2641 V_VT(&v) = VT_UNKNOWN;
2642 V_UNKNOWN(&v) = NULL;
2643 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2644 EXPECT_HR(hr, S_OK);
2646 V_VT(&v) = VT_EMPTY;
2647 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2648 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2649 EXPECT_HR(hr, S_OK);
2650 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2651 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2653 /* block QueryInterface on handler riid */
2654 V_VT(&v) = VT_UNKNOWN;
2655 V_UNKNOWN(&v) = ptr->iface;
2656 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2657 EXPECT_HR(hr, S_OK);
2659 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2660 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2662 V_VT(&v) = VT_UNKNOWN;
2663 V_UNKNOWN(&v) = ptr->iface;
2664 EXPECT_REF(ptr->iface, 1);
2665 ref = get_refcount(ptr->iface);
2666 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2667 EXPECT_HR(hr, E_NOINTERFACE);
2668 EXPECT_REF(ptr->iface, 1);
2670 V_VT(&v) = VT_EMPTY;
2671 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2672 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2673 EXPECT_HR(hr, S_OK);
2674 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2675 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2677 ptr++;
2678 free_bstrs();
2681 ISAXXMLReader_Release(reader);
2683 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2684 return;
2686 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2687 &IID_ISAXXMLReader, (void**)&reader);
2688 EXPECT_HR(hr, S_OK);
2690 /* xmldecl-version property */
2691 V_VT(&v) = VT_EMPTY;
2692 V_BSTR(&v) = (void*)0xdeadbeef;
2693 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2694 EXPECT_HR(hr, S_OK);
2695 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2696 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2698 /* stream without declaration */
2699 V_VT(&v) = VT_BSTR;
2700 V_BSTR(&v) = _bstr_("<element></element>");
2701 hr = ISAXXMLReader_parse(reader, v);
2702 EXPECT_HR(hr, S_OK);
2704 V_VT(&v) = VT_EMPTY;
2705 V_BSTR(&v) = (void*)0xdeadbeef;
2706 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2707 EXPECT_HR(hr, S_OK);
2708 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2709 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2711 /* stream with declaration */
2712 V_VT(&v) = VT_BSTR;
2713 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2714 hr = ISAXXMLReader_parse(reader, v);
2715 EXPECT_HR(hr, S_OK);
2717 /* VT_BSTR|VT_BYREF input type */
2718 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2719 V_VT(&v) = VT_BSTR|VT_BYREF;
2720 V_BSTRREF(&v) = &str;
2721 hr = ISAXXMLReader_parse(reader, v);
2722 EXPECT_HR(hr, S_OK);
2724 V_VT(&v) = VT_EMPTY;
2725 V_BSTR(&v) = (void*)0xdeadbeef;
2726 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2727 EXPECT_HR(hr, S_OK);
2728 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2729 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2730 VariantClear(&v);
2732 ISAXXMLReader_Release(reader);
2733 free_bstrs();
2736 struct feature_ns_entry_t {
2737 const GUID *guid;
2738 const char *clsid;
2739 VARIANT_BOOL value;
2740 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2743 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2744 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2745 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2746 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2747 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2748 { 0 }
2751 static const char *feature_names[] = {
2752 "http://xml.org/sax/features/namespaces",
2753 "http://xml.org/sax/features/namespace-prefixes",
2757 static void test_saxreader_features(void)
2759 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2760 ISAXXMLReader *reader;
2762 while (entry->guid)
2764 VARIANT_BOOL value;
2765 const char **name;
2766 HRESULT hr;
2768 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2769 if (hr != S_OK)
2771 win_skip("can't create %s instance\n", entry->clsid);
2772 entry++;
2773 continue;
2776 name = feature_names;
2777 while (*name)
2779 value = 0xc;
2780 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2781 EXPECT_HR(hr, S_OK);
2782 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2784 value = 0xc;
2785 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2786 EXPECT_HR(hr, S_OK);
2788 value = 0xd;
2789 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2790 EXPECT_HR(hr, S_OK);
2791 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2793 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2794 EXPECT_HR(hr, S_OK);
2795 value = 0xd;
2796 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2797 EXPECT_HR(hr, S_OK);
2798 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2800 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2801 EXPECT_HR(hr, S_OK);
2802 value = 0xd;
2803 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2804 EXPECT_HR(hr, S_OK);
2805 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2807 name++;
2810 ISAXXMLReader_Release(reader);
2812 entry++;
2816 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2817 static const CHAR UTF8BOMTest[] =
2818 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2819 "<a></a>\n";
2821 struct enc_test_entry_t {
2822 const GUID *guid;
2823 const char *clsid;
2824 const char *data;
2825 HRESULT hr;
2826 BOOL todo;
2829 static const struct enc_test_entry_t encoding_test_data[] = {
2830 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE },
2831 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE },
2832 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE },
2833 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE },
2834 { 0 }
2837 static void test_saxreader_encoding(void)
2839 const struct enc_test_entry_t *entry = encoding_test_data;
2840 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2841 static const CHAR testXmlA[] = "test.xml";
2843 while (entry->guid)
2845 ISAXXMLReader *reader;
2846 VARIANT input;
2847 DWORD written;
2848 HANDLE file;
2849 HRESULT hr;
2851 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2852 if (hr != S_OK)
2854 win_skip("can't create %s instance\n", entry->clsid);
2855 entry++;
2856 continue;
2859 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2860 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2861 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2862 CloseHandle(file);
2864 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2865 if (entry->todo)
2866 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2867 else
2868 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2870 DeleteFileA(testXmlA);
2872 /* try BSTR input with no BOM or '<?xml' instruction */
2873 V_VT(&input) = VT_BSTR;
2874 V_BSTR(&input) = _bstr_("<element></element>");
2875 hr = ISAXXMLReader_parse(reader, input);
2876 EXPECT_HR(hr, S_OK);
2878 ISAXXMLReader_Release(reader);
2880 free_bstrs();
2881 entry++;
2885 static void test_mxwriter_handlers(void)
2887 IMXWriter *writer;
2888 HRESULT hr;
2889 int i;
2891 static REFIID riids[] =
2893 &IID_ISAXContentHandler,
2894 &IID_ISAXLexicalHandler,
2895 &IID_ISAXDeclHandler,
2896 &IID_ISAXDTDHandler,
2897 &IID_ISAXErrorHandler,
2898 &IID_IVBSAXDeclHandler,
2899 &IID_IVBSAXLexicalHandler,
2900 &IID_IVBSAXContentHandler,
2901 &IID_IVBSAXDTDHandler,
2902 &IID_IVBSAXErrorHandler
2905 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2906 &IID_IMXWriter, (void**)&writer);
2907 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2909 EXPECT_REF(writer, 1);
2911 for (i = 0; i < sizeof(riids)/sizeof(REFIID); i++)
2913 IUnknown *handler;
2914 IMXWriter *writer2;
2916 /* handler from IMXWriter */
2917 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
2918 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2919 EXPECT_REF(writer, 2);
2920 EXPECT_REF(handler, 2);
2922 /* IMXWriter from a handler */
2923 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2924 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2925 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2926 EXPECT_REF(writer, 3);
2927 EXPECT_REF(writer2, 3);
2928 IMXWriter_Release(writer2);
2929 IUnknown_Release(handler);
2932 IMXWriter_Release(writer);
2935 static struct msxmlsupported_data_t mxwriter_support_data[] =
2937 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2938 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2939 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2940 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2941 { NULL }
2944 static struct msxmlsupported_data_t mxattributes_support_data[] =
2946 { &CLSID_SAXAttributes, "SAXAttributes" },
2947 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2948 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2949 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2950 { NULL }
2953 struct mxwriter_props_t
2955 const GUID *clsid;
2956 VARIANT_BOOL bom;
2957 VARIANT_BOOL disable_escape;
2958 VARIANT_BOOL indent;
2959 VARIANT_BOOL omitdecl;
2960 VARIANT_BOOL standalone;
2961 const char *encoding;
2964 static const struct mxwriter_props_t mxwriter_default_props[] =
2966 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2967 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2968 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2969 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2970 { NULL }
2973 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2975 int i = 0;
2977 while (table->clsid)
2979 IMXWriter *writer;
2980 VARIANT_BOOL b;
2981 BSTR encoding;
2982 HRESULT hr;
2984 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2986 table++;
2987 i++;
2988 continue;
2991 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2992 &IID_IMXWriter, (void**)&writer);
2993 EXPECT_HR(hr, S_OK);
2995 b = !table->bom;
2996 hr = IMXWriter_get_byteOrderMark(writer, &b);
2997 EXPECT_HR(hr, S_OK);
2998 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
3000 b = !table->disable_escape;
3001 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
3002 EXPECT_HR(hr, S_OK);
3003 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
3004 table->disable_escape);
3006 b = !table->indent;
3007 hr = IMXWriter_get_indent(writer, &b);
3008 EXPECT_HR(hr, S_OK);
3009 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
3011 b = !table->omitdecl;
3012 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
3013 EXPECT_HR(hr, S_OK);
3014 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
3016 b = !table->standalone;
3017 hr = IMXWriter_get_standalone(writer, &b);
3018 EXPECT_HR(hr, S_OK);
3019 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
3021 hr = IMXWriter_get_encoding(writer, &encoding);
3022 EXPECT_HR(hr, S_OK);
3023 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
3024 i, wine_dbgstr_w(encoding), table->encoding);
3025 SysFreeString(encoding);
3027 IMXWriter_Release(writer);
3029 table++;
3030 i++;
3034 static void test_mxwriter_properties(void)
3036 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
3037 static const WCHAR testW[] = {'t','e','s','t',0};
3038 ISAXContentHandler *content;
3039 IMXWriter *writer;
3040 VARIANT_BOOL b;
3041 HRESULT hr;
3042 BSTR str, str2;
3043 VARIANT dest;
3045 test_mxwriter_default_properties(mxwriter_default_props);
3047 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3048 &IID_IMXWriter, (void**)&writer);
3049 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3051 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
3052 ok(hr == E_POINTER, "got %08x\n", hr);
3054 hr = IMXWriter_get_byteOrderMark(writer, NULL);
3055 ok(hr == E_POINTER, "got %08x\n", hr);
3057 hr = IMXWriter_get_indent(writer, NULL);
3058 ok(hr == E_POINTER, "got %08x\n", hr);
3060 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
3061 ok(hr == E_POINTER, "got %08x\n", hr);
3063 hr = IMXWriter_get_standalone(writer, NULL);
3064 ok(hr == E_POINTER, "got %08x\n", hr);
3066 /* set and check */
3067 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
3068 ok(hr == S_OK, "got %08x\n", hr);
3070 b = VARIANT_FALSE;
3071 hr = IMXWriter_get_standalone(writer, &b);
3072 ok(hr == S_OK, "got %08x\n", hr);
3073 ok(b == VARIANT_TRUE, "got %d\n", b);
3075 hr = IMXWriter_get_encoding(writer, NULL);
3076 EXPECT_HR(hr, E_POINTER);
3078 /* UTF-16 is a default setting apparently */
3079 str = (void*)0xdeadbeef;
3080 hr = IMXWriter_get_encoding(writer, &str);
3081 EXPECT_HR(hr, S_OK);
3082 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
3084 str2 = (void*)0xdeadbeef;
3085 hr = IMXWriter_get_encoding(writer, &str2);
3086 ok(hr == S_OK, "got %08x\n", hr);
3087 ok(str != str2, "expected newly allocated, got same %p\n", str);
3089 SysFreeString(str2);
3090 SysFreeString(str);
3092 /* put empty string */
3093 str = SysAllocString(emptyW);
3094 hr = IMXWriter_put_encoding(writer, str);
3095 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3096 SysFreeString(str);
3098 str = (void*)0xdeadbeef;
3099 hr = IMXWriter_get_encoding(writer, &str);
3100 EXPECT_HR(hr, S_OK);
3101 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
3102 SysFreeString(str);
3104 /* invalid encoding name */
3105 str = SysAllocString(testW);
3106 hr = IMXWriter_put_encoding(writer, str);
3107 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3108 SysFreeString(str);
3110 /* test case sensivity */
3111 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
3112 EXPECT_HR(hr, S_OK);
3113 str = (void*)0xdeadbeef;
3114 hr = IMXWriter_get_encoding(writer, &str);
3115 EXPECT_HR(hr, S_OK);
3116 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
3117 SysFreeString(str);
3119 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
3120 EXPECT_HR(hr, S_OK);
3121 str = (void*)0xdeadbeef;
3122 hr = IMXWriter_get_encoding(writer, &str);
3123 EXPECT_HR(hr, S_OK);
3124 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
3125 SysFreeString(str);
3127 /* how it affects document creation */
3128 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3129 EXPECT_HR(hr, S_OK);
3131 hr = ISAXContentHandler_startDocument(content);
3132 EXPECT_HR(hr, S_OK);
3133 hr = ISAXContentHandler_endDocument(content);
3134 EXPECT_HR(hr, S_OK);
3136 V_VT(&dest) = VT_EMPTY;
3137 hr = IMXWriter_get_output(writer, &dest);
3138 EXPECT_HR(hr, S_OK);
3139 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3140 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
3141 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3142 VariantClear(&dest);
3143 ISAXContentHandler_Release(content);
3145 hr = IMXWriter_get_version(writer, NULL);
3146 ok(hr == E_POINTER, "got %08x\n", hr);
3147 /* default version is 'surprisingly' 1.0 */
3148 hr = IMXWriter_get_version(writer, &str);
3149 ok(hr == S_OK, "got %08x\n", hr);
3150 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3151 SysFreeString(str);
3153 /* store version string as is */
3154 hr = IMXWriter_put_version(writer, NULL);
3155 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3157 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3158 ok(hr == S_OK, "got %08x\n", hr);
3160 hr = IMXWriter_put_version(writer, _bstr_(""));
3161 ok(hr == S_OK, "got %08x\n", hr);
3162 hr = IMXWriter_get_version(writer, &str);
3163 ok(hr == S_OK, "got %08x\n", hr);
3164 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3165 SysFreeString(str);
3167 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3168 ok(hr == S_OK, "got %08x\n", hr);
3169 hr = IMXWriter_get_version(writer, &str);
3170 ok(hr == S_OK, "got %08x\n", hr);
3171 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3172 SysFreeString(str);
3174 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3175 ok(hr == S_OK, "got %08x\n", hr);
3176 hr = IMXWriter_get_version(writer, &str);
3177 ok(hr == S_OK, "got %08x\n", hr);
3178 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3179 SysFreeString(str);
3181 IMXWriter_Release(writer);
3182 free_bstrs();
3185 static void test_mxwriter_flush(void)
3187 ISAXContentHandler *content;
3188 IMXWriter *writer;
3189 LARGE_INTEGER pos;
3190 ULARGE_INTEGER pos2;
3191 IStream *stream;
3192 VARIANT dest;
3193 HRESULT hr;
3194 char *buff;
3195 LONG ref;
3196 int len;
3198 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3199 &IID_IMXWriter, (void**)&writer);
3200 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3202 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3203 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3204 EXPECT_REF(stream, 1);
3206 /* detach when nothing was attached */
3207 V_VT(&dest) = VT_EMPTY;
3208 hr = IMXWriter_put_output(writer, dest);
3209 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3211 /* attach stream */
3212 V_VT(&dest) = VT_UNKNOWN;
3213 V_UNKNOWN(&dest) = (IUnknown*)stream;
3214 hr = IMXWriter_put_output(writer, dest);
3215 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3216 todo_wine EXPECT_REF(stream, 3);
3218 /* detach setting VT_EMPTY destination */
3219 V_VT(&dest) = VT_EMPTY;
3220 hr = IMXWriter_put_output(writer, dest);
3221 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3222 EXPECT_REF(stream, 1);
3224 V_VT(&dest) = VT_UNKNOWN;
3225 V_UNKNOWN(&dest) = (IUnknown*)stream;
3226 hr = IMXWriter_put_output(writer, dest);
3227 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3229 /* flush() doesn't detach a stream */
3230 hr = IMXWriter_flush(writer);
3231 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3232 todo_wine EXPECT_REF(stream, 3);
3234 pos.QuadPart = 0;
3235 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3236 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3237 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3239 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3240 ok(hr == S_OK, "got %08x\n", hr);
3242 hr = ISAXContentHandler_startDocument(content);
3243 ok(hr == S_OK, "got %08x\n", hr);
3245 pos.QuadPart = 0;
3246 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3247 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3248 ok(pos2.QuadPart != 0, "expected stream beginning\n");
3250 /* already started */
3251 hr = ISAXContentHandler_startDocument(content);
3252 ok(hr == S_OK, "got %08x\n", hr);
3254 hr = ISAXContentHandler_endDocument(content);
3255 ok(hr == S_OK, "got %08x\n", hr);
3257 /* flushed on endDocument() */
3258 pos.QuadPart = 0;
3259 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3260 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3261 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3263 IStream_Release(stream);
3265 /* auto-flush feature */
3266 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3267 EXPECT_HR(hr, S_OK);
3268 EXPECT_REF(stream, 1);
3270 V_VT(&dest) = VT_UNKNOWN;
3271 V_UNKNOWN(&dest) = (IUnknown*)stream;
3272 hr = IMXWriter_put_output(writer, dest);
3273 EXPECT_HR(hr, S_OK);
3275 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
3276 EXPECT_HR(hr, S_OK);
3278 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3279 EXPECT_HR(hr, S_OK);
3281 hr = ISAXContentHandler_startDocument(content);
3282 EXPECT_HR(hr, S_OK);
3284 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3285 EXPECT_HR(hr, S_OK);
3287 /* internal buffer is flushed automatically on certain threshold */
3288 pos.QuadPart = 0;
3289 pos2.QuadPart = 1;
3290 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3291 EXPECT_HR(hr, S_OK);
3292 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3294 len = 2048;
3295 buff = HeapAlloc(GetProcessHeap(), 0, len+1);
3296 memset(buff, 'A', len);
3297 buff[len] = 0;
3298 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3299 EXPECT_HR(hr, S_OK);
3301 pos.QuadPart = 0;
3302 pos2.QuadPart = 0;
3303 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3304 EXPECT_HR(hr, S_OK);
3305 todo_wine
3306 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
3308 hr = IMXWriter_get_output(writer, NULL);
3309 EXPECT_HR(hr, E_POINTER);
3311 ref = get_refcount(stream);
3312 V_VT(&dest) = VT_EMPTY;
3313 hr = IMXWriter_get_output(writer, &dest);
3314 EXPECT_HR(hr, S_OK);
3315 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3316 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3317 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3318 VariantClear(&dest);
3320 hr = ISAXContentHandler_endDocument(content);
3321 EXPECT_HR(hr, S_OK);
3323 IStream_Release(stream);
3325 /* test char count lower than threshold */
3326 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3327 EXPECT_HR(hr, S_OK);
3328 EXPECT_REF(stream, 1);
3330 hr = ISAXContentHandler_startDocument(content);
3331 EXPECT_HR(hr, S_OK);
3333 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3334 EXPECT_HR(hr, S_OK);
3336 pos.QuadPart = 0;
3337 pos2.QuadPart = 1;
3338 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3339 EXPECT_HR(hr, S_OK);
3340 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3342 memset(buff, 'A', len);
3343 buff[len] = 0;
3344 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3345 EXPECT_HR(hr, S_OK);
3347 pos.QuadPart = 0;
3348 pos2.QuadPart = 1;
3349 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3350 EXPECT_HR(hr, S_OK);
3351 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3353 hr = ISAXContentHandler_endDocument(content);
3354 EXPECT_HR(hr, S_OK);
3356 /* test auto-flush function when stream is not set */
3357 V_VT(&dest) = VT_EMPTY;
3358 hr = IMXWriter_put_output(writer, dest);
3359 EXPECT_HR(hr, S_OK);
3361 hr = ISAXContentHandler_startDocument(content);
3362 EXPECT_HR(hr, S_OK);
3364 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3365 EXPECT_HR(hr, S_OK);
3367 memset(buff, 'A', len);
3368 buff[len] = 0;
3369 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3370 EXPECT_HR(hr, S_OK);
3372 V_VT(&dest) = VT_EMPTY;
3373 hr = IMXWriter_get_output(writer, &dest);
3374 EXPECT_HR(hr, S_OK);
3375 len += strlen("<a>");
3376 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3377 VariantClear(&dest);
3379 HeapFree(GetProcessHeap(), 0, buff);
3380 ISAXContentHandler_Release(content);
3381 IStream_Release(stream);
3382 IMXWriter_Release(writer);
3383 free_bstrs();
3386 static void test_mxwriter_startenddocument(void)
3388 ISAXContentHandler *content;
3389 IMXWriter *writer;
3390 VARIANT dest;
3391 HRESULT hr;
3393 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3394 &IID_IMXWriter, (void**)&writer);
3395 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3397 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3398 ok(hr == S_OK, "got %08x\n", hr);
3400 hr = ISAXContentHandler_startDocument(content);
3401 ok(hr == S_OK, "got %08x\n", hr);
3403 hr = ISAXContentHandler_endDocument(content);
3404 ok(hr == S_OK, "got %08x\n", hr);
3406 V_VT(&dest) = VT_EMPTY;
3407 hr = IMXWriter_get_output(writer, &dest);
3408 ok(hr == S_OK, "got %08x\n", hr);
3409 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3410 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3411 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3412 VariantClear(&dest);
3414 /* now try another startDocument */
3415 hr = ISAXContentHandler_startDocument(content);
3416 ok(hr == S_OK, "got %08x\n", hr);
3417 /* and get duplicated prolog */
3418 V_VT(&dest) = VT_EMPTY;
3419 hr = IMXWriter_get_output(writer, &dest);
3420 ok(hr == S_OK, "got %08x\n", hr);
3421 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3422 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3423 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3424 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3425 VariantClear(&dest);
3427 ISAXContentHandler_Release(content);
3428 IMXWriter_Release(writer);
3430 /* now with omitted declaration */
3431 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3432 &IID_IMXWriter, (void**)&writer);
3433 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3435 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3436 ok(hr == S_OK, "got %08x\n", hr);
3438 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3439 ok(hr == S_OK, "got %08x\n", hr);
3441 hr = ISAXContentHandler_startDocument(content);
3442 ok(hr == S_OK, "got %08x\n", hr);
3444 hr = ISAXContentHandler_endDocument(content);
3445 ok(hr == S_OK, "got %08x\n", hr);
3447 V_VT(&dest) = VT_EMPTY;
3448 hr = IMXWriter_get_output(writer, &dest);
3449 ok(hr == S_OK, "got %08x\n", hr);
3450 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3451 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3452 VariantClear(&dest);
3454 ISAXContentHandler_Release(content);
3455 IMXWriter_Release(writer);
3457 free_bstrs();
3460 enum startendtype
3462 StartElement = 0x001,
3463 EndElement = 0x010,
3464 StartEndElement = 0x011,
3465 DisableEscaping = 0x100
3468 struct writer_startendelement_t {
3469 const GUID *clsid;
3470 enum startendtype type;
3471 const char *uri;
3472 const char *local_name;
3473 const char *qname;
3474 const char *output;
3475 HRESULT hr;
3476 ISAXAttributes *attr;
3479 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\">";
3480 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\"/>";
3481 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\'\"/>";
3483 static const struct writer_startendelement_t writer_startendelement[] = {
3484 /* 0 */
3485 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3486 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3487 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3488 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3489 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3490 /* 5 */
3491 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3492 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3493 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3494 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3495 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3496 /* 10 */
3497 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3498 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3499 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3500 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3501 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3502 /* 15 */
3503 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3504 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3505 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3506 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3507 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3508 /* 20 */
3509 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3510 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3511 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3512 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3513 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3514 /* 25 */
3515 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3516 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3517 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3518 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3519 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3520 /* 30 */
3521 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3522 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3523 /* endElement tests */
3524 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3525 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3526 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3527 /* 35 */
3528 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3529 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3530 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3531 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3532 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3533 /* 40 */
3534 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3535 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3536 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3537 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3538 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3539 /* 45 */
3540 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3541 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3542 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3543 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3544 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3545 /* 50 */
3546 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3547 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3548 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3549 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3550 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3551 /* 55 */
3552 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3553 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3554 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3555 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3556 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3557 /* 60 */
3558 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3559 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3560 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3561 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3563 /* with attributes */
3564 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3565 /* 65 */
3566 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3567 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3568 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3569 /* empty elements */
3570 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3571 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3572 /* 70 */
3573 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3574 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3575 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3576 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3577 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3578 /* 75 */
3579 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3581 /* with disabled output escaping */
3582 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3583 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3584 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3585 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3587 { NULL }
3590 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3592 while (table->clsid)
3594 IUnknown *unk;
3595 HRESULT hr;
3597 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3598 if (hr == S_OK) IUnknown_Release(unk);
3600 table->supported = hr == S_OK;
3601 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3603 table++;
3607 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3609 int i = 0;
3611 while (table->clsid)
3613 ISAXContentHandler *content;
3614 IMXWriter *writer;
3615 HRESULT hr;
3617 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3619 table++;
3620 i++;
3621 continue;
3624 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3625 &IID_IMXWriter, (void**)&writer);
3626 EXPECT_HR(hr, S_OK);
3628 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3629 EXPECT_HR(hr, S_OK);
3631 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3632 EXPECT_HR(hr, S_OK);
3634 hr = ISAXContentHandler_startDocument(content);
3635 EXPECT_HR(hr, S_OK);
3637 if (table->type & DisableEscaping)
3639 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3640 EXPECT_HR(hr, S_OK);
3643 if (table->type & StartElement)
3645 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3646 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3647 table->qname ? strlen(table->qname) : 0, table->attr);
3648 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3651 if (table->type & EndElement)
3653 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3654 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3655 table->qname ? strlen(table->qname) : 0);
3656 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3659 /* test output */
3660 if (hr == S_OK)
3662 VARIANT dest;
3664 V_VT(&dest) = VT_EMPTY;
3665 hr = IMXWriter_get_output(writer, &dest);
3666 EXPECT_HR(hr, S_OK);
3667 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3668 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3669 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3670 VariantClear(&dest);
3673 ISAXContentHandler_Release(content);
3674 IMXWriter_Release(writer);
3676 table++;
3677 i++;
3680 free_bstrs();
3683 /* point of these test is to start/end element with different names and name lengths */
3684 struct writer_startendelement2_t {
3685 const GUID *clsid;
3686 const char *qnamestart;
3687 int qnamestart_len;
3688 const char *qnameend;
3689 int qnameend_len;
3690 const char *output;
3691 HRESULT hr;
3694 static const struct writer_startendelement2_t writer_startendelement2[] = {
3695 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3696 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3697 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3698 /* -1 length is not allowed for version 6 */
3699 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3701 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3702 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3703 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3704 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3705 { NULL }
3708 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3710 int i = 0;
3712 while (table->clsid)
3714 ISAXContentHandler *content;
3715 IMXWriter *writer;
3716 HRESULT hr;
3718 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3720 table++;
3721 i++;
3722 continue;
3725 hr = CoCreateInstance(table->clsid, 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_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3733 EXPECT_HR(hr, S_OK);
3735 hr = ISAXContentHandler_startDocument(content);
3736 EXPECT_HR(hr, S_OK);
3738 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3739 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3740 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3742 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3743 _bstr_(table->qnameend), table->qnameend_len);
3744 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3746 /* test output */
3747 if (hr == S_OK)
3749 VARIANT dest;
3751 V_VT(&dest) = VT_EMPTY;
3752 hr = IMXWriter_get_output(writer, &dest);
3753 EXPECT_HR(hr, S_OK);
3754 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3755 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3756 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3757 VariantClear(&dest);
3760 ISAXContentHandler_Release(content);
3761 IMXWriter_Release(writer);
3763 table++;
3764 i++;
3766 free_bstrs();
3771 static void test_mxwriter_startendelement(void)
3773 ISAXContentHandler *content;
3774 IMXWriter *writer;
3775 VARIANT dest;
3776 HRESULT hr;
3778 test_mxwriter_startendelement_batch(writer_startendelement);
3779 test_mxwriter_startendelement_batch2(writer_startendelement2);
3781 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3782 &IID_IMXWriter, (void**)&writer);
3783 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3785 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3786 ok(hr == S_OK, "got %08x\n", hr);
3788 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3789 ok(hr == S_OK, "got %08x\n", hr);
3791 hr = ISAXContentHandler_startDocument(content);
3792 ok(hr == S_OK, "got %08x\n", hr);
3794 /* all string pointers should be not null */
3795 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3796 ok(hr == S_OK, "got %08x\n", hr);
3798 V_VT(&dest) = VT_EMPTY;
3799 hr = IMXWriter_get_output(writer, &dest);
3800 ok(hr == S_OK, "got %08x\n", hr);
3801 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3802 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3803 VariantClear(&dest);
3805 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3806 ok(hr == S_OK, "got %08x\n", hr);
3808 V_VT(&dest) = VT_EMPTY;
3809 hr = IMXWriter_get_output(writer, &dest);
3810 ok(hr == S_OK, "got %08x\n", hr);
3811 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3812 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3813 VariantClear(&dest);
3815 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3816 EXPECT_HR(hr, E_INVALIDARG);
3818 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3819 EXPECT_HR(hr, E_INVALIDARG);
3821 /* only local name is an error too */
3822 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3823 EXPECT_HR(hr, E_INVALIDARG);
3825 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3826 EXPECT_HR(hr, S_OK);
3828 V_VT(&dest) = VT_EMPTY;
3829 hr = IMXWriter_get_output(writer, &dest);
3830 EXPECT_HR(hr, S_OK);
3831 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3832 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3833 VariantClear(&dest);
3835 hr = ISAXContentHandler_endDocument(content);
3836 EXPECT_HR(hr, S_OK);
3838 V_VT(&dest) = VT_EMPTY;
3839 hr = IMXWriter_put_output(writer, dest);
3840 EXPECT_HR(hr, S_OK);
3842 V_VT(&dest) = VT_EMPTY;
3843 hr = IMXWriter_get_output(writer, &dest);
3844 EXPECT_HR(hr, S_OK);
3845 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3846 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3847 VariantClear(&dest);
3849 hr = ISAXContentHandler_startDocument(content);
3850 EXPECT_HR(hr, S_OK);
3852 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3853 EXPECT_HR(hr, S_OK);
3855 V_VT(&dest) = VT_EMPTY;
3856 hr = IMXWriter_get_output(writer, &dest);
3857 EXPECT_HR(hr, S_OK);
3858 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3859 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3860 VariantClear(&dest);
3862 hr = ISAXContentHandler_endDocument(content);
3863 EXPECT_HR(hr, S_OK);
3864 IMXWriter_flush(writer);
3866 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3867 EXPECT_HR(hr, S_OK);
3868 V_VT(&dest) = VT_EMPTY;
3869 hr = IMXWriter_get_output(writer, &dest);
3870 EXPECT_HR(hr, S_OK);
3871 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3872 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3873 VariantClear(&dest);
3875 V_VT(&dest) = VT_EMPTY;
3876 hr = IMXWriter_put_output(writer, dest);
3877 EXPECT_HR(hr, S_OK);
3879 /* length -1 */
3880 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3881 EXPECT_HR(hr, S_OK);
3882 V_VT(&dest) = VT_EMPTY;
3883 hr = IMXWriter_get_output(writer, &dest);
3884 EXPECT_HR(hr, S_OK);
3885 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3886 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3887 VariantClear(&dest);
3889 ISAXContentHandler_Release(content);
3890 IMXWriter_Release(writer);
3891 free_bstrs();
3894 struct writer_characters_t {
3895 const GUID *clsid;
3896 const char *data;
3897 const char *output;
3900 static const struct writer_characters_t writer_characters[] = {
3901 { &CLSID_MXXMLWriter, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3902 { &CLSID_MXXMLWriter30, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3903 { &CLSID_MXXMLWriter40, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3904 { &CLSID_MXXMLWriter60, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3905 { NULL }
3908 static void test_mxwriter_characters(void)
3910 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3911 const struct writer_characters_t *table = writer_characters;
3912 ISAXContentHandler *content;
3913 IMXWriter *writer;
3914 VARIANT dest;
3915 HRESULT hr;
3916 int i = 0;
3918 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3919 &IID_IMXWriter, (void**)&writer);
3920 EXPECT_HR(hr, S_OK);
3922 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3923 EXPECT_HR(hr, S_OK);
3925 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3926 EXPECT_HR(hr, S_OK);
3928 hr = ISAXContentHandler_startDocument(content);
3929 EXPECT_HR(hr, S_OK);
3931 hr = ISAXContentHandler_characters(content, NULL, 0);
3932 EXPECT_HR(hr, E_INVALIDARG);
3934 hr = ISAXContentHandler_characters(content, chardataW, 0);
3935 EXPECT_HR(hr, S_OK);
3937 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3938 EXPECT_HR(hr, S_OK);
3940 V_VT(&dest) = VT_EMPTY;
3941 hr = IMXWriter_get_output(writer, &dest);
3942 EXPECT_HR(hr, S_OK);
3943 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3944 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3945 VariantClear(&dest);
3947 hr = ISAXContentHandler_endDocument(content);
3948 EXPECT_HR(hr, S_OK);
3950 ISAXContentHandler_Release(content);
3951 IMXWriter_Release(writer);
3953 /* try empty characters data to see if element is closed */
3954 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3955 &IID_IMXWriter, (void**)&writer);
3956 EXPECT_HR(hr, S_OK);
3958 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3959 EXPECT_HR(hr, S_OK);
3961 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3962 EXPECT_HR(hr, S_OK);
3964 hr = ISAXContentHandler_startDocument(content);
3965 EXPECT_HR(hr, S_OK);
3967 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3968 EXPECT_HR(hr, S_OK);
3970 hr = ISAXContentHandler_characters(content, chardataW, 0);
3971 EXPECT_HR(hr, S_OK);
3973 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3974 EXPECT_HR(hr, S_OK);
3976 V_VT(&dest) = VT_EMPTY;
3977 hr = IMXWriter_get_output(writer, &dest);
3978 EXPECT_HR(hr, S_OK);
3979 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3980 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3981 VariantClear(&dest);
3983 ISAXContentHandler_Release(content);
3984 IMXWriter_Release(writer);
3986 /* batch tests */
3987 while (table->clsid)
3989 ISAXContentHandler *content;
3990 IMXWriter *writer;
3991 VARIANT dest;
3992 HRESULT hr;
3994 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3996 table++;
3997 i++;
3998 continue;
4001 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4002 &IID_IMXWriter, (void**)&writer);
4003 EXPECT_HR(hr, S_OK);
4005 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4006 EXPECT_HR(hr, S_OK);
4008 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4009 EXPECT_HR(hr, S_OK);
4011 hr = ISAXContentHandler_startDocument(content);
4012 EXPECT_HR(hr, S_OK);
4014 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4015 EXPECT_HR(hr, S_OK);
4017 /* test output */
4018 if (hr == S_OK)
4020 V_VT(&dest) = VT_EMPTY;
4021 hr = IMXWriter_get_output(writer, &dest);
4022 EXPECT_HR(hr, S_OK);
4023 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4024 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
4025 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
4026 VariantClear(&dest);
4029 /* with disabled escaping */
4030 V_VT(&dest) = VT_EMPTY;
4031 hr = IMXWriter_put_output(writer, dest);
4032 EXPECT_HR(hr, S_OK);
4034 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
4035 EXPECT_HR(hr, S_OK);
4037 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4038 EXPECT_HR(hr, S_OK);
4040 /* test output */
4041 if (hr == S_OK)
4043 V_VT(&dest) = VT_EMPTY;
4044 hr = IMXWriter_get_output(writer, &dest);
4045 EXPECT_HR(hr, S_OK);
4046 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4047 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
4048 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
4049 VariantClear(&dest);
4052 ISAXContentHandler_Release(content);
4053 IMXWriter_Release(writer);
4055 table++;
4056 i++;
4059 free_bstrs();
4062 static const mxwriter_stream_test mxwriter_stream_tests[] = {
4064 VARIANT_TRUE,"UTF-16",
4066 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4067 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4068 {TRUE}
4072 VARIANT_FALSE,"UTF-16",
4074 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4075 {TRUE}
4079 VARIANT_TRUE,"UTF-8",
4081 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
4082 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4083 * and the writer is released.
4085 {FALSE,NULL,0},
4086 {TRUE}
4090 VARIANT_TRUE,"utf-8",
4092 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
4093 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4094 * and the writer is released.
4096 {FALSE,NULL,0},
4097 {TRUE}
4101 VARIANT_TRUE,"UTF-16",
4103 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4104 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4105 {TRUE}
4109 VARIANT_TRUE,"UTF-16",
4111 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
4112 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4113 {TRUE}
4118 static void test_mxwriter_stream(void)
4120 IMXWriter *writer;
4121 ISAXContentHandler *content;
4122 HRESULT hr;
4123 VARIANT dest;
4124 IStream *stream;
4125 LARGE_INTEGER pos;
4126 ULARGE_INTEGER pos2;
4127 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
4129 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
4130 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
4132 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4133 &IID_IMXWriter, (void**)&writer);
4134 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4136 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4137 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4139 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
4140 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
4142 V_VT(&dest) = VT_UNKNOWN;
4143 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
4144 hr = IMXWriter_put_output(writer, dest);
4145 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
4146 VariantClear(&dest);
4148 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
4149 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
4151 current_write_test = test->expected_writes;
4153 hr = ISAXContentHandler_startDocument(content);
4154 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4156 hr = ISAXContentHandler_endDocument(content);
4157 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4159 ISAXContentHandler_Release(content);
4160 IMXWriter_Release(writer);
4162 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
4163 (int)(current_write_test-test->expected_writes), current_stream_test_index);
4166 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4167 &IID_IMXWriter, (void**)&writer);
4168 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4170 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4171 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
4173 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4174 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4176 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4177 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
4179 V_VT(&dest) = VT_UNKNOWN;
4180 V_UNKNOWN(&dest) = (IUnknown*)stream;
4181 hr = IMXWriter_put_output(writer, dest);
4182 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4184 hr = ISAXContentHandler_startDocument(content);
4185 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4187 /* Setting output of the mxwriter causes the current output to be flushed,
4188 * and the writer to start over.
4190 V_VT(&dest) = VT_EMPTY;
4191 hr = IMXWriter_put_output(writer, dest);
4192 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4194 pos.QuadPart = 0;
4195 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4196 ok(hr == S_OK, "Seek failed: %08x\n", hr);
4197 ok(pos2.QuadPart != 0, "expected stream position moved\n");
4199 hr = ISAXContentHandler_startDocument(content);
4200 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4202 hr = ISAXContentHandler_endDocument(content);
4203 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
4205 V_VT(&dest) = VT_EMPTY;
4206 hr = IMXWriter_get_output(writer, &dest);
4207 ok(hr == S_OK, "get_output failed: %08x\n", hr);
4208 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4209 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4210 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4211 VariantClear(&dest);
4213 /* test when BOM is written to output stream */
4214 V_VT(&dest) = VT_EMPTY;
4215 hr = IMXWriter_put_output(writer, dest);
4216 EXPECT_HR(hr, S_OK);
4218 pos.QuadPart = 0;
4219 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
4220 EXPECT_HR(hr, S_OK);
4222 V_VT(&dest) = VT_UNKNOWN;
4223 V_UNKNOWN(&dest) = (IUnknown*)stream;
4224 hr = IMXWriter_put_output(writer, dest);
4225 EXPECT_HR(hr, S_OK);
4227 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
4228 EXPECT_HR(hr, S_OK);
4230 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4231 EXPECT_HR(hr, S_OK);
4233 hr = ISAXContentHandler_startDocument(content);
4234 EXPECT_HR(hr, S_OK);
4236 pos.QuadPart = 0;
4237 pos2.QuadPart = 0;
4238 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4239 EXPECT_HR(hr, S_OK);
4240 ok(pos2.QuadPart == 2, "got wrong position\n");
4242 IStream_Release(stream);
4243 ISAXContentHandler_Release(content);
4244 IMXWriter_Release(writer);
4246 free_bstrs();
4249 static const char *encoding_names[] = {
4250 "iso-8859-1",
4251 "iso-8859-2",
4252 "iso-8859-3",
4253 "iso-8859-4",
4254 "iso-8859-5",
4255 "iso-8859-7",
4256 "iso-8859-9",
4257 "iso-8859-13",
4258 "iso-8859-15",
4259 NULL
4262 static void test_mxwriter_encoding(void)
4264 ISAXContentHandler *content;
4265 IMXWriter *writer;
4266 IStream *stream;
4267 const char *enc;
4268 VARIANT dest;
4269 HRESULT hr;
4270 HGLOBAL g;
4271 char *ptr;
4272 BSTR s;
4273 int i;
4275 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4276 &IID_IMXWriter, (void**)&writer);
4277 EXPECT_HR(hr, S_OK);
4279 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4280 EXPECT_HR(hr, S_OK);
4282 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4283 EXPECT_HR(hr, S_OK);
4285 hr = ISAXContentHandler_startDocument(content);
4286 EXPECT_HR(hr, S_OK);
4288 hr = ISAXContentHandler_endDocument(content);
4289 EXPECT_HR(hr, S_OK);
4291 /* The content is always re-encoded to UTF-16 when the output is
4292 * retrieved as a BSTR.
4294 V_VT(&dest) = VT_EMPTY;
4295 hr = IMXWriter_get_output(writer, &dest);
4296 EXPECT_HR(hr, S_OK);
4297 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4298 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4299 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4300 VariantClear(&dest);
4302 /* switch encoding when something is written already */
4303 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4304 EXPECT_HR(hr, S_OK);
4306 V_VT(&dest) = VT_UNKNOWN;
4307 V_UNKNOWN(&dest) = (IUnknown*)stream;
4308 hr = IMXWriter_put_output(writer, dest);
4309 EXPECT_HR(hr, S_OK);
4311 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4312 EXPECT_HR(hr, S_OK);
4314 /* write empty element */
4315 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
4316 EXPECT_HR(hr, S_OK);
4318 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
4319 EXPECT_HR(hr, S_OK);
4321 /* switch */
4322 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4323 EXPECT_HR(hr, S_OK);
4325 hr = IMXWriter_flush(writer);
4326 EXPECT_HR(hr, S_OK);
4328 hr = GetHGlobalFromStream(stream, &g);
4329 EXPECT_HR(hr, S_OK);
4331 ptr = GlobalLock(g);
4332 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4333 GlobalUnlock(g);
4335 /* so output is unaffected, encoding name is stored however */
4336 hr = IMXWriter_get_encoding(writer, &s);
4337 EXPECT_HR(hr, S_OK);
4338 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4339 SysFreeString(s);
4341 IStream_Release(stream);
4343 i = 0;
4344 enc = encoding_names[i];
4345 while (enc)
4347 char expectedA[200];
4349 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4350 EXPECT_HR(hr, S_OK);
4352 V_VT(&dest) = VT_UNKNOWN;
4353 V_UNKNOWN(&dest) = (IUnknown*)stream;
4354 hr = IMXWriter_put_output(writer, dest);
4355 EXPECT_HR(hr, S_OK);
4357 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4358 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4359 "%s: encoding not accepted\n", enc);
4360 if (hr != S_OK)
4362 enc = encoding_names[++i];
4363 IStream_Release(stream);
4364 continue;
4367 hr = ISAXContentHandler_startDocument(content);
4368 EXPECT_HR(hr, S_OK);
4370 hr = ISAXContentHandler_endDocument(content);
4371 EXPECT_HR(hr, S_OK);
4373 hr = IMXWriter_flush(writer);
4374 EXPECT_HR(hr, S_OK);
4376 /* prepare expected string */
4377 *expectedA = 0;
4378 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4379 strcat(expectedA, enc);
4380 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4382 hr = GetHGlobalFromStream(stream, &g);
4383 EXPECT_HR(hr, S_OK);
4385 ptr = GlobalLock(g);
4386 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4387 GlobalUnlock(g);
4389 V_VT(&dest) = VT_EMPTY;
4390 hr = IMXWriter_put_output(writer, dest);
4391 EXPECT_HR(hr, S_OK);
4393 IStream_Release(stream);
4395 enc = encoding_names[++i];
4398 ISAXContentHandler_Release(content);
4399 IMXWriter_Release(writer);
4401 free_bstrs();
4404 static void test_obj_dispex(IUnknown *obj)
4406 static const WCHAR testW[] = {'t','e','s','t','p','r','o','p',0};
4407 static const WCHAR starW[] = {'*',0};
4408 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4409 IDispatchEx *dispex;
4410 IUnknown *unk;
4411 DWORD props;
4412 UINT ticnt;
4413 HRESULT hr;
4414 BSTR name;
4415 DISPID did;
4417 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4418 EXPECT_HR(hr, S_OK);
4419 if (FAILED(hr)) return;
4421 ticnt = 0;
4422 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4423 EXPECT_HR(hr, S_OK);
4424 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4426 name = SysAllocString(starW);
4427 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4428 EXPECT_HR(hr, E_NOTIMPL);
4429 SysFreeString(name);
4431 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4432 EXPECT_HR(hr, E_NOTIMPL);
4434 props = 0;
4435 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4436 EXPECT_HR(hr, E_NOTIMPL);
4437 ok(props == 0, "expected 0 got %d\n", props);
4439 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4440 EXPECT_HR(hr, E_NOTIMPL);
4441 if (SUCCEEDED(hr)) SysFreeString(name);
4443 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4444 EXPECT_HR(hr, E_NOTIMPL);
4446 unk = (IUnknown*)0xdeadbeef;
4447 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4448 EXPECT_HR(hr, E_NOTIMPL);
4449 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk);
4451 name = SysAllocString(testW);
4452 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did);
4453 ok(hr == DISP_E_UNKNOWNNAME, "got 0x%08x\n", hr);
4454 SysFreeString(name);
4456 IDispatchEx_Release(dispex);
4459 static void test_saxreader_dispex(void)
4461 IVBSAXXMLReader *vbreader;
4462 ISAXXMLReader *reader;
4463 DISPPARAMS dispparams;
4464 DISPID dispid;
4465 IUnknown *unk;
4466 VARIANT arg;
4467 HRESULT hr;
4469 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4470 &IID_ISAXXMLReader, (void**)&reader);
4471 EXPECT_HR(hr, S_OK);
4473 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4474 EXPECT_HR(hr, S_OK);
4475 test_obj_dispex(unk);
4476 IUnknown_Release(unk);
4478 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4479 EXPECT_HR(hr, S_OK);
4480 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4481 EXPECT_HR(hr, S_OK);
4482 test_obj_dispex(unk);
4483 IUnknown_Release(unk);
4485 dispid = DISPID_PROPERTYPUT;
4486 dispparams.cArgs = 1;
4487 dispparams.cNamedArgs = 1;
4488 dispparams.rgdispidNamedArgs = &dispid;
4489 dispparams.rgvarg = &arg;
4491 V_VT(&arg) = VT_DISPATCH;
4492 V_DISPATCH(&arg) = NULL;
4494 /* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */
4495 hr = IVBSAXXMLReader_Invoke(vbreader,
4496 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4497 &IID_NULL,
4499 DISPATCH_PROPERTYPUT,
4500 &dispparams,
4501 NULL,
4502 NULL,
4503 NULL);
4504 ok(hr == S_OK, "got 0x%08x\n", hr);
4506 hr = IVBSAXXMLReader_Invoke(vbreader,
4507 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4508 &IID_NULL,
4510 DISPATCH_PROPERTYPUTREF,
4511 &dispparams,
4512 NULL,
4513 NULL,
4514 NULL);
4515 ok(hr == S_OK, "got 0x%08x\n", hr);
4517 IVBSAXXMLReader_Release(vbreader);
4518 ISAXXMLReader_Release(reader);
4520 if (is_clsid_supported(&CLSID_SAXXMLReader60, reader_support_data))
4522 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4523 ok(hr == S_OK, "got 0x%08x\n", hr);
4524 test_obj_dispex(unk);
4525 IUnknown_Release(unk);
4529 static void test_mxwriter_dispex(void)
4531 IDispatchEx *dispex;
4532 IMXWriter *writer;
4533 IUnknown *unk;
4534 HRESULT hr;
4536 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4537 &IID_IMXWriter, (void**)&writer);
4538 EXPECT_HR(hr, S_OK);
4540 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4541 EXPECT_HR(hr, S_OK);
4542 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4543 test_obj_dispex(unk);
4544 IUnknown_Release(unk);
4545 IDispatchEx_Release(dispex);
4546 IMXWriter_Release(writer);
4548 if (is_clsid_supported(&CLSID_MXXMLWriter60, mxwriter_support_data))
4550 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4551 ok(hr == S_OK, "got 0x%08x\n", hr);
4552 test_obj_dispex(unk);
4553 IUnknown_Release(unk);
4557 static void test_mxwriter_comment(void)
4559 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4560 IVBSAXLexicalHandler *vblexical;
4561 ISAXContentHandler *content;
4562 ISAXLexicalHandler *lexical;
4563 IMXWriter *writer;
4564 VARIANT dest;
4565 HRESULT hr;
4567 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4568 &IID_IMXWriter, (void**)&writer);
4569 EXPECT_HR(hr, S_OK);
4571 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4572 EXPECT_HR(hr, S_OK);
4574 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4575 EXPECT_HR(hr, S_OK);
4577 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4578 EXPECT_HR(hr, S_OK);
4580 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4581 EXPECT_HR(hr, S_OK);
4583 hr = ISAXContentHandler_startDocument(content);
4584 EXPECT_HR(hr, S_OK);
4586 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4587 EXPECT_HR(hr, E_INVALIDARG);
4589 hr = IVBSAXLexicalHandler_comment(vblexical, NULL);
4590 EXPECT_HR(hr, E_POINTER);
4592 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4593 EXPECT_HR(hr, S_OK);
4595 V_VT(&dest) = VT_EMPTY;
4596 hr = IMXWriter_get_output(writer, &dest);
4597 EXPECT_HR(hr, S_OK);
4598 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4599 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4600 VariantClear(&dest);
4602 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4603 EXPECT_HR(hr, S_OK);
4605 V_VT(&dest) = VT_EMPTY;
4606 hr = IMXWriter_get_output(writer, &dest);
4607 EXPECT_HR(hr, S_OK);
4608 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4609 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4610 VariantClear(&dest);
4612 ISAXContentHandler_Release(content);
4613 ISAXLexicalHandler_Release(lexical);
4614 IVBSAXLexicalHandler_Release(vblexical);
4615 IMXWriter_Release(writer);
4616 free_bstrs();
4619 static void test_mxwriter_cdata(void)
4621 IVBSAXLexicalHandler *vblexical;
4622 ISAXContentHandler *content;
4623 ISAXLexicalHandler *lexical;
4624 IMXWriter *writer;
4625 VARIANT dest;
4626 HRESULT hr;
4628 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4629 &IID_IMXWriter, (void**)&writer);
4630 EXPECT_HR(hr, S_OK);
4632 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4633 EXPECT_HR(hr, S_OK);
4635 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4636 EXPECT_HR(hr, S_OK);
4638 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4639 EXPECT_HR(hr, S_OK);
4641 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4642 EXPECT_HR(hr, S_OK);
4644 hr = ISAXContentHandler_startDocument(content);
4645 EXPECT_HR(hr, S_OK);
4647 hr = ISAXLexicalHandler_startCDATA(lexical);
4648 EXPECT_HR(hr, S_OK);
4650 V_VT(&dest) = VT_EMPTY;
4651 hr = IMXWriter_get_output(writer, &dest);
4652 EXPECT_HR(hr, S_OK);
4653 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4654 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4655 VariantClear(&dest);
4657 hr = IVBSAXLexicalHandler_startCDATA(vblexical);
4658 EXPECT_HR(hr, S_OK);
4660 /* all these are escaped for text nodes */
4661 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4662 EXPECT_HR(hr, S_OK);
4664 hr = ISAXLexicalHandler_endCDATA(lexical);
4665 EXPECT_HR(hr, S_OK);
4667 V_VT(&dest) = VT_EMPTY;
4668 hr = IMXWriter_get_output(writer, &dest);
4669 EXPECT_HR(hr, S_OK);
4670 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4671 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4672 VariantClear(&dest);
4674 ISAXContentHandler_Release(content);
4675 ISAXLexicalHandler_Release(lexical);
4676 IVBSAXLexicalHandler_Release(vblexical);
4677 IMXWriter_Release(writer);
4678 free_bstrs();
4681 static void test_mxwriter_pi(void)
4683 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4684 static const WCHAR dataW[] = {'d','a','t','a',0};
4685 ISAXContentHandler *content;
4686 IMXWriter *writer;
4687 VARIANT dest;
4688 HRESULT hr;
4690 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4691 &IID_IMXWriter, (void**)&writer);
4692 EXPECT_HR(hr, S_OK);
4694 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4695 EXPECT_HR(hr, S_OK);
4697 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4698 EXPECT_HR(hr, E_INVALIDARG);
4700 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4701 EXPECT_HR(hr, S_OK);
4703 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4704 EXPECT_HR(hr, S_OK);
4706 V_VT(&dest) = VT_EMPTY;
4707 hr = IMXWriter_get_output(writer, &dest);
4708 EXPECT_HR(hr, S_OK);
4709 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4710 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4711 VariantClear(&dest);
4713 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4714 EXPECT_HR(hr, S_OK);
4716 V_VT(&dest) = VT_EMPTY;
4717 hr = IMXWriter_get_output(writer, &dest);
4718 EXPECT_HR(hr, S_OK);
4719 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4720 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)));
4721 VariantClear(&dest);
4723 V_VT(&dest) = VT_EMPTY;
4724 hr = IMXWriter_put_output(writer, dest);
4725 EXPECT_HR(hr, S_OK);
4727 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4728 EXPECT_HR(hr, S_OK);
4730 V_VT(&dest) = VT_EMPTY;
4731 hr = IMXWriter_get_output(writer, &dest);
4732 EXPECT_HR(hr, S_OK);
4733 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4734 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4735 VariantClear(&dest);
4738 ISAXContentHandler_Release(content);
4739 IMXWriter_Release(writer);
4742 static void test_mxwriter_ignorablespaces(void)
4744 static const WCHAR dataW[] = {'d','a','t','a',0};
4745 ISAXContentHandler *content;
4746 IMXWriter *writer;
4747 VARIANT dest;
4748 HRESULT hr;
4750 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4751 &IID_IMXWriter, (void**)&writer);
4752 EXPECT_HR(hr, S_OK);
4754 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4755 EXPECT_HR(hr, S_OK);
4757 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4758 EXPECT_HR(hr, E_INVALIDARG);
4760 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4761 EXPECT_HR(hr, S_OK);
4763 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4764 EXPECT_HR(hr, S_OK);
4766 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4767 EXPECT_HR(hr, S_OK);
4769 V_VT(&dest) = VT_EMPTY;
4770 hr = IMXWriter_get_output(writer, &dest);
4771 EXPECT_HR(hr, S_OK);
4772 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4773 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4774 VariantClear(&dest);
4776 ISAXContentHandler_Release(content);
4777 IMXWriter_Release(writer);
4780 static void test_mxwriter_dtd(void)
4782 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4783 static const WCHAR nameW[] = {'n','a','m','e'};
4784 static const WCHAR pubW[] = {'p','u','b'};
4785 static const WCHAR sysW[] = {'s','y','s'};
4786 IVBSAXLexicalHandler *vblexical;
4787 ISAXContentHandler *content;
4788 ISAXLexicalHandler *lexical;
4789 IVBSAXDeclHandler *vbdecl;
4790 ISAXDeclHandler *decl;
4791 IMXWriter *writer;
4792 VARIANT dest;
4793 HRESULT hr;
4795 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4796 &IID_IMXWriter, (void**)&writer);
4797 EXPECT_HR(hr, S_OK);
4799 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4800 EXPECT_HR(hr, S_OK);
4802 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4803 EXPECT_HR(hr, S_OK);
4805 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4806 EXPECT_HR(hr, S_OK);
4808 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl);
4809 EXPECT_HR(hr, S_OK);
4811 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4812 EXPECT_HR(hr, S_OK);
4814 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4815 EXPECT_HR(hr, S_OK);
4817 hr = ISAXContentHandler_startDocument(content);
4818 EXPECT_HR(hr, S_OK);
4820 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4821 EXPECT_HR(hr, E_INVALIDARG);
4823 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL);
4824 EXPECT_HR(hr, E_POINTER);
4826 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4827 EXPECT_HR(hr, E_INVALIDARG);
4829 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4830 EXPECT_HR(hr, E_INVALIDARG);
4832 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4833 EXPECT_HR(hr, E_INVALIDARG);
4835 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4836 EXPECT_HR(hr, S_OK);
4838 V_VT(&dest) = VT_EMPTY;
4839 hr = IMXWriter_get_output(writer, &dest);
4840 EXPECT_HR(hr, S_OK);
4841 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4842 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4843 VariantClear(&dest);
4845 /* system id is required if public is present */
4846 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4847 EXPECT_HR(hr, E_INVALIDARG);
4849 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4850 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4851 EXPECT_HR(hr, S_OK);
4853 V_VT(&dest) = VT_EMPTY;
4854 hr = IMXWriter_get_output(writer, &dest);
4855 EXPECT_HR(hr, S_OK);
4856 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4857 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4858 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4859 VariantClear(&dest);
4861 hr = ISAXLexicalHandler_endDTD(lexical);
4862 EXPECT_HR(hr, S_OK);
4864 hr = IVBSAXLexicalHandler_endDTD(vblexical);
4865 EXPECT_HR(hr, S_OK);
4867 V_VT(&dest) = VT_EMPTY;
4868 hr = IMXWriter_get_output(writer, &dest);
4869 EXPECT_HR(hr, S_OK);
4870 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4871 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4872 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4873 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4874 VariantClear(&dest);
4876 /* element declaration */
4877 V_VT(&dest) = VT_EMPTY;
4878 hr = IMXWriter_put_output(writer, dest);
4879 EXPECT_HR(hr, S_OK);
4881 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4882 EXPECT_HR(hr, E_INVALIDARG);
4884 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL);
4885 EXPECT_HR(hr, E_POINTER);
4887 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4888 EXPECT_HR(hr, E_INVALIDARG);
4890 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4891 EXPECT_HR(hr, S_OK);
4893 V_VT(&dest) = VT_EMPTY;
4894 hr = IMXWriter_get_output(writer, &dest);
4895 EXPECT_HR(hr, S_OK);
4896 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4897 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4898 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4899 VariantClear(&dest);
4901 V_VT(&dest) = VT_EMPTY;
4902 hr = IMXWriter_put_output(writer, dest);
4903 EXPECT_HR(hr, S_OK);
4905 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4906 EXPECT_HR(hr, S_OK);
4908 V_VT(&dest) = VT_EMPTY;
4909 hr = IMXWriter_get_output(writer, &dest);
4910 EXPECT_HR(hr, S_OK);
4911 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4912 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4913 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4914 VariantClear(&dest);
4916 /* attribute declaration */
4917 V_VT(&dest) = VT_EMPTY;
4918 hr = IMXWriter_put_output(writer, dest);
4919 EXPECT_HR(hr, S_OK);
4921 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4922 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4923 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4924 EXPECT_HR(hr, S_OK);
4926 V_VT(&dest) = VT_EMPTY;
4927 hr = IMXWriter_get_output(writer, &dest);
4928 EXPECT_HR(hr, S_OK);
4929 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4930 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4931 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4932 VariantClear(&dest);
4934 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4935 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4936 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4937 EXPECT_HR(hr, S_OK);
4939 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4940 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4941 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4942 EXPECT_HR(hr, S_OK);
4944 V_VT(&dest) = VT_EMPTY;
4945 hr = IMXWriter_get_output(writer, &dest);
4946 EXPECT_HR(hr, S_OK);
4947 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4948 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4949 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4950 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4951 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4952 VariantClear(&dest);
4954 /* internal entities */
4955 V_VT(&dest) = VT_EMPTY;
4956 hr = IMXWriter_put_output(writer, dest);
4957 EXPECT_HR(hr, S_OK);
4959 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4960 EXPECT_HR(hr, E_INVALIDARG);
4962 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL);
4963 EXPECT_HR(hr, E_POINTER);
4965 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4966 EXPECT_HR(hr, E_INVALIDARG);
4968 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4969 EXPECT_HR(hr, S_OK);
4971 V_VT(&dest) = VT_EMPTY;
4972 hr = IMXWriter_get_output(writer, &dest);
4973 EXPECT_HR(hr, S_OK);
4974 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4975 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4976 VariantClear(&dest);
4978 /* external entities */
4979 V_VT(&dest) = VT_EMPTY;
4980 hr = IMXWriter_put_output(writer, dest);
4981 ok(hr == S_OK, "got 0x%08x\n", hr);
4983 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0);
4984 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4986 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL);
4987 ok(hr == E_POINTER, "got 0x%08x\n", hr);
4989 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0);
4990 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4992 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"),
4993 _bstr_("sysid"), strlen("sysid"));
4994 ok(hr == S_OK, "got 0x%08x\n", hr);
4996 V_VT(&dest) = VT_EMPTY;
4997 hr = IMXWriter_get_output(writer, &dest);
4998 ok(hr == S_OK, "got 0x%08x\n", hr);
4999 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5000 ok(!lstrcmpW(_bstr_("<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5001 VariantClear(&dest);
5003 ISAXContentHandler_Release(content);
5004 ISAXLexicalHandler_Release(lexical);
5005 IVBSAXLexicalHandler_Release(vblexical);
5006 IVBSAXDeclHandler_Release(vbdecl);
5007 ISAXDeclHandler_Release(decl);
5008 IMXWriter_Release(writer);
5009 free_bstrs();
5012 typedef struct {
5013 const CLSID *clsid;
5014 const char *uri;
5015 const char *local;
5016 const char *qname;
5017 const char *type;
5018 const char *value;
5019 HRESULT hr;
5020 } addattribute_test_t;
5022 static const addattribute_test_t addattribute_data[] = {
5023 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5024 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5025 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5026 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
5028 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5029 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5030 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5031 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
5033 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5034 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5035 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5036 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
5038 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
5039 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
5040 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
5041 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
5043 { NULL }
5046 static void test_mxattr_addAttribute(void)
5048 const addattribute_test_t *table = addattribute_data;
5049 int i = 0;
5051 while (table->clsid)
5053 ISAXAttributes *saxattr;
5054 IMXAttributes *mxattr;
5055 const WCHAR *value;
5056 int len, index;
5057 HRESULT hr;
5059 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5061 table++;
5062 i++;
5063 continue;
5066 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5067 &IID_IMXAttributes, (void**)&mxattr);
5068 EXPECT_HR(hr, S_OK);
5070 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5071 EXPECT_HR(hr, S_OK);
5073 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5074 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5075 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5077 hr = ISAXAttributes_getLength(saxattr, NULL);
5078 EXPECT_HR(hr, E_POINTER);
5081 len = -1;
5082 hr = ISAXAttributes_getLength(saxattr, &len);
5083 EXPECT_HR(hr, S_OK);
5084 ok(len == 0, "got %d\n", len);
5086 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5087 EXPECT_HR(hr, E_INVALIDARG);
5089 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5090 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5092 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5093 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5095 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5096 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5098 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5099 EXPECT_HR(hr, E_INVALIDARG);
5101 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5102 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5104 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5105 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5107 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5108 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5110 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
5111 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
5112 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
5114 if (hr == S_OK)
5116 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5117 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5118 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5120 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5121 EXPECT_HR(hr, E_POINTER);
5123 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5124 EXPECT_HR(hr, E_POINTER);
5126 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5127 EXPECT_HR(hr, E_POINTER);
5129 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5130 EXPECT_HR(hr, E_POINTER);
5132 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5133 EXPECT_HR(hr, E_POINTER);
5135 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5136 EXPECT_HR(hr, E_POINTER);
5139 len = -1;
5140 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5141 EXPECT_HR(hr, S_OK);
5142 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5143 table->value);
5144 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5146 len = -1;
5147 value = (void*)0xdeadbeef;
5148 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5149 EXPECT_HR(hr, S_OK);
5151 if (table->type)
5153 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5154 table->type);
5155 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
5157 else
5159 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
5160 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
5163 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
5164 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5165 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5167 EXPECT_HR(hr, E_POINTER);
5169 else
5170 EXPECT_HR(hr, E_INVALIDARG);
5172 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
5173 EXPECT_HR(hr, E_INVALIDARG);
5175 index = -1;
5176 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
5177 EXPECT_HR(hr, E_INVALIDARG);
5178 ok(index == -1, "%d: got wrong index %d\n", i, index);
5180 index = -1;
5181 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
5182 EXPECT_HR(hr, E_INVALIDARG);
5183 ok(index == -1, "%d: got wrong index %d\n", i, index);
5185 index = -1;
5186 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
5187 EXPECT_HR(hr, S_OK);
5188 ok(index == 0, "%d: got wrong index %d\n", i, index);
5190 index = -1;
5191 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
5192 EXPECT_HR(hr, E_INVALIDARG);
5193 ok(index == -1, "%d: got wrong index %d\n", i, index);
5195 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
5196 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
5198 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5199 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5201 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5202 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5204 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5205 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5207 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5208 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5210 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5211 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5213 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5214 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5216 else
5218 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5219 EXPECT_HR(hr, E_POINTER);
5221 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5222 EXPECT_HR(hr, E_POINTER);
5224 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5225 EXPECT_HR(hr, E_POINTER);
5227 /* versions 4 and 6 crash */
5228 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
5229 EXPECT_HR(hr, E_POINTER);
5231 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
5232 EXPECT_HR(hr, E_POINTER);
5234 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5235 EXPECT_HR(hr, E_POINTER);
5237 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5238 EXPECT_HR(hr, E_POINTER);
5240 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5241 EXPECT_HR(hr, E_POINTER);
5243 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
5244 EXPECT_HR(hr, E_POINTER);
5246 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
5247 EXPECT_HR(hr, E_POINTER);
5249 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
5250 strlen(table->local), NULL, NULL);
5251 EXPECT_HR(hr, E_POINTER);
5254 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
5255 EXPECT_HR(hr, S_OK);
5256 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5257 table->value);
5258 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5260 if (table->uri) {
5261 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
5262 _bstr_(table->local), strlen(table->local), &value, &len);
5263 EXPECT_HR(hr, S_OK);
5264 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5265 table->value);
5266 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5270 len = -1;
5271 hr = ISAXAttributes_getLength(saxattr, &len);
5272 EXPECT_HR(hr, S_OK);
5273 if (table->hr == S_OK)
5274 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
5275 else
5276 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
5278 ISAXAttributes_Release(saxattr);
5279 IMXAttributes_Release(mxattr);
5281 table++;
5282 i++;
5285 free_bstrs();
5288 static void test_mxattr_clear(void)
5290 ISAXAttributes *saxattr;
5291 IMXAttributes *mxattr;
5292 const WCHAR *ptr;
5293 HRESULT hr;
5294 int len;
5296 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5297 &IID_IMXAttributes, (void**)&mxattr);
5298 EXPECT_HR(hr, S_OK);
5300 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5301 EXPECT_HR(hr, S_OK);
5303 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
5304 EXPECT_HR(hr, E_INVALIDARG);
5306 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5307 EXPECT_HR(hr, E_INVALIDARG);
5309 hr = IMXAttributes_clear(mxattr);
5310 EXPECT_HR(hr, S_OK);
5312 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
5313 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
5314 EXPECT_HR(hr, S_OK);
5316 len = -1;
5317 hr = ISAXAttributes_getLength(saxattr, &len);
5318 EXPECT_HR(hr, S_OK);
5319 ok(len == 1, "got %d\n", len);
5321 len = -1;
5322 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
5323 EXPECT_HR(hr, E_POINTER);
5324 ok(len == -1, "got %d\n", len);
5326 ptr = (void*)0xdeadbeef;
5327 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
5328 EXPECT_HR(hr, E_POINTER);
5329 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5331 len = 0;
5332 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5333 EXPECT_HR(hr, S_OK);
5334 ok(len == 5, "got %d\n", len);
5335 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
5337 hr = IMXAttributes_clear(mxattr);
5338 EXPECT_HR(hr, S_OK);
5340 len = -1;
5341 hr = ISAXAttributes_getLength(saxattr, &len);
5342 EXPECT_HR(hr, S_OK);
5343 ok(len == 0, "got %d\n", len);
5345 len = -1;
5346 ptr = (void*)0xdeadbeef;
5347 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5348 EXPECT_HR(hr, E_INVALIDARG);
5349 ok(len == -1, "got %d\n", len);
5350 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5352 IMXAttributes_Release(mxattr);
5353 ISAXAttributes_Release(saxattr);
5354 free_bstrs();
5357 static void test_mxattr_dispex(void)
5359 IMXAttributes *mxattr;
5360 IDispatchEx *dispex;
5361 IUnknown *unk;
5362 HRESULT hr;
5364 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5365 &IID_IMXAttributes, (void**)&mxattr);
5366 EXPECT_HR(hr, S_OK);
5368 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
5369 EXPECT_HR(hr, S_OK);
5370 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
5371 test_obj_dispex(unk);
5372 IUnknown_Release(unk);
5373 IDispatchEx_Release(dispex);
5375 IMXAttributes_Release(mxattr);
5378 static void test_mxattr_qi(void)
5380 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
5381 ISAXAttributes *saxattr;
5382 IMXAttributes *mxattr;
5383 HRESULT hr;
5385 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5386 &IID_IMXAttributes, (void**)&mxattr);
5387 EXPECT_HR(hr, S_OK);
5389 EXPECT_REF(mxattr, 1);
5390 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5391 EXPECT_HR(hr, S_OK);
5393 EXPECT_REF(mxattr, 2);
5394 EXPECT_REF(saxattr, 2);
5396 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
5397 EXPECT_HR(hr, S_OK);
5399 EXPECT_REF(vbsaxattr, 3);
5400 EXPECT_REF(mxattr, 3);
5401 EXPECT_REF(saxattr, 3);
5403 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
5404 EXPECT_HR(hr, S_OK);
5406 EXPECT_REF(vbsaxattr, 4);
5407 EXPECT_REF(mxattr, 4);
5408 EXPECT_REF(saxattr, 4);
5410 IMXAttributes_Release(mxattr);
5411 ISAXAttributes_Release(saxattr);
5412 IVBSAXAttributes_Release(vbsaxattr);
5413 IVBSAXAttributes_Release(vbsaxattr2);
5416 static struct msxmlsupported_data_t saxattr_support_data[] =
5418 { &CLSID_SAXAttributes, "SAXAttributes" },
5419 { &CLSID_SAXAttributes30, "SAXAttributes30" },
5420 { &CLSID_SAXAttributes40, "SAXAttributes40" },
5421 { &CLSID_SAXAttributes60, "SAXAttributes60" },
5422 { NULL }
5425 static void test_mxattr_localname(void)
5427 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
5428 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
5429 static const WCHAR uri1W[] = {'u','r','i','1',0};
5430 static const WCHAR uriW[] = {'u','r','i',0};
5432 const struct msxmlsupported_data_t *table = saxattr_support_data;
5434 while (table->clsid)
5436 ISAXAttributes *saxattr;
5437 IMXAttributes *mxattr;
5438 HRESULT hr;
5439 int index;
5441 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5443 table++;
5444 continue;
5447 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5448 &IID_IMXAttributes, (void**)&mxattr);
5449 EXPECT_HR(hr, S_OK);
5451 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5452 EXPECT_HR(hr, S_OK);
5454 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5455 EXPECT_HR(hr, E_INVALIDARG);
5457 /* add some ambiguos attribute names */
5458 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5459 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5460 EXPECT_HR(hr, S_OK);
5461 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5462 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5463 EXPECT_HR(hr, S_OK);
5465 index = -1;
5466 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5467 EXPECT_HR(hr, S_OK);
5468 ok(index == 0, "%s: got index %d\n", table->name, index);
5470 index = -1;
5471 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5472 EXPECT_HR(hr, E_INVALIDARG);
5473 ok(index == -1, "%s: got index %d\n", table->name, index);
5475 index = -1;
5476 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5477 EXPECT_HR(hr, E_INVALIDARG);
5478 ok(index == -1, "%s: got index %d\n", table->name, index);
5480 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5481 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5483 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5484 EXPECT_HR(hr, E_POINTER);
5486 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5487 EXPECT_HR(hr, E_POINTER);
5489 else
5491 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5492 EXPECT_HR(hr, E_INVALIDARG);
5494 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5495 EXPECT_HR(hr, E_INVALIDARG);
5498 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5499 EXPECT_HR(hr, E_INVALIDARG);
5501 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5502 EXPECT_HR(hr, E_INVALIDARG);
5504 table++;
5506 ISAXAttributes_Release(saxattr);
5507 IMXAttributes_Release(mxattr);
5508 free_bstrs();
5512 static void test_mxwriter_indent(void)
5514 ISAXContentHandler *content;
5515 IMXWriter *writer;
5516 VARIANT dest;
5517 HRESULT hr;
5519 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer);
5520 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5522 hr = IMXWriter_put_indent(writer, VARIANT_TRUE);
5523 ok(hr == S_OK, "got %08x\n", hr);
5525 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
5526 ok(hr == S_OK, "got %08x\n", hr);
5528 hr = ISAXContentHandler_startDocument(content);
5529 ok(hr == S_OK, "got %08x\n", hr);
5531 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
5532 ok(hr == S_OK, "got %08x\n", hr);
5534 hr = ISAXContentHandler_characters(content, _bstr_(""), 0);
5535 ok(hr == S_OK, "got %08x\n", hr);
5537 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL);
5538 ok(hr == S_OK, "got %08x\n", hr);
5540 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL);
5541 ok(hr == S_OK, "got %08x\n", hr);
5543 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1);
5544 ok(hr == S_OK, "got %08x\n", hr);
5546 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1);
5547 ok(hr == S_OK, "got %08x\n", hr);
5549 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1);
5550 ok(hr == S_OK, "got %08x\n", hr);
5552 hr = ISAXContentHandler_endDocument(content);
5553 ok(hr == S_OK, "got %08x\n", hr);
5555 V_VT(&dest) = VT_EMPTY;
5556 hr = IMXWriter_get_output(writer, &dest);
5557 ok(hr == S_OK, "got %08x\n", hr);
5558 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5559 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n<a><b>\r\n\t\t<c/>\r\n\t</b>\r\n</a>"), V_BSTR(&dest)),
5560 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5561 VariantClear(&dest);
5563 ISAXContentHandler_Release(content);
5564 IMXWriter_Release(writer);
5566 free_bstrs();
5569 START_TEST(saxreader)
5571 ISAXXMLReader *reader;
5572 HRESULT hr;
5574 hr = CoInitialize(NULL);
5575 ok(hr == S_OK, "failed to init com\n");
5577 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5578 &IID_ISAXXMLReader, (void**)&reader);
5580 if(FAILED(hr))
5582 skip("Failed to create SAXXMLReader instance\n");
5583 CoUninitialize();
5584 return;
5586 ISAXXMLReader_Release(reader);
5588 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5590 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5592 test_saxreader();
5593 test_saxreader_properties();
5594 test_saxreader_features();
5595 test_saxreader_encoding();
5596 test_saxreader_dispex();
5598 /* MXXMLWriter tests */
5599 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5600 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5602 test_mxwriter_handlers();
5603 test_mxwriter_startenddocument();
5604 test_mxwriter_startendelement();
5605 test_mxwriter_characters();
5606 test_mxwriter_comment();
5607 test_mxwriter_cdata();
5608 test_mxwriter_pi();
5609 test_mxwriter_ignorablespaces();
5610 test_mxwriter_dtd();
5611 test_mxwriter_properties();
5612 test_mxwriter_flush();
5613 test_mxwriter_stream();
5614 test_mxwriter_encoding();
5615 test_mxwriter_dispex();
5616 test_mxwriter_indent();
5618 else
5619 win_skip("MXXMLWriter not supported\n");
5621 /* SAXAttributes tests */
5622 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5623 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5625 test_mxattr_qi();
5626 test_mxattr_addAttribute();
5627 test_mxattr_clear();
5628 test_mxattr_localname();
5629 test_mxattr_dispex();
5631 else
5632 skip("SAXAttributes not supported\n");
5634 CoUninitialize();