TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blob0958c03d685b0f469e66d7032c87946a1f520f45
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 IStream_Release(stream);
2395 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2396 EXPECT_HR(hr, S_OK);
2398 /* switch off 'namespace-prefixes' feature */
2399 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2400 EXPECT_HR(hr, S_OK);
2402 stream = create_test_stream(test_attributes, -1);
2403 V_VT(&var) = VT_UNKNOWN;
2404 V_UNKNOWN(&var) = (IUnknown*)stream;
2406 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2407 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2409 test_seq = content_handler_test_attributes_alt_no_prefix;
2411 else
2412 test_seq = content_handler_test_attributes_no_prefix;
2414 set_expected_seq(test_seq);
2415 hr = ISAXXMLReader_parse(reader, var);
2416 EXPECT_HR(hr, S_OK);
2417 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2418 IStream_Release(stream);
2420 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2421 EXPECT_HR(hr, S_OK);
2423 /* attribute normalization */
2424 stream = create_test_stream(attribute_normalize, -1);
2425 V_VT(&var) = VT_UNKNOWN;
2426 V_UNKNOWN(&var) = (IUnknown*)stream;
2428 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2429 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2431 test_seq = attribute_norm_alt;
2433 else
2434 test_seq = attribute_norm;
2436 set_expected_seq(test_seq);
2437 hr = ISAXXMLReader_parse(reader, var);
2438 EXPECT_HR(hr, S_OK);
2439 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2440 IStream_Release(stream);
2442 resolver = (void*)0xdeadbeef;
2443 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2444 ok(hr == S_OK, "got 0x%08x\n", hr);
2445 ok(resolver == NULL, "got %p\n", resolver);
2447 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2448 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2450 /* CDATA sections */
2451 init_saxlexicalhandler(&lexicalhandler, S_OK);
2453 V_VT(&var) = VT_UNKNOWN;
2454 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2455 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2456 ok(hr == S_OK, "got 0x%08x\n", hr);
2458 stream = create_test_stream(test_cdata_xml, -1);
2459 V_VT(&var) = VT_UNKNOWN;
2460 V_UNKNOWN(&var) = (IUnknown*)stream;
2462 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2463 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2464 test_seq = cdata_test_alt;
2465 else
2466 test_seq = cdata_test;
2468 set_expected_seq(test_seq);
2469 hr = ISAXXMLReader_parse(reader, var);
2470 ok(hr == S_OK, "got 0x%08x\n", hr);
2471 sprintf(seqname, "%s: cdata test", table->name);
2472 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2474 IStream_Release(stream);
2476 /* 2. CDATA sections */
2477 stream = create_test_stream(test2_cdata_xml, -1);
2478 V_VT(&var) = VT_UNKNOWN;
2479 V_UNKNOWN(&var) = (IUnknown*)stream;
2481 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2482 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2483 test_seq = cdata_test2_alt;
2484 else
2485 test_seq = cdata_test2;
2487 set_expected_seq(test_seq);
2488 hr = ISAXXMLReader_parse(reader, var);
2489 ok(hr == S_OK, "got 0x%08x\n", hr);
2490 sprintf(seqname, "%s: cdata test 2", table->name);
2491 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2493 IStream_Release(stream);
2495 /* 3. CDATA sections */
2496 stream = create_test_stream(test3_cdata_xml, -1);
2497 V_VT(&var) = VT_UNKNOWN;
2498 V_UNKNOWN(&var) = (IUnknown*)stream;
2500 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2501 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2502 test_seq = cdata_test3_alt;
2503 else
2504 test_seq = cdata_test3;
2506 set_expected_seq(test_seq);
2507 hr = ISAXXMLReader_parse(reader, var);
2508 ok(hr == S_OK, "got 0x%08x\n", hr);
2509 sprintf(seqname, "%s: cdata test 3", table->name);
2510 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2512 IStream_Release(stream);
2514 ISAXXMLReader_Release(reader);
2515 table++;
2518 free_bstrs();
2521 struct saxreader_props_test_t
2523 const char *prop_name;
2524 IUnknown *iface;
2527 static const struct saxreader_props_test_t props_test_data[] = {
2528 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2529 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2530 { 0 }
2533 static void test_saxreader_properties(void)
2535 const struct saxreader_props_test_t *ptr = props_test_data;
2536 ISAXXMLReader *reader;
2537 HRESULT hr;
2538 VARIANT v;
2539 BSTR str;
2541 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2542 &IID_ISAXXMLReader, (void**)&reader);
2543 EXPECT_HR(hr, S_OK);
2545 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2546 EXPECT_HR(hr, E_POINTER);
2548 while (ptr->prop_name)
2550 VARIANT varref;
2551 LONG ref;
2553 init_saxlexicalhandler(&lexicalhandler, S_OK);
2554 init_saxdeclhandler(&declhandler, S_OK);
2556 V_VT(&v) = VT_EMPTY;
2557 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2558 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2559 EXPECT_HR(hr, S_OK);
2560 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2561 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2563 /* VT_UNKNOWN */
2564 V_VT(&v) = VT_UNKNOWN;
2565 V_UNKNOWN(&v) = ptr->iface;
2566 ref = get_refcount(ptr->iface);
2567 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2568 EXPECT_HR(hr, S_OK);
2569 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2571 /* VT_DISPATCH */
2572 V_VT(&v) = VT_DISPATCH;
2573 V_UNKNOWN(&v) = ptr->iface;
2574 ref = get_refcount(ptr->iface);
2575 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2576 EXPECT_HR(hr, S_OK);
2577 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2579 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2580 V_VT(&varref) = VT_UNKNOWN;
2581 V_UNKNOWN(&varref) = ptr->iface;
2583 V_VT(&v) = VT_VARIANT|VT_BYREF;
2584 V_VARIANTREF(&v) = &varref;
2585 ref = get_refcount(ptr->iface);
2586 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2587 EXPECT_HR(hr, S_OK);
2588 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2590 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2591 V_VT(&varref) = VT_DISPATCH;
2592 V_UNKNOWN(&varref) = ptr->iface;
2594 V_VT(&v) = VT_VARIANT|VT_BYREF;
2595 V_VARIANTREF(&v) = &varref;
2596 ref = get_refcount(ptr->iface);
2597 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2598 EXPECT_HR(hr, S_OK);
2599 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2601 V_VT(&v) = VT_EMPTY;
2602 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2604 ref = get_refcount(ptr->iface);
2605 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2606 EXPECT_HR(hr, S_OK);
2607 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2608 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2609 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2610 VariantClear(&v);
2612 V_VT(&v) = VT_EMPTY;
2613 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2614 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2615 EXPECT_HR(hr, S_OK);
2617 V_VT(&v) = VT_EMPTY;
2618 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2619 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2620 EXPECT_HR(hr, S_OK);
2621 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2622 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2624 V_VT(&v) = VT_UNKNOWN;
2625 V_UNKNOWN(&v) = ptr->iface;
2626 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2627 EXPECT_HR(hr, S_OK);
2629 /* only VT_EMPTY seems to be valid to reset property */
2630 V_VT(&v) = VT_I4;
2631 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2632 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2633 EXPECT_HR(hr, E_INVALIDARG);
2635 V_VT(&v) = VT_EMPTY;
2636 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2637 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2638 EXPECT_HR(hr, S_OK);
2639 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2640 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2641 VariantClear(&v);
2643 V_VT(&v) = VT_UNKNOWN;
2644 V_UNKNOWN(&v) = NULL;
2645 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2646 EXPECT_HR(hr, S_OK);
2648 V_VT(&v) = VT_EMPTY;
2649 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2650 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2651 EXPECT_HR(hr, S_OK);
2652 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2653 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2655 /* block QueryInterface on handler riid */
2656 V_VT(&v) = VT_UNKNOWN;
2657 V_UNKNOWN(&v) = ptr->iface;
2658 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2659 EXPECT_HR(hr, S_OK);
2661 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2662 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2664 V_VT(&v) = VT_UNKNOWN;
2665 V_UNKNOWN(&v) = ptr->iface;
2666 EXPECT_REF(ptr->iface, 1);
2667 ref = get_refcount(ptr->iface);
2668 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2669 EXPECT_HR(hr, E_NOINTERFACE);
2670 EXPECT_REF(ptr->iface, 1);
2672 V_VT(&v) = VT_EMPTY;
2673 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2674 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2675 EXPECT_HR(hr, S_OK);
2676 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2677 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2679 ptr++;
2680 free_bstrs();
2683 ISAXXMLReader_Release(reader);
2685 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2686 return;
2688 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2689 &IID_ISAXXMLReader, (void**)&reader);
2690 EXPECT_HR(hr, S_OK);
2692 /* xmldecl-version property */
2693 V_VT(&v) = VT_EMPTY;
2694 V_BSTR(&v) = (void*)0xdeadbeef;
2695 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2696 EXPECT_HR(hr, S_OK);
2697 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2698 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2700 /* stream without declaration */
2701 V_VT(&v) = VT_BSTR;
2702 V_BSTR(&v) = _bstr_("<element></element>");
2703 hr = ISAXXMLReader_parse(reader, v);
2704 EXPECT_HR(hr, S_OK);
2706 V_VT(&v) = VT_EMPTY;
2707 V_BSTR(&v) = (void*)0xdeadbeef;
2708 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2709 EXPECT_HR(hr, S_OK);
2710 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2711 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2713 /* stream with declaration */
2714 V_VT(&v) = VT_BSTR;
2715 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2716 hr = ISAXXMLReader_parse(reader, v);
2717 EXPECT_HR(hr, S_OK);
2719 /* VT_BSTR|VT_BYREF input type */
2720 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2721 V_VT(&v) = VT_BSTR|VT_BYREF;
2722 V_BSTRREF(&v) = &str;
2723 hr = ISAXXMLReader_parse(reader, v);
2724 EXPECT_HR(hr, S_OK);
2726 V_VT(&v) = VT_EMPTY;
2727 V_BSTR(&v) = (void*)0xdeadbeef;
2728 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2729 EXPECT_HR(hr, S_OK);
2730 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2731 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2732 VariantClear(&v);
2734 ISAXXMLReader_Release(reader);
2735 free_bstrs();
2738 struct feature_ns_entry_t {
2739 const GUID *guid;
2740 const char *clsid;
2741 VARIANT_BOOL value;
2742 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2745 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2746 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2747 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2748 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2749 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2750 { 0 }
2753 static const char *feature_names[] = {
2754 "http://xml.org/sax/features/namespaces",
2755 "http://xml.org/sax/features/namespace-prefixes",
2759 static void test_saxreader_features(void)
2761 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2762 ISAXXMLReader *reader;
2764 while (entry->guid)
2766 VARIANT_BOOL value;
2767 const char **name;
2768 HRESULT hr;
2770 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2771 if (hr != S_OK)
2773 win_skip("can't create %s instance\n", entry->clsid);
2774 entry++;
2775 continue;
2778 name = feature_names;
2779 while (*name)
2781 value = 0xc;
2782 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2783 EXPECT_HR(hr, S_OK);
2784 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2786 value = 0xc;
2787 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2788 EXPECT_HR(hr, S_OK);
2790 value = 0xd;
2791 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2792 EXPECT_HR(hr, S_OK);
2793 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2795 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2796 EXPECT_HR(hr, S_OK);
2797 value = 0xd;
2798 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2799 EXPECT_HR(hr, S_OK);
2800 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2802 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2803 EXPECT_HR(hr, S_OK);
2804 value = 0xd;
2805 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2806 EXPECT_HR(hr, S_OK);
2807 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2809 name++;
2812 ISAXXMLReader_Release(reader);
2814 entry++;
2818 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2819 static const CHAR UTF8BOMTest[] =
2820 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2821 "<a></a>\n";
2823 struct enc_test_entry_t {
2824 const GUID *guid;
2825 const char *clsid;
2826 const char *data;
2827 HRESULT hr;
2828 BOOL todo;
2831 static const struct enc_test_entry_t encoding_test_data[] = {
2832 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE },
2833 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE },
2834 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE },
2835 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE },
2836 { 0 }
2839 static void test_saxreader_encoding(void)
2841 const struct enc_test_entry_t *entry = encoding_test_data;
2842 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2843 static const CHAR testXmlA[] = "test.xml";
2845 while (entry->guid)
2847 ISAXXMLReader *reader;
2848 VARIANT input;
2849 DWORD written;
2850 HANDLE file;
2851 HRESULT hr;
2853 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2854 if (hr != S_OK)
2856 win_skip("can't create %s instance\n", entry->clsid);
2857 entry++;
2858 continue;
2861 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2862 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2863 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2864 CloseHandle(file);
2866 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2867 if (entry->todo)
2868 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2869 else
2870 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2872 DeleteFileA(testXmlA);
2874 /* try BSTR input with no BOM or '<?xml' instruction */
2875 V_VT(&input) = VT_BSTR;
2876 V_BSTR(&input) = _bstr_("<element></element>");
2877 hr = ISAXXMLReader_parse(reader, input);
2878 EXPECT_HR(hr, S_OK);
2880 ISAXXMLReader_Release(reader);
2882 free_bstrs();
2883 entry++;
2887 static void test_mxwriter_handlers(void)
2889 IMXWriter *writer;
2890 HRESULT hr;
2891 int i;
2893 static REFIID riids[] =
2895 &IID_ISAXContentHandler,
2896 &IID_ISAXLexicalHandler,
2897 &IID_ISAXDeclHandler,
2898 &IID_ISAXDTDHandler,
2899 &IID_ISAXErrorHandler,
2900 &IID_IVBSAXDeclHandler,
2901 &IID_IVBSAXLexicalHandler,
2902 &IID_IVBSAXContentHandler,
2903 &IID_IVBSAXDTDHandler,
2904 &IID_IVBSAXErrorHandler
2907 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2908 &IID_IMXWriter, (void**)&writer);
2909 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2911 EXPECT_REF(writer, 1);
2913 for (i = 0; i < sizeof(riids)/sizeof(REFIID); i++)
2915 IUnknown *handler;
2916 IMXWriter *writer2;
2918 /* handler from IMXWriter */
2919 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
2920 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2921 EXPECT_REF(writer, 2);
2922 EXPECT_REF(handler, 2);
2924 /* IMXWriter from a handler */
2925 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2926 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2927 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2928 EXPECT_REF(writer, 3);
2929 EXPECT_REF(writer2, 3);
2930 IMXWriter_Release(writer2);
2931 IUnknown_Release(handler);
2934 IMXWriter_Release(writer);
2937 static struct msxmlsupported_data_t mxwriter_support_data[] =
2939 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2940 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2941 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2942 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2943 { NULL }
2946 static struct msxmlsupported_data_t mxattributes_support_data[] =
2948 { &CLSID_SAXAttributes, "SAXAttributes" },
2949 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2950 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2951 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2952 { NULL }
2955 struct mxwriter_props_t
2957 const GUID *clsid;
2958 VARIANT_BOOL bom;
2959 VARIANT_BOOL disable_escape;
2960 VARIANT_BOOL indent;
2961 VARIANT_BOOL omitdecl;
2962 VARIANT_BOOL standalone;
2963 const char *encoding;
2966 static const struct mxwriter_props_t mxwriter_default_props[] =
2968 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2969 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2970 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2971 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2972 { NULL }
2975 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2977 int i = 0;
2979 while (table->clsid)
2981 IMXWriter *writer;
2982 VARIANT_BOOL b;
2983 BSTR encoding;
2984 HRESULT hr;
2986 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2988 table++;
2989 i++;
2990 continue;
2993 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2994 &IID_IMXWriter, (void**)&writer);
2995 EXPECT_HR(hr, S_OK);
2997 b = !table->bom;
2998 hr = IMXWriter_get_byteOrderMark(writer, &b);
2999 EXPECT_HR(hr, S_OK);
3000 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
3002 b = !table->disable_escape;
3003 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
3004 EXPECT_HR(hr, S_OK);
3005 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
3006 table->disable_escape);
3008 b = !table->indent;
3009 hr = IMXWriter_get_indent(writer, &b);
3010 EXPECT_HR(hr, S_OK);
3011 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
3013 b = !table->omitdecl;
3014 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
3015 EXPECT_HR(hr, S_OK);
3016 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
3018 b = !table->standalone;
3019 hr = IMXWriter_get_standalone(writer, &b);
3020 EXPECT_HR(hr, S_OK);
3021 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
3023 hr = IMXWriter_get_encoding(writer, &encoding);
3024 EXPECT_HR(hr, S_OK);
3025 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
3026 i, wine_dbgstr_w(encoding), table->encoding);
3027 SysFreeString(encoding);
3029 IMXWriter_Release(writer);
3031 table++;
3032 i++;
3036 static void test_mxwriter_properties(void)
3038 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
3039 static const WCHAR testW[] = {'t','e','s','t',0};
3040 ISAXContentHandler *content;
3041 IMXWriter *writer;
3042 VARIANT_BOOL b;
3043 HRESULT hr;
3044 BSTR str, str2;
3045 VARIANT dest;
3047 test_mxwriter_default_properties(mxwriter_default_props);
3049 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3050 &IID_IMXWriter, (void**)&writer);
3051 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3053 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
3054 ok(hr == E_POINTER, "got %08x\n", hr);
3056 hr = IMXWriter_get_byteOrderMark(writer, NULL);
3057 ok(hr == E_POINTER, "got %08x\n", hr);
3059 hr = IMXWriter_get_indent(writer, NULL);
3060 ok(hr == E_POINTER, "got %08x\n", hr);
3062 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
3063 ok(hr == E_POINTER, "got %08x\n", hr);
3065 hr = IMXWriter_get_standalone(writer, NULL);
3066 ok(hr == E_POINTER, "got %08x\n", hr);
3068 /* set and check */
3069 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
3070 ok(hr == S_OK, "got %08x\n", hr);
3072 b = VARIANT_FALSE;
3073 hr = IMXWriter_get_standalone(writer, &b);
3074 ok(hr == S_OK, "got %08x\n", hr);
3075 ok(b == VARIANT_TRUE, "got %d\n", b);
3077 hr = IMXWriter_get_encoding(writer, NULL);
3078 EXPECT_HR(hr, E_POINTER);
3080 /* UTF-16 is a default setting apparently */
3081 str = (void*)0xdeadbeef;
3082 hr = IMXWriter_get_encoding(writer, &str);
3083 EXPECT_HR(hr, S_OK);
3084 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
3086 str2 = (void*)0xdeadbeef;
3087 hr = IMXWriter_get_encoding(writer, &str2);
3088 ok(hr == S_OK, "got %08x\n", hr);
3089 ok(str != str2, "expected newly allocated, got same %p\n", str);
3091 SysFreeString(str2);
3092 SysFreeString(str);
3094 /* put empty string */
3095 str = SysAllocString(emptyW);
3096 hr = IMXWriter_put_encoding(writer, str);
3097 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3098 SysFreeString(str);
3100 str = (void*)0xdeadbeef;
3101 hr = IMXWriter_get_encoding(writer, &str);
3102 EXPECT_HR(hr, S_OK);
3103 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
3104 SysFreeString(str);
3106 /* invalid encoding name */
3107 str = SysAllocString(testW);
3108 hr = IMXWriter_put_encoding(writer, str);
3109 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3110 SysFreeString(str);
3112 /* test case sensivity */
3113 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
3114 EXPECT_HR(hr, S_OK);
3115 str = (void*)0xdeadbeef;
3116 hr = IMXWriter_get_encoding(writer, &str);
3117 EXPECT_HR(hr, S_OK);
3118 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
3119 SysFreeString(str);
3121 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
3122 EXPECT_HR(hr, S_OK);
3123 str = (void*)0xdeadbeef;
3124 hr = IMXWriter_get_encoding(writer, &str);
3125 EXPECT_HR(hr, S_OK);
3126 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
3127 SysFreeString(str);
3129 /* how it affects document creation */
3130 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3131 EXPECT_HR(hr, S_OK);
3133 hr = ISAXContentHandler_startDocument(content);
3134 EXPECT_HR(hr, S_OK);
3135 hr = ISAXContentHandler_endDocument(content);
3136 EXPECT_HR(hr, S_OK);
3138 V_VT(&dest) = VT_EMPTY;
3139 hr = IMXWriter_get_output(writer, &dest);
3140 EXPECT_HR(hr, S_OK);
3141 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3142 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
3143 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3144 VariantClear(&dest);
3145 ISAXContentHandler_Release(content);
3147 hr = IMXWriter_get_version(writer, NULL);
3148 ok(hr == E_POINTER, "got %08x\n", hr);
3149 /* default version is 'surprisingly' 1.0 */
3150 hr = IMXWriter_get_version(writer, &str);
3151 ok(hr == S_OK, "got %08x\n", hr);
3152 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3153 SysFreeString(str);
3155 /* store version string as is */
3156 hr = IMXWriter_put_version(writer, NULL);
3157 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3159 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3160 ok(hr == S_OK, "got %08x\n", hr);
3162 hr = IMXWriter_put_version(writer, _bstr_(""));
3163 ok(hr == S_OK, "got %08x\n", hr);
3164 hr = IMXWriter_get_version(writer, &str);
3165 ok(hr == S_OK, "got %08x\n", hr);
3166 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3167 SysFreeString(str);
3169 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3170 ok(hr == S_OK, "got %08x\n", hr);
3171 hr = IMXWriter_get_version(writer, &str);
3172 ok(hr == S_OK, "got %08x\n", hr);
3173 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3174 SysFreeString(str);
3176 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3177 ok(hr == S_OK, "got %08x\n", hr);
3178 hr = IMXWriter_get_version(writer, &str);
3179 ok(hr == S_OK, "got %08x\n", hr);
3180 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3181 SysFreeString(str);
3183 IMXWriter_Release(writer);
3184 free_bstrs();
3187 static void test_mxwriter_flush(void)
3189 ISAXContentHandler *content;
3190 IMXWriter *writer;
3191 LARGE_INTEGER pos;
3192 ULARGE_INTEGER pos2;
3193 IStream *stream;
3194 VARIANT dest;
3195 HRESULT hr;
3196 char *buff;
3197 LONG ref;
3198 int len;
3200 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3201 &IID_IMXWriter, (void**)&writer);
3202 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3204 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3205 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3206 EXPECT_REF(stream, 1);
3208 /* detach when nothing was attached */
3209 V_VT(&dest) = VT_EMPTY;
3210 hr = IMXWriter_put_output(writer, dest);
3211 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3213 /* attach stream */
3214 V_VT(&dest) = VT_UNKNOWN;
3215 V_UNKNOWN(&dest) = (IUnknown*)stream;
3216 hr = IMXWriter_put_output(writer, dest);
3217 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3218 todo_wine EXPECT_REF(stream, 3);
3220 /* detach setting VT_EMPTY destination */
3221 V_VT(&dest) = VT_EMPTY;
3222 hr = IMXWriter_put_output(writer, dest);
3223 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3224 EXPECT_REF(stream, 1);
3226 V_VT(&dest) = VT_UNKNOWN;
3227 V_UNKNOWN(&dest) = (IUnknown*)stream;
3228 hr = IMXWriter_put_output(writer, dest);
3229 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3231 /* flush() doesn't detach a stream */
3232 hr = IMXWriter_flush(writer);
3233 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3234 todo_wine EXPECT_REF(stream, 3);
3236 pos.QuadPart = 0;
3237 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3238 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3239 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3241 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3242 ok(hr == S_OK, "got %08x\n", hr);
3244 hr = ISAXContentHandler_startDocument(content);
3245 ok(hr == S_OK, "got %08x\n", hr);
3247 pos.QuadPart = 0;
3248 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3249 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3250 ok(pos2.QuadPart != 0, "expected stream beginning\n");
3252 /* already started */
3253 hr = ISAXContentHandler_startDocument(content);
3254 ok(hr == S_OK, "got %08x\n", hr);
3256 hr = ISAXContentHandler_endDocument(content);
3257 ok(hr == S_OK, "got %08x\n", hr);
3259 /* flushed on endDocument() */
3260 pos.QuadPart = 0;
3261 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3262 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3263 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3265 IStream_Release(stream);
3267 /* auto-flush feature */
3268 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3269 EXPECT_HR(hr, S_OK);
3270 EXPECT_REF(stream, 1);
3272 V_VT(&dest) = VT_UNKNOWN;
3273 V_UNKNOWN(&dest) = (IUnknown*)stream;
3274 hr = IMXWriter_put_output(writer, dest);
3275 EXPECT_HR(hr, S_OK);
3277 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
3278 EXPECT_HR(hr, S_OK);
3280 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3281 EXPECT_HR(hr, S_OK);
3283 hr = ISAXContentHandler_startDocument(content);
3284 EXPECT_HR(hr, S_OK);
3286 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3287 EXPECT_HR(hr, S_OK);
3289 /* internal buffer is flushed automatically on certain threshold */
3290 pos.QuadPart = 0;
3291 pos2.QuadPart = 1;
3292 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3293 EXPECT_HR(hr, S_OK);
3294 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3296 len = 2048;
3297 buff = HeapAlloc(GetProcessHeap(), 0, len+1);
3298 memset(buff, 'A', len);
3299 buff[len] = 0;
3300 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3301 EXPECT_HR(hr, S_OK);
3303 pos.QuadPart = 0;
3304 pos2.QuadPart = 0;
3305 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3306 EXPECT_HR(hr, S_OK);
3307 todo_wine
3308 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
3310 hr = IMXWriter_get_output(writer, NULL);
3311 EXPECT_HR(hr, E_POINTER);
3313 ref = get_refcount(stream);
3314 V_VT(&dest) = VT_EMPTY;
3315 hr = IMXWriter_get_output(writer, &dest);
3316 EXPECT_HR(hr, S_OK);
3317 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3318 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3319 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3320 VariantClear(&dest);
3322 hr = ISAXContentHandler_endDocument(content);
3323 EXPECT_HR(hr, S_OK);
3325 IStream_Release(stream);
3327 /* test char count lower than threshold */
3328 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3329 EXPECT_HR(hr, S_OK);
3330 EXPECT_REF(stream, 1);
3332 hr = ISAXContentHandler_startDocument(content);
3333 EXPECT_HR(hr, S_OK);
3335 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3336 EXPECT_HR(hr, S_OK);
3338 pos.QuadPart = 0;
3339 pos2.QuadPart = 1;
3340 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3341 EXPECT_HR(hr, S_OK);
3342 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3344 memset(buff, 'A', len);
3345 buff[len] = 0;
3346 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3347 EXPECT_HR(hr, S_OK);
3349 pos.QuadPart = 0;
3350 pos2.QuadPart = 1;
3351 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3352 EXPECT_HR(hr, S_OK);
3353 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3355 hr = ISAXContentHandler_endDocument(content);
3356 EXPECT_HR(hr, S_OK);
3358 /* test auto-flush function when stream is not set */
3359 V_VT(&dest) = VT_EMPTY;
3360 hr = IMXWriter_put_output(writer, dest);
3361 EXPECT_HR(hr, S_OK);
3363 hr = ISAXContentHandler_startDocument(content);
3364 EXPECT_HR(hr, S_OK);
3366 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3367 EXPECT_HR(hr, S_OK);
3369 memset(buff, 'A', len);
3370 buff[len] = 0;
3371 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3372 EXPECT_HR(hr, S_OK);
3374 V_VT(&dest) = VT_EMPTY;
3375 hr = IMXWriter_get_output(writer, &dest);
3376 EXPECT_HR(hr, S_OK);
3377 len += strlen("<a>");
3378 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3379 VariantClear(&dest);
3381 HeapFree(GetProcessHeap(), 0, buff);
3382 ISAXContentHandler_Release(content);
3383 IStream_Release(stream);
3384 IMXWriter_Release(writer);
3385 free_bstrs();
3388 static void test_mxwriter_startenddocument(void)
3390 ISAXContentHandler *content;
3391 IMXWriter *writer;
3392 VARIANT dest;
3393 HRESULT hr;
3395 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3396 &IID_IMXWriter, (void**)&writer);
3397 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3399 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3400 ok(hr == S_OK, "got %08x\n", hr);
3402 hr = ISAXContentHandler_startDocument(content);
3403 ok(hr == S_OK, "got %08x\n", hr);
3405 hr = ISAXContentHandler_endDocument(content);
3406 ok(hr == S_OK, "got %08x\n", hr);
3408 V_VT(&dest) = VT_EMPTY;
3409 hr = IMXWriter_get_output(writer, &dest);
3410 ok(hr == S_OK, "got %08x\n", hr);
3411 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3412 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3413 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3414 VariantClear(&dest);
3416 /* now try another startDocument */
3417 hr = ISAXContentHandler_startDocument(content);
3418 ok(hr == S_OK, "got %08x\n", hr);
3419 /* and get duplicated prolog */
3420 V_VT(&dest) = VT_EMPTY;
3421 hr = IMXWriter_get_output(writer, &dest);
3422 ok(hr == S_OK, "got %08x\n", hr);
3423 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3424 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3425 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3426 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3427 VariantClear(&dest);
3429 ISAXContentHandler_Release(content);
3430 IMXWriter_Release(writer);
3432 /* now with omitted declaration */
3433 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3434 &IID_IMXWriter, (void**)&writer);
3435 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3437 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3438 ok(hr == S_OK, "got %08x\n", hr);
3440 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3441 ok(hr == S_OK, "got %08x\n", hr);
3443 hr = ISAXContentHandler_startDocument(content);
3444 ok(hr == S_OK, "got %08x\n", hr);
3446 hr = ISAXContentHandler_endDocument(content);
3447 ok(hr == S_OK, "got %08x\n", hr);
3449 V_VT(&dest) = VT_EMPTY;
3450 hr = IMXWriter_get_output(writer, &dest);
3451 ok(hr == S_OK, "got %08x\n", hr);
3452 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3453 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3454 VariantClear(&dest);
3456 ISAXContentHandler_Release(content);
3457 IMXWriter_Release(writer);
3459 free_bstrs();
3462 enum startendtype
3464 StartElement = 0x001,
3465 EndElement = 0x010,
3466 StartEndElement = 0x011,
3467 DisableEscaping = 0x100
3470 struct writer_startendelement_t {
3471 const GUID *clsid;
3472 enum startendtype type;
3473 const char *uri;
3474 const char *local_name;
3475 const char *qname;
3476 const char *output;
3477 HRESULT hr;
3478 ISAXAttributes *attr;
3481 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\">";
3482 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\"/>";
3483 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\'\"/>";
3485 static const struct writer_startendelement_t writer_startendelement[] = {
3486 /* 0 */
3487 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3488 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3489 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3490 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3491 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3492 /* 5 */
3493 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3494 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3495 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3496 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3497 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3498 /* 10 */
3499 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3500 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3501 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3502 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3503 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3504 /* 15 */
3505 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3506 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3507 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3508 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3509 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3510 /* 20 */
3511 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3512 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3513 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3514 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3515 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3516 /* 25 */
3517 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3518 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3519 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3520 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3521 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3522 /* 30 */
3523 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3524 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3525 /* endElement tests */
3526 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3527 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3528 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3529 /* 35 */
3530 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3531 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3532 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3533 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3534 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3535 /* 40 */
3536 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3537 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3538 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3539 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3540 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3541 /* 45 */
3542 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3543 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3544 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3545 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3546 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3547 /* 50 */
3548 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3549 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3550 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3551 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3552 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3553 /* 55 */
3554 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3555 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3556 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3557 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3558 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3559 /* 60 */
3560 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3561 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3562 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3563 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3565 /* with attributes */
3566 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3567 /* 65 */
3568 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3569 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3570 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3571 /* empty elements */
3572 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3573 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3574 /* 70 */
3575 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3576 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3577 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3578 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3579 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3580 /* 75 */
3581 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3583 /* with disabled output escaping */
3584 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3585 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3586 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3587 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3589 { NULL }
3592 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3594 while (table->clsid)
3596 IUnknown *unk;
3597 HRESULT hr;
3599 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3600 if (hr == S_OK) IUnknown_Release(unk);
3602 table->supported = hr == S_OK;
3603 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3605 table++;
3609 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3611 int i = 0;
3613 while (table->clsid)
3615 ISAXContentHandler *content;
3616 IMXWriter *writer;
3617 HRESULT hr;
3619 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3621 table++;
3622 i++;
3623 continue;
3626 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3627 &IID_IMXWriter, (void**)&writer);
3628 EXPECT_HR(hr, S_OK);
3630 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3631 EXPECT_HR(hr, S_OK);
3633 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3634 EXPECT_HR(hr, S_OK);
3636 hr = ISAXContentHandler_startDocument(content);
3637 EXPECT_HR(hr, S_OK);
3639 if (table->type & DisableEscaping)
3641 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3642 EXPECT_HR(hr, S_OK);
3645 if (table->type & StartElement)
3647 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3648 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3649 table->qname ? strlen(table->qname) : 0, table->attr);
3650 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3653 if (table->type & EndElement)
3655 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0,
3656 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname),
3657 table->qname ? strlen(table->qname) : 0);
3658 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3661 /* test output */
3662 if (hr == S_OK)
3664 VARIANT dest;
3666 V_VT(&dest) = VT_EMPTY;
3667 hr = IMXWriter_get_output(writer, &dest);
3668 EXPECT_HR(hr, S_OK);
3669 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3670 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3671 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3672 VariantClear(&dest);
3675 ISAXContentHandler_Release(content);
3676 IMXWriter_Release(writer);
3678 table++;
3679 i++;
3682 free_bstrs();
3685 /* point of these test is to start/end element with different names and name lengths */
3686 struct writer_startendelement2_t {
3687 const GUID *clsid;
3688 const char *qnamestart;
3689 int qnamestart_len;
3690 const char *qnameend;
3691 int qnameend_len;
3692 const char *output;
3693 HRESULT hr;
3696 static const struct writer_startendelement2_t writer_startendelement2[] = {
3697 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3698 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3699 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3700 /* -1 length is not allowed for version 6 */
3701 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3703 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3704 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3705 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3706 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3707 { NULL }
3710 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3712 int i = 0;
3714 while (table->clsid)
3716 ISAXContentHandler *content;
3717 IMXWriter *writer;
3718 HRESULT hr;
3720 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3722 table++;
3723 i++;
3724 continue;
3727 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3728 &IID_IMXWriter, (void**)&writer);
3729 EXPECT_HR(hr, S_OK);
3731 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3732 EXPECT_HR(hr, S_OK);
3734 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3735 EXPECT_HR(hr, S_OK);
3737 hr = ISAXContentHandler_startDocument(content);
3738 EXPECT_HR(hr, S_OK);
3740 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3741 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3742 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3744 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3745 _bstr_(table->qnameend), table->qnameend_len);
3746 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3748 /* test output */
3749 if (hr == S_OK)
3751 VARIANT dest;
3753 V_VT(&dest) = VT_EMPTY;
3754 hr = IMXWriter_get_output(writer, &dest);
3755 EXPECT_HR(hr, S_OK);
3756 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3757 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3758 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3759 VariantClear(&dest);
3762 ISAXContentHandler_Release(content);
3763 IMXWriter_Release(writer);
3765 table++;
3766 i++;
3768 free_bstrs();
3773 static void test_mxwriter_startendelement(void)
3775 ISAXContentHandler *content;
3776 IMXWriter *writer;
3777 VARIANT dest;
3778 HRESULT hr;
3780 test_mxwriter_startendelement_batch(writer_startendelement);
3781 test_mxwriter_startendelement_batch2(writer_startendelement2);
3783 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3784 &IID_IMXWriter, (void**)&writer);
3785 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3787 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3788 ok(hr == S_OK, "got %08x\n", hr);
3790 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3791 ok(hr == S_OK, "got %08x\n", hr);
3793 hr = ISAXContentHandler_startDocument(content);
3794 ok(hr == S_OK, "got %08x\n", hr);
3796 /* all string pointers should be not null */
3797 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3798 ok(hr == S_OK, "got %08x\n", hr);
3800 V_VT(&dest) = VT_EMPTY;
3801 hr = IMXWriter_get_output(writer, &dest);
3802 ok(hr == S_OK, "got %08x\n", hr);
3803 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3804 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3805 VariantClear(&dest);
3807 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3808 ok(hr == S_OK, "got %08x\n", hr);
3810 V_VT(&dest) = VT_EMPTY;
3811 hr = IMXWriter_get_output(writer, &dest);
3812 ok(hr == S_OK, "got %08x\n", hr);
3813 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3814 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3815 VariantClear(&dest);
3817 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3818 EXPECT_HR(hr, E_INVALIDARG);
3820 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3821 EXPECT_HR(hr, E_INVALIDARG);
3823 /* only local name is an error too */
3824 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3825 EXPECT_HR(hr, E_INVALIDARG);
3827 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3828 EXPECT_HR(hr, S_OK);
3830 V_VT(&dest) = VT_EMPTY;
3831 hr = IMXWriter_get_output(writer, &dest);
3832 EXPECT_HR(hr, S_OK);
3833 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3834 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3835 VariantClear(&dest);
3837 hr = ISAXContentHandler_endDocument(content);
3838 EXPECT_HR(hr, S_OK);
3840 V_VT(&dest) = VT_EMPTY;
3841 hr = IMXWriter_put_output(writer, dest);
3842 EXPECT_HR(hr, S_OK);
3844 V_VT(&dest) = VT_EMPTY;
3845 hr = IMXWriter_get_output(writer, &dest);
3846 EXPECT_HR(hr, S_OK);
3847 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3848 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3849 VariantClear(&dest);
3851 hr = ISAXContentHandler_startDocument(content);
3852 EXPECT_HR(hr, S_OK);
3854 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3855 EXPECT_HR(hr, S_OK);
3857 V_VT(&dest) = VT_EMPTY;
3858 hr = IMXWriter_get_output(writer, &dest);
3859 EXPECT_HR(hr, S_OK);
3860 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3861 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3862 VariantClear(&dest);
3864 hr = ISAXContentHandler_endDocument(content);
3865 EXPECT_HR(hr, S_OK);
3866 IMXWriter_flush(writer);
3868 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3869 EXPECT_HR(hr, S_OK);
3870 V_VT(&dest) = VT_EMPTY;
3871 hr = IMXWriter_get_output(writer, &dest);
3872 EXPECT_HR(hr, S_OK);
3873 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3874 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3875 VariantClear(&dest);
3877 V_VT(&dest) = VT_EMPTY;
3878 hr = IMXWriter_put_output(writer, dest);
3879 EXPECT_HR(hr, S_OK);
3881 /* length -1 */
3882 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3883 EXPECT_HR(hr, S_OK);
3884 V_VT(&dest) = VT_EMPTY;
3885 hr = IMXWriter_get_output(writer, &dest);
3886 EXPECT_HR(hr, S_OK);
3887 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3888 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3889 VariantClear(&dest);
3891 ISAXContentHandler_Release(content);
3892 IMXWriter_Release(writer);
3893 free_bstrs();
3896 struct writer_characters_t {
3897 const GUID *clsid;
3898 const char *data;
3899 const char *output;
3902 static const struct writer_characters_t writer_characters[] = {
3903 { &CLSID_MXXMLWriter, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3904 { &CLSID_MXXMLWriter30, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3905 { &CLSID_MXXMLWriter40, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3906 { &CLSID_MXXMLWriter60, "< > & \" \'", "&lt; &gt; &amp; \" \'" },
3907 { NULL }
3910 static void test_mxwriter_characters(void)
3912 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3913 const struct writer_characters_t *table = writer_characters;
3914 ISAXContentHandler *content;
3915 IMXWriter *writer;
3916 VARIANT dest;
3917 HRESULT hr;
3918 int i = 0;
3920 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3921 &IID_IMXWriter, (void**)&writer);
3922 EXPECT_HR(hr, S_OK);
3924 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3925 EXPECT_HR(hr, S_OK);
3927 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3928 EXPECT_HR(hr, S_OK);
3930 hr = ISAXContentHandler_startDocument(content);
3931 EXPECT_HR(hr, S_OK);
3933 hr = ISAXContentHandler_characters(content, NULL, 0);
3934 EXPECT_HR(hr, E_INVALIDARG);
3936 hr = ISAXContentHandler_characters(content, chardataW, 0);
3937 EXPECT_HR(hr, S_OK);
3939 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3940 EXPECT_HR(hr, S_OK);
3942 V_VT(&dest) = VT_EMPTY;
3943 hr = IMXWriter_get_output(writer, &dest);
3944 EXPECT_HR(hr, S_OK);
3945 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3946 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3947 VariantClear(&dest);
3949 hr = ISAXContentHandler_endDocument(content);
3950 EXPECT_HR(hr, S_OK);
3952 ISAXContentHandler_Release(content);
3953 IMXWriter_Release(writer);
3955 /* try empty characters data to see if element is closed */
3956 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3957 &IID_IMXWriter, (void**)&writer);
3958 EXPECT_HR(hr, S_OK);
3960 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3961 EXPECT_HR(hr, S_OK);
3963 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3964 EXPECT_HR(hr, S_OK);
3966 hr = ISAXContentHandler_startDocument(content);
3967 EXPECT_HR(hr, S_OK);
3969 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3970 EXPECT_HR(hr, S_OK);
3972 hr = ISAXContentHandler_characters(content, chardataW, 0);
3973 EXPECT_HR(hr, S_OK);
3975 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3976 EXPECT_HR(hr, S_OK);
3978 V_VT(&dest) = VT_EMPTY;
3979 hr = IMXWriter_get_output(writer, &dest);
3980 EXPECT_HR(hr, S_OK);
3981 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3982 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3983 VariantClear(&dest);
3985 ISAXContentHandler_Release(content);
3986 IMXWriter_Release(writer);
3988 /* batch tests */
3989 while (table->clsid)
3991 ISAXContentHandler *content;
3992 IMXWriter *writer;
3993 VARIANT dest;
3994 HRESULT hr;
3996 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3998 table++;
3999 i++;
4000 continue;
4003 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4004 &IID_IMXWriter, (void**)&writer);
4005 EXPECT_HR(hr, S_OK);
4007 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4008 EXPECT_HR(hr, S_OK);
4010 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4011 EXPECT_HR(hr, S_OK);
4013 hr = ISAXContentHandler_startDocument(content);
4014 EXPECT_HR(hr, S_OK);
4016 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4017 EXPECT_HR(hr, S_OK);
4019 /* test output */
4020 if (hr == S_OK)
4022 V_VT(&dest) = VT_EMPTY;
4023 hr = IMXWriter_get_output(writer, &dest);
4024 EXPECT_HR(hr, S_OK);
4025 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4026 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
4027 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
4028 VariantClear(&dest);
4031 /* with disabled escaping */
4032 V_VT(&dest) = VT_EMPTY;
4033 hr = IMXWriter_put_output(writer, dest);
4034 EXPECT_HR(hr, S_OK);
4036 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
4037 EXPECT_HR(hr, S_OK);
4039 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
4040 EXPECT_HR(hr, S_OK);
4042 /* test output */
4043 if (hr == S_OK)
4045 V_VT(&dest) = VT_EMPTY;
4046 hr = IMXWriter_get_output(writer, &dest);
4047 EXPECT_HR(hr, S_OK);
4048 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4049 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
4050 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
4051 VariantClear(&dest);
4054 ISAXContentHandler_Release(content);
4055 IMXWriter_Release(writer);
4057 table++;
4058 i++;
4061 free_bstrs();
4064 static const mxwriter_stream_test mxwriter_stream_tests[] = {
4066 VARIANT_TRUE,"UTF-16",
4068 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4069 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4070 {TRUE}
4074 VARIANT_FALSE,"UTF-16",
4076 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4077 {TRUE}
4081 VARIANT_TRUE,"UTF-8",
4083 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
4084 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4085 * and the writer is released.
4087 {FALSE,NULL,0},
4088 {TRUE}
4092 VARIANT_TRUE,"utf-8",
4094 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
4095 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
4096 * and the writer is released.
4098 {FALSE,NULL,0},
4099 {TRUE}
4103 VARIANT_TRUE,"UTF-16",
4105 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
4106 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4107 {TRUE}
4111 VARIANT_TRUE,"UTF-16",
4113 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
4114 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
4115 {TRUE}
4120 static void test_mxwriter_stream(void)
4122 IMXWriter *writer;
4123 ISAXContentHandler *content;
4124 HRESULT hr;
4125 VARIANT dest;
4126 IStream *stream;
4127 LARGE_INTEGER pos;
4128 ULARGE_INTEGER pos2;
4129 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
4131 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
4132 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
4134 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4135 &IID_IMXWriter, (void**)&writer);
4136 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4138 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4139 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4141 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
4142 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
4144 V_VT(&dest) = VT_UNKNOWN;
4145 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
4146 hr = IMXWriter_put_output(writer, dest);
4147 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
4148 VariantClear(&dest);
4150 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
4151 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
4153 current_write_test = test->expected_writes;
4155 hr = ISAXContentHandler_startDocument(content);
4156 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4158 hr = ISAXContentHandler_endDocument(content);
4159 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4161 ISAXContentHandler_Release(content);
4162 IMXWriter_Release(writer);
4164 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
4165 (int)(current_write_test-test->expected_writes), current_stream_test_index);
4168 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4169 &IID_IMXWriter, (void**)&writer);
4170 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4172 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4173 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
4175 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4176 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4178 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4179 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
4181 V_VT(&dest) = VT_UNKNOWN;
4182 V_UNKNOWN(&dest) = (IUnknown*)stream;
4183 hr = IMXWriter_put_output(writer, dest);
4184 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4186 hr = ISAXContentHandler_startDocument(content);
4187 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4189 /* Setting output of the mxwriter causes the current output to be flushed,
4190 * and the writer to start over.
4192 V_VT(&dest) = VT_EMPTY;
4193 hr = IMXWriter_put_output(writer, dest);
4194 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4196 pos.QuadPart = 0;
4197 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4198 ok(hr == S_OK, "Seek failed: %08x\n", hr);
4199 ok(pos2.QuadPart != 0, "expected stream position moved\n");
4201 hr = ISAXContentHandler_startDocument(content);
4202 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4204 hr = ISAXContentHandler_endDocument(content);
4205 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
4207 V_VT(&dest) = VT_EMPTY;
4208 hr = IMXWriter_get_output(writer, &dest);
4209 ok(hr == S_OK, "get_output failed: %08x\n", hr);
4210 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4211 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4212 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4213 VariantClear(&dest);
4215 /* test when BOM is written to output stream */
4216 V_VT(&dest) = VT_EMPTY;
4217 hr = IMXWriter_put_output(writer, dest);
4218 EXPECT_HR(hr, S_OK);
4220 pos.QuadPart = 0;
4221 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
4222 EXPECT_HR(hr, S_OK);
4224 V_VT(&dest) = VT_UNKNOWN;
4225 V_UNKNOWN(&dest) = (IUnknown*)stream;
4226 hr = IMXWriter_put_output(writer, dest);
4227 EXPECT_HR(hr, S_OK);
4229 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
4230 EXPECT_HR(hr, S_OK);
4232 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4233 EXPECT_HR(hr, S_OK);
4235 hr = ISAXContentHandler_startDocument(content);
4236 EXPECT_HR(hr, S_OK);
4238 pos.QuadPart = 0;
4239 pos2.QuadPart = 0;
4240 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4241 EXPECT_HR(hr, S_OK);
4242 ok(pos2.QuadPart == 2, "got wrong position\n");
4244 IStream_Release(stream);
4245 ISAXContentHandler_Release(content);
4246 IMXWriter_Release(writer);
4248 free_bstrs();
4251 static const char *encoding_names[] = {
4252 "iso-8859-1",
4253 "iso-8859-2",
4254 "iso-8859-3",
4255 "iso-8859-4",
4256 "iso-8859-5",
4257 "iso-8859-7",
4258 "iso-8859-9",
4259 "iso-8859-13",
4260 "iso-8859-15",
4261 NULL
4264 static void test_mxwriter_encoding(void)
4266 ISAXContentHandler *content;
4267 IMXWriter *writer;
4268 IStream *stream;
4269 const char *enc;
4270 VARIANT dest;
4271 HRESULT hr;
4272 HGLOBAL g;
4273 char *ptr;
4274 BSTR s;
4275 int i;
4277 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4278 &IID_IMXWriter, (void**)&writer);
4279 EXPECT_HR(hr, S_OK);
4281 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4282 EXPECT_HR(hr, S_OK);
4284 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4285 EXPECT_HR(hr, S_OK);
4287 hr = ISAXContentHandler_startDocument(content);
4288 EXPECT_HR(hr, S_OK);
4290 hr = ISAXContentHandler_endDocument(content);
4291 EXPECT_HR(hr, S_OK);
4293 /* The content is always re-encoded to UTF-16 when the output is
4294 * retrieved as a BSTR.
4296 V_VT(&dest) = VT_EMPTY;
4297 hr = IMXWriter_get_output(writer, &dest);
4298 EXPECT_HR(hr, S_OK);
4299 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4300 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4301 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4302 VariantClear(&dest);
4304 /* switch encoding when something is written already */
4305 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4306 EXPECT_HR(hr, S_OK);
4308 V_VT(&dest) = VT_UNKNOWN;
4309 V_UNKNOWN(&dest) = (IUnknown*)stream;
4310 hr = IMXWriter_put_output(writer, dest);
4311 EXPECT_HR(hr, S_OK);
4313 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4314 EXPECT_HR(hr, S_OK);
4316 /* write empty element */
4317 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
4318 EXPECT_HR(hr, S_OK);
4320 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
4321 EXPECT_HR(hr, S_OK);
4323 /* switch */
4324 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4325 EXPECT_HR(hr, S_OK);
4327 hr = IMXWriter_flush(writer);
4328 EXPECT_HR(hr, S_OK);
4330 hr = GetHGlobalFromStream(stream, &g);
4331 EXPECT_HR(hr, S_OK);
4333 ptr = GlobalLock(g);
4334 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4335 GlobalUnlock(g);
4337 /* so output is unaffected, encoding name is stored however */
4338 hr = IMXWriter_get_encoding(writer, &s);
4339 EXPECT_HR(hr, S_OK);
4340 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4341 SysFreeString(s);
4343 IStream_Release(stream);
4345 i = 0;
4346 enc = encoding_names[i];
4347 while (enc)
4349 char expectedA[200];
4351 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4352 EXPECT_HR(hr, S_OK);
4354 V_VT(&dest) = VT_UNKNOWN;
4355 V_UNKNOWN(&dest) = (IUnknown*)stream;
4356 hr = IMXWriter_put_output(writer, dest);
4357 EXPECT_HR(hr, S_OK);
4359 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4360 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4361 "%s: encoding not accepted\n", enc);
4362 if (hr != S_OK)
4364 enc = encoding_names[++i];
4365 IStream_Release(stream);
4366 continue;
4369 hr = ISAXContentHandler_startDocument(content);
4370 EXPECT_HR(hr, S_OK);
4372 hr = ISAXContentHandler_endDocument(content);
4373 EXPECT_HR(hr, S_OK);
4375 hr = IMXWriter_flush(writer);
4376 EXPECT_HR(hr, S_OK);
4378 /* prepare expected string */
4379 *expectedA = 0;
4380 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4381 strcat(expectedA, enc);
4382 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4384 hr = GetHGlobalFromStream(stream, &g);
4385 EXPECT_HR(hr, S_OK);
4387 ptr = GlobalLock(g);
4388 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4389 GlobalUnlock(g);
4391 V_VT(&dest) = VT_EMPTY;
4392 hr = IMXWriter_put_output(writer, dest);
4393 EXPECT_HR(hr, S_OK);
4395 IStream_Release(stream);
4397 enc = encoding_names[++i];
4400 ISAXContentHandler_Release(content);
4401 IMXWriter_Release(writer);
4403 free_bstrs();
4406 static void test_obj_dispex(IUnknown *obj)
4408 static const WCHAR testW[] = {'t','e','s','t','p','r','o','p',0};
4409 static const WCHAR starW[] = {'*',0};
4410 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4411 IDispatchEx *dispex;
4412 IUnknown *unk;
4413 DWORD props;
4414 UINT ticnt;
4415 HRESULT hr;
4416 BSTR name;
4417 DISPID did;
4419 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4420 EXPECT_HR(hr, S_OK);
4421 if (FAILED(hr)) return;
4423 ticnt = 0;
4424 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4425 EXPECT_HR(hr, S_OK);
4426 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4428 name = SysAllocString(starW);
4429 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4430 EXPECT_HR(hr, E_NOTIMPL);
4431 SysFreeString(name);
4433 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4434 EXPECT_HR(hr, E_NOTIMPL);
4436 props = 0;
4437 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4438 EXPECT_HR(hr, E_NOTIMPL);
4439 ok(props == 0, "expected 0 got %d\n", props);
4441 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4442 EXPECT_HR(hr, E_NOTIMPL);
4443 if (SUCCEEDED(hr)) SysFreeString(name);
4445 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4446 EXPECT_HR(hr, E_NOTIMPL);
4448 unk = (IUnknown*)0xdeadbeef;
4449 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4450 EXPECT_HR(hr, E_NOTIMPL);
4451 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk);
4453 name = SysAllocString(testW);
4454 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did);
4455 ok(hr == DISP_E_UNKNOWNNAME, "got 0x%08x\n", hr);
4456 SysFreeString(name);
4458 IDispatchEx_Release(dispex);
4461 static void test_saxreader_dispex(void)
4463 IVBSAXXMLReader *vbreader;
4464 ISAXXMLReader *reader;
4465 DISPPARAMS dispparams;
4466 DISPID dispid;
4467 IUnknown *unk;
4468 VARIANT arg;
4469 HRESULT hr;
4471 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4472 &IID_ISAXXMLReader, (void**)&reader);
4473 EXPECT_HR(hr, S_OK);
4475 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4476 EXPECT_HR(hr, S_OK);
4477 test_obj_dispex(unk);
4478 IUnknown_Release(unk);
4480 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4481 EXPECT_HR(hr, S_OK);
4482 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4483 EXPECT_HR(hr, S_OK);
4484 test_obj_dispex(unk);
4485 IUnknown_Release(unk);
4487 dispid = DISPID_PROPERTYPUT;
4488 dispparams.cArgs = 1;
4489 dispparams.cNamedArgs = 1;
4490 dispparams.rgdispidNamedArgs = &dispid;
4491 dispparams.rgvarg = &arg;
4493 V_VT(&arg) = VT_DISPATCH;
4494 V_DISPATCH(&arg) = NULL;
4496 /* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */
4497 hr = IVBSAXXMLReader_Invoke(vbreader,
4498 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4499 &IID_NULL,
4501 DISPATCH_PROPERTYPUT,
4502 &dispparams,
4503 NULL,
4504 NULL,
4505 NULL);
4506 ok(hr == S_OK, "got 0x%08x\n", hr);
4508 hr = IVBSAXXMLReader_Invoke(vbreader,
4509 DISPID_SAX_XMLREADER_CONTENTHANDLER,
4510 &IID_NULL,
4512 DISPATCH_PROPERTYPUTREF,
4513 &dispparams,
4514 NULL,
4515 NULL,
4516 NULL);
4517 ok(hr == S_OK, "got 0x%08x\n", hr);
4519 IVBSAXXMLReader_Release(vbreader);
4520 ISAXXMLReader_Release(reader);
4522 if (is_clsid_supported(&CLSID_SAXXMLReader60, reader_support_data))
4524 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4525 ok(hr == S_OK, "got 0x%08x\n", hr);
4526 test_obj_dispex(unk);
4527 IUnknown_Release(unk);
4531 static void test_mxwriter_dispex(void)
4533 IDispatchEx *dispex;
4534 IMXWriter *writer;
4535 IUnknown *unk;
4536 HRESULT hr;
4538 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4539 &IID_IMXWriter, (void**)&writer);
4540 EXPECT_HR(hr, S_OK);
4542 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4543 EXPECT_HR(hr, S_OK);
4544 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4545 test_obj_dispex(unk);
4546 IUnknown_Release(unk);
4547 IDispatchEx_Release(dispex);
4548 IMXWriter_Release(writer);
4550 if (is_clsid_supported(&CLSID_MXXMLWriter60, mxwriter_support_data))
4552 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk);
4553 ok(hr == S_OK, "got 0x%08x\n", hr);
4554 test_obj_dispex(unk);
4555 IUnknown_Release(unk);
4559 static void test_mxwriter_comment(void)
4561 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4562 IVBSAXLexicalHandler *vblexical;
4563 ISAXContentHandler *content;
4564 ISAXLexicalHandler *lexical;
4565 IMXWriter *writer;
4566 VARIANT dest;
4567 HRESULT hr;
4569 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4570 &IID_IMXWriter, (void**)&writer);
4571 EXPECT_HR(hr, S_OK);
4573 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4574 EXPECT_HR(hr, S_OK);
4576 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4577 EXPECT_HR(hr, S_OK);
4579 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4580 EXPECT_HR(hr, S_OK);
4582 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4583 EXPECT_HR(hr, S_OK);
4585 hr = ISAXContentHandler_startDocument(content);
4586 EXPECT_HR(hr, S_OK);
4588 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4589 EXPECT_HR(hr, E_INVALIDARG);
4591 hr = IVBSAXLexicalHandler_comment(vblexical, NULL);
4592 EXPECT_HR(hr, E_POINTER);
4594 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4595 EXPECT_HR(hr, S_OK);
4597 V_VT(&dest) = VT_EMPTY;
4598 hr = IMXWriter_get_output(writer, &dest);
4599 EXPECT_HR(hr, S_OK);
4600 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4601 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4602 VariantClear(&dest);
4604 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4605 EXPECT_HR(hr, S_OK);
4607 V_VT(&dest) = VT_EMPTY;
4608 hr = IMXWriter_get_output(writer, &dest);
4609 EXPECT_HR(hr, S_OK);
4610 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4611 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4612 VariantClear(&dest);
4614 ISAXContentHandler_Release(content);
4615 ISAXLexicalHandler_Release(lexical);
4616 IVBSAXLexicalHandler_Release(vblexical);
4617 IMXWriter_Release(writer);
4618 free_bstrs();
4621 static void test_mxwriter_cdata(void)
4623 IVBSAXLexicalHandler *vblexical;
4624 ISAXContentHandler *content;
4625 ISAXLexicalHandler *lexical;
4626 IMXWriter *writer;
4627 VARIANT dest;
4628 HRESULT hr;
4630 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4631 &IID_IMXWriter, (void**)&writer);
4632 EXPECT_HR(hr, S_OK);
4634 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4635 EXPECT_HR(hr, S_OK);
4637 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4638 EXPECT_HR(hr, S_OK);
4640 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4641 EXPECT_HR(hr, S_OK);
4643 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4644 EXPECT_HR(hr, S_OK);
4646 hr = ISAXContentHandler_startDocument(content);
4647 EXPECT_HR(hr, S_OK);
4649 hr = ISAXLexicalHandler_startCDATA(lexical);
4650 EXPECT_HR(hr, S_OK);
4652 V_VT(&dest) = VT_EMPTY;
4653 hr = IMXWriter_get_output(writer, &dest);
4654 EXPECT_HR(hr, S_OK);
4655 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4656 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4657 VariantClear(&dest);
4659 hr = IVBSAXLexicalHandler_startCDATA(vblexical);
4660 EXPECT_HR(hr, S_OK);
4662 /* all these are escaped for text nodes */
4663 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4664 EXPECT_HR(hr, S_OK);
4666 hr = ISAXLexicalHandler_endCDATA(lexical);
4667 EXPECT_HR(hr, S_OK);
4669 V_VT(&dest) = VT_EMPTY;
4670 hr = IMXWriter_get_output(writer, &dest);
4671 EXPECT_HR(hr, S_OK);
4672 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4673 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4674 VariantClear(&dest);
4676 ISAXContentHandler_Release(content);
4677 ISAXLexicalHandler_Release(lexical);
4678 IVBSAXLexicalHandler_Release(vblexical);
4679 IMXWriter_Release(writer);
4680 free_bstrs();
4683 static void test_mxwriter_pi(void)
4685 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4686 static const WCHAR dataW[] = {'d','a','t','a',0};
4687 ISAXContentHandler *content;
4688 IMXWriter *writer;
4689 VARIANT dest;
4690 HRESULT hr;
4692 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4693 &IID_IMXWriter, (void**)&writer);
4694 EXPECT_HR(hr, S_OK);
4696 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4697 EXPECT_HR(hr, S_OK);
4699 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4700 EXPECT_HR(hr, E_INVALIDARG);
4702 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4703 EXPECT_HR(hr, S_OK);
4705 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4706 EXPECT_HR(hr, S_OK);
4708 V_VT(&dest) = VT_EMPTY;
4709 hr = IMXWriter_get_output(writer, &dest);
4710 EXPECT_HR(hr, S_OK);
4711 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4712 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4713 VariantClear(&dest);
4715 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4716 EXPECT_HR(hr, S_OK);
4718 V_VT(&dest) = VT_EMPTY;
4719 hr = IMXWriter_get_output(writer, &dest);
4720 EXPECT_HR(hr, S_OK);
4721 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4722 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)));
4723 VariantClear(&dest);
4725 V_VT(&dest) = VT_EMPTY;
4726 hr = IMXWriter_put_output(writer, dest);
4727 EXPECT_HR(hr, S_OK);
4729 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4730 EXPECT_HR(hr, S_OK);
4732 V_VT(&dest) = VT_EMPTY;
4733 hr = IMXWriter_get_output(writer, &dest);
4734 EXPECT_HR(hr, S_OK);
4735 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4736 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4737 VariantClear(&dest);
4740 ISAXContentHandler_Release(content);
4741 IMXWriter_Release(writer);
4744 static void test_mxwriter_ignorablespaces(void)
4746 static const WCHAR dataW[] = {'d','a','t','a',0};
4747 ISAXContentHandler *content;
4748 IMXWriter *writer;
4749 VARIANT dest;
4750 HRESULT hr;
4752 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4753 &IID_IMXWriter, (void**)&writer);
4754 EXPECT_HR(hr, S_OK);
4756 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4757 EXPECT_HR(hr, S_OK);
4759 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4760 EXPECT_HR(hr, E_INVALIDARG);
4762 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4763 EXPECT_HR(hr, S_OK);
4765 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4766 EXPECT_HR(hr, S_OK);
4768 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4769 EXPECT_HR(hr, S_OK);
4771 V_VT(&dest) = VT_EMPTY;
4772 hr = IMXWriter_get_output(writer, &dest);
4773 EXPECT_HR(hr, S_OK);
4774 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4775 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4776 VariantClear(&dest);
4778 ISAXContentHandler_Release(content);
4779 IMXWriter_Release(writer);
4782 static void test_mxwriter_dtd(void)
4784 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4785 static const WCHAR nameW[] = {'n','a','m','e'};
4786 static const WCHAR pubW[] = {'p','u','b'};
4787 static const WCHAR sysW[] = {'s','y','s'};
4788 IVBSAXLexicalHandler *vblexical;
4789 ISAXContentHandler *content;
4790 ISAXLexicalHandler *lexical;
4791 IVBSAXDeclHandler *vbdecl;
4792 ISAXDeclHandler *decl;
4793 IMXWriter *writer;
4794 VARIANT dest;
4795 HRESULT hr;
4797 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4798 &IID_IMXWriter, (void**)&writer);
4799 EXPECT_HR(hr, S_OK);
4801 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4802 EXPECT_HR(hr, S_OK);
4804 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4805 EXPECT_HR(hr, S_OK);
4807 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4808 EXPECT_HR(hr, S_OK);
4810 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl);
4811 EXPECT_HR(hr, S_OK);
4813 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
4814 EXPECT_HR(hr, S_OK);
4816 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4817 EXPECT_HR(hr, S_OK);
4819 hr = ISAXContentHandler_startDocument(content);
4820 EXPECT_HR(hr, S_OK);
4822 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4823 EXPECT_HR(hr, E_INVALIDARG);
4825 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL);
4826 EXPECT_HR(hr, E_POINTER);
4828 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4829 EXPECT_HR(hr, E_INVALIDARG);
4831 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4832 EXPECT_HR(hr, E_INVALIDARG);
4834 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4835 EXPECT_HR(hr, E_INVALIDARG);
4837 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4838 EXPECT_HR(hr, S_OK);
4840 V_VT(&dest) = VT_EMPTY;
4841 hr = IMXWriter_get_output(writer, &dest);
4842 EXPECT_HR(hr, S_OK);
4843 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4844 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4845 VariantClear(&dest);
4847 /* system id is required if public is present */
4848 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4849 EXPECT_HR(hr, E_INVALIDARG);
4851 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4852 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4853 EXPECT_HR(hr, S_OK);
4855 V_VT(&dest) = VT_EMPTY;
4856 hr = IMXWriter_get_output(writer, &dest);
4857 EXPECT_HR(hr, S_OK);
4858 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4859 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4860 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4861 VariantClear(&dest);
4863 hr = ISAXLexicalHandler_endDTD(lexical);
4864 EXPECT_HR(hr, S_OK);
4866 hr = IVBSAXLexicalHandler_endDTD(vblexical);
4867 EXPECT_HR(hr, S_OK);
4869 V_VT(&dest) = VT_EMPTY;
4870 hr = IMXWriter_get_output(writer, &dest);
4871 EXPECT_HR(hr, S_OK);
4872 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4873 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4874 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4875 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4876 VariantClear(&dest);
4878 /* element declaration */
4879 V_VT(&dest) = VT_EMPTY;
4880 hr = IMXWriter_put_output(writer, dest);
4881 EXPECT_HR(hr, S_OK);
4883 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4884 EXPECT_HR(hr, E_INVALIDARG);
4886 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL);
4887 EXPECT_HR(hr, E_POINTER);
4889 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4890 EXPECT_HR(hr, E_INVALIDARG);
4892 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4893 EXPECT_HR(hr, S_OK);
4895 V_VT(&dest) = VT_EMPTY;
4896 hr = IMXWriter_get_output(writer, &dest);
4897 EXPECT_HR(hr, S_OK);
4898 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4899 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4900 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4901 VariantClear(&dest);
4903 V_VT(&dest) = VT_EMPTY;
4904 hr = IMXWriter_put_output(writer, dest);
4905 EXPECT_HR(hr, S_OK);
4907 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4908 EXPECT_HR(hr, S_OK);
4910 V_VT(&dest) = VT_EMPTY;
4911 hr = IMXWriter_get_output(writer, &dest);
4912 EXPECT_HR(hr, S_OK);
4913 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4914 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4915 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4916 VariantClear(&dest);
4918 /* attribute declaration */
4919 V_VT(&dest) = VT_EMPTY;
4920 hr = IMXWriter_put_output(writer, dest);
4921 EXPECT_HR(hr, S_OK);
4923 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4924 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4925 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4926 EXPECT_HR(hr, S_OK);
4928 V_VT(&dest) = VT_EMPTY;
4929 hr = IMXWriter_get_output(writer, &dest);
4930 EXPECT_HR(hr, S_OK);
4931 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4932 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4933 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4934 VariantClear(&dest);
4936 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4937 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4938 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4939 EXPECT_HR(hr, S_OK);
4941 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4942 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4943 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4944 EXPECT_HR(hr, S_OK);
4946 V_VT(&dest) = VT_EMPTY;
4947 hr = IMXWriter_get_output(writer, &dest);
4948 EXPECT_HR(hr, S_OK);
4949 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4950 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4951 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4952 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4953 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4954 VariantClear(&dest);
4956 /* internal entities */
4957 V_VT(&dest) = VT_EMPTY;
4958 hr = IMXWriter_put_output(writer, dest);
4959 EXPECT_HR(hr, S_OK);
4961 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4962 EXPECT_HR(hr, E_INVALIDARG);
4964 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL);
4965 EXPECT_HR(hr, E_POINTER);
4967 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4968 EXPECT_HR(hr, E_INVALIDARG);
4970 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4971 EXPECT_HR(hr, S_OK);
4973 V_VT(&dest) = VT_EMPTY;
4974 hr = IMXWriter_get_output(writer, &dest);
4975 EXPECT_HR(hr, S_OK);
4976 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4977 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4978 VariantClear(&dest);
4980 /* external entities */
4981 V_VT(&dest) = VT_EMPTY;
4982 hr = IMXWriter_put_output(writer, dest);
4983 ok(hr == S_OK, "got 0x%08x\n", hr);
4985 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0);
4986 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4988 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL);
4989 ok(hr == E_POINTER, "got 0x%08x\n", hr);
4991 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0);
4992 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4994 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"),
4995 _bstr_("sysid"), strlen("sysid"));
4996 ok(hr == S_OK, "got 0x%08x\n", hr);
4998 V_VT(&dest) = VT_EMPTY;
4999 hr = IMXWriter_get_output(writer, &dest);
5000 ok(hr == S_OK, "got 0x%08x\n", hr);
5001 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5002 ok(!lstrcmpW(_bstr_("<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5003 VariantClear(&dest);
5005 ISAXContentHandler_Release(content);
5006 ISAXLexicalHandler_Release(lexical);
5007 IVBSAXLexicalHandler_Release(vblexical);
5008 IVBSAXDeclHandler_Release(vbdecl);
5009 ISAXDeclHandler_Release(decl);
5010 IMXWriter_Release(writer);
5011 free_bstrs();
5014 typedef struct {
5015 const CLSID *clsid;
5016 const char *uri;
5017 const char *local;
5018 const char *qname;
5019 const char *type;
5020 const char *value;
5021 HRESULT hr;
5022 } addattribute_test_t;
5024 static const addattribute_test_t addattribute_data[] = {
5025 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5026 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5027 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
5028 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
5030 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5031 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5032 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5033 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
5035 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5036 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5037 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
5038 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
5040 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
5041 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
5042 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
5043 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
5045 { NULL }
5048 static void test_mxattr_addAttribute(void)
5050 const addattribute_test_t *table = addattribute_data;
5051 int i = 0;
5053 while (table->clsid)
5055 ISAXAttributes *saxattr;
5056 IMXAttributes *mxattr;
5057 const WCHAR *value;
5058 int len, index;
5059 HRESULT hr;
5061 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5063 table++;
5064 i++;
5065 continue;
5068 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5069 &IID_IMXAttributes, (void**)&mxattr);
5070 EXPECT_HR(hr, S_OK);
5072 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5073 EXPECT_HR(hr, S_OK);
5075 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5076 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5077 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5079 hr = ISAXAttributes_getLength(saxattr, NULL);
5080 EXPECT_HR(hr, E_POINTER);
5083 len = -1;
5084 hr = ISAXAttributes_getLength(saxattr, &len);
5085 EXPECT_HR(hr, S_OK);
5086 ok(len == 0, "got %d\n", len);
5088 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5089 EXPECT_HR(hr, E_INVALIDARG);
5091 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5092 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5094 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5095 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5097 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5098 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5100 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5101 EXPECT_HR(hr, E_INVALIDARG);
5103 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5104 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5106 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5107 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5109 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5110 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5112 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
5113 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
5114 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
5116 if (hr == S_OK)
5118 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
5119 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5120 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5122 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
5123 EXPECT_HR(hr, E_POINTER);
5125 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
5126 EXPECT_HR(hr, E_POINTER);
5128 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
5129 EXPECT_HR(hr, E_POINTER);
5131 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
5132 EXPECT_HR(hr, E_POINTER);
5134 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
5135 EXPECT_HR(hr, E_POINTER);
5137 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
5138 EXPECT_HR(hr, E_POINTER);
5141 len = -1;
5142 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
5143 EXPECT_HR(hr, S_OK);
5144 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5145 table->value);
5146 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5148 len = -1;
5149 value = (void*)0xdeadbeef;
5150 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
5151 EXPECT_HR(hr, S_OK);
5153 if (table->type)
5155 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5156 table->type);
5157 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
5159 else
5161 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
5162 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
5165 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
5166 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5167 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5169 EXPECT_HR(hr, E_POINTER);
5171 else
5172 EXPECT_HR(hr, E_INVALIDARG);
5174 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
5175 EXPECT_HR(hr, E_INVALIDARG);
5177 index = -1;
5178 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
5179 EXPECT_HR(hr, E_INVALIDARG);
5180 ok(index == -1, "%d: got wrong index %d\n", i, index);
5182 index = -1;
5183 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
5184 EXPECT_HR(hr, E_INVALIDARG);
5185 ok(index == -1, "%d: got wrong index %d\n", i, index);
5187 index = -1;
5188 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
5189 EXPECT_HR(hr, S_OK);
5190 ok(index == 0, "%d: got wrong index %d\n", i, index);
5192 index = -1;
5193 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
5194 EXPECT_HR(hr, E_INVALIDARG);
5195 ok(index == -1, "%d: got wrong index %d\n", i, index);
5197 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
5198 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
5200 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5201 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5203 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5204 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5206 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5207 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5209 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5210 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5212 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5213 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5215 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5216 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr);
5218 else
5220 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
5221 EXPECT_HR(hr, E_POINTER);
5223 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
5224 EXPECT_HR(hr, E_POINTER);
5226 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
5227 EXPECT_HR(hr, E_POINTER);
5229 /* versions 4 and 6 crash */
5230 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
5231 EXPECT_HR(hr, E_POINTER);
5233 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
5234 EXPECT_HR(hr, E_POINTER);
5236 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
5237 EXPECT_HR(hr, E_POINTER);
5239 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
5240 EXPECT_HR(hr, E_POINTER);
5242 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
5243 EXPECT_HR(hr, E_POINTER);
5245 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
5246 EXPECT_HR(hr, E_POINTER);
5248 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
5249 EXPECT_HR(hr, E_POINTER);
5251 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
5252 strlen(table->local), NULL, NULL);
5253 EXPECT_HR(hr, E_POINTER);
5256 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
5257 EXPECT_HR(hr, S_OK);
5258 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5259 table->value);
5260 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5262 if (table->uri) {
5263 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
5264 _bstr_(table->local), strlen(table->local), &value, &len);
5265 EXPECT_HR(hr, S_OK);
5266 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5267 table->value);
5268 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5272 len = -1;
5273 hr = ISAXAttributes_getLength(saxattr, &len);
5274 EXPECT_HR(hr, S_OK);
5275 if (table->hr == S_OK)
5276 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
5277 else
5278 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
5280 ISAXAttributes_Release(saxattr);
5281 IMXAttributes_Release(mxattr);
5283 table++;
5284 i++;
5287 free_bstrs();
5290 static void test_mxattr_clear(void)
5292 ISAXAttributes *saxattr;
5293 IMXAttributes *mxattr;
5294 const WCHAR *ptr;
5295 HRESULT hr;
5296 int len;
5298 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5299 &IID_IMXAttributes, (void**)&mxattr);
5300 EXPECT_HR(hr, S_OK);
5302 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5303 EXPECT_HR(hr, S_OK);
5305 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
5306 EXPECT_HR(hr, E_INVALIDARG);
5308 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5309 EXPECT_HR(hr, E_INVALIDARG);
5311 hr = IMXAttributes_clear(mxattr);
5312 EXPECT_HR(hr, S_OK);
5314 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
5315 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
5316 EXPECT_HR(hr, S_OK);
5318 len = -1;
5319 hr = ISAXAttributes_getLength(saxattr, &len);
5320 EXPECT_HR(hr, S_OK);
5321 ok(len == 1, "got %d\n", len);
5323 len = -1;
5324 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
5325 EXPECT_HR(hr, E_POINTER);
5326 ok(len == -1, "got %d\n", len);
5328 ptr = (void*)0xdeadbeef;
5329 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
5330 EXPECT_HR(hr, E_POINTER);
5331 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5333 len = 0;
5334 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5335 EXPECT_HR(hr, S_OK);
5336 ok(len == 5, "got %d\n", len);
5337 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
5339 hr = IMXAttributes_clear(mxattr);
5340 EXPECT_HR(hr, S_OK);
5342 len = -1;
5343 hr = ISAXAttributes_getLength(saxattr, &len);
5344 EXPECT_HR(hr, S_OK);
5345 ok(len == 0, "got %d\n", len);
5347 len = -1;
5348 ptr = (void*)0xdeadbeef;
5349 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5350 EXPECT_HR(hr, E_INVALIDARG);
5351 ok(len == -1, "got %d\n", len);
5352 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5354 IMXAttributes_Release(mxattr);
5355 ISAXAttributes_Release(saxattr);
5356 free_bstrs();
5359 static void test_mxattr_dispex(void)
5361 IMXAttributes *mxattr;
5362 IDispatchEx *dispex;
5363 IUnknown *unk;
5364 HRESULT hr;
5366 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5367 &IID_IMXAttributes, (void**)&mxattr);
5368 EXPECT_HR(hr, S_OK);
5370 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
5371 EXPECT_HR(hr, S_OK);
5372 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
5373 test_obj_dispex(unk);
5374 IUnknown_Release(unk);
5375 IDispatchEx_Release(dispex);
5377 IMXAttributes_Release(mxattr);
5380 static void test_mxattr_qi(void)
5382 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
5383 ISAXAttributes *saxattr;
5384 IMXAttributes *mxattr;
5385 HRESULT hr;
5387 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5388 &IID_IMXAttributes, (void**)&mxattr);
5389 EXPECT_HR(hr, S_OK);
5391 EXPECT_REF(mxattr, 1);
5392 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5393 EXPECT_HR(hr, S_OK);
5395 EXPECT_REF(mxattr, 2);
5396 EXPECT_REF(saxattr, 2);
5398 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
5399 EXPECT_HR(hr, S_OK);
5401 EXPECT_REF(vbsaxattr, 3);
5402 EXPECT_REF(mxattr, 3);
5403 EXPECT_REF(saxattr, 3);
5405 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
5406 EXPECT_HR(hr, S_OK);
5408 EXPECT_REF(vbsaxattr, 4);
5409 EXPECT_REF(mxattr, 4);
5410 EXPECT_REF(saxattr, 4);
5412 IMXAttributes_Release(mxattr);
5413 ISAXAttributes_Release(saxattr);
5414 IVBSAXAttributes_Release(vbsaxattr);
5415 IVBSAXAttributes_Release(vbsaxattr2);
5418 static struct msxmlsupported_data_t saxattr_support_data[] =
5420 { &CLSID_SAXAttributes, "SAXAttributes" },
5421 { &CLSID_SAXAttributes30, "SAXAttributes30" },
5422 { &CLSID_SAXAttributes40, "SAXAttributes40" },
5423 { &CLSID_SAXAttributes60, "SAXAttributes60" },
5424 { NULL }
5427 static void test_mxattr_localname(void)
5429 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
5430 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
5431 static const WCHAR uri1W[] = {'u','r','i','1',0};
5432 static const WCHAR uriW[] = {'u','r','i',0};
5434 const struct msxmlsupported_data_t *table = saxattr_support_data;
5436 while (table->clsid)
5438 ISAXAttributes *saxattr;
5439 IMXAttributes *mxattr;
5440 HRESULT hr;
5441 int index;
5443 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5445 table++;
5446 continue;
5449 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5450 &IID_IMXAttributes, (void**)&mxattr);
5451 EXPECT_HR(hr, S_OK);
5453 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5454 EXPECT_HR(hr, S_OK);
5456 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5457 EXPECT_HR(hr, E_INVALIDARG);
5459 /* add some ambiguos attribute names */
5460 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5461 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5462 EXPECT_HR(hr, S_OK);
5463 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5464 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5465 EXPECT_HR(hr, S_OK);
5467 index = -1;
5468 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5469 EXPECT_HR(hr, S_OK);
5470 ok(index == 0, "%s: got index %d\n", table->name, index);
5472 index = -1;
5473 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5474 EXPECT_HR(hr, E_INVALIDARG);
5475 ok(index == -1, "%s: got index %d\n", table->name, index);
5477 index = -1;
5478 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5479 EXPECT_HR(hr, E_INVALIDARG);
5480 ok(index == -1, "%s: got index %d\n", table->name, index);
5482 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5483 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5485 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5486 EXPECT_HR(hr, E_POINTER);
5488 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5489 EXPECT_HR(hr, E_POINTER);
5491 else
5493 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5494 EXPECT_HR(hr, E_INVALIDARG);
5496 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5497 EXPECT_HR(hr, E_INVALIDARG);
5500 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5501 EXPECT_HR(hr, E_INVALIDARG);
5503 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5504 EXPECT_HR(hr, E_INVALIDARG);
5506 table++;
5508 ISAXAttributes_Release(saxattr);
5509 IMXAttributes_Release(mxattr);
5510 free_bstrs();
5514 static void test_mxwriter_indent(void)
5516 ISAXContentHandler *content;
5517 IMXWriter *writer;
5518 VARIANT dest;
5519 HRESULT hr;
5521 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer);
5522 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5524 hr = IMXWriter_put_indent(writer, VARIANT_TRUE);
5525 ok(hr == S_OK, "got %08x\n", hr);
5527 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
5528 ok(hr == S_OK, "got %08x\n", hr);
5530 hr = ISAXContentHandler_startDocument(content);
5531 ok(hr == S_OK, "got %08x\n", hr);
5533 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
5534 ok(hr == S_OK, "got %08x\n", hr);
5536 hr = ISAXContentHandler_characters(content, _bstr_(""), 0);
5537 ok(hr == S_OK, "got %08x\n", hr);
5539 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL);
5540 ok(hr == S_OK, "got %08x\n", hr);
5542 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL);
5543 ok(hr == S_OK, "got %08x\n", hr);
5545 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1);
5546 ok(hr == S_OK, "got %08x\n", hr);
5548 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1);
5549 ok(hr == S_OK, "got %08x\n", hr);
5551 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1);
5552 ok(hr == S_OK, "got %08x\n", hr);
5554 hr = ISAXContentHandler_endDocument(content);
5555 ok(hr == S_OK, "got %08x\n", hr);
5557 V_VT(&dest) = VT_EMPTY;
5558 hr = IMXWriter_get_output(writer, &dest);
5559 ok(hr == S_OK, "got %08x\n", hr);
5560 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
5561 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)),
5562 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
5563 VariantClear(&dest);
5565 ISAXContentHandler_Release(content);
5566 IMXWriter_Release(writer);
5568 free_bstrs();
5571 START_TEST(saxreader)
5573 ISAXXMLReader *reader;
5574 HRESULT hr;
5576 hr = CoInitialize(NULL);
5577 ok(hr == S_OK, "failed to init com\n");
5579 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5580 &IID_ISAXXMLReader, (void**)&reader);
5582 if(FAILED(hr))
5584 skip("Failed to create SAXXMLReader instance\n");
5585 CoUninitialize();
5586 return;
5588 ISAXXMLReader_Release(reader);
5590 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5592 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5594 test_saxreader();
5595 test_saxreader_properties();
5596 test_saxreader_features();
5597 test_saxreader_encoding();
5598 test_saxreader_dispex();
5600 /* MXXMLWriter tests */
5601 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5602 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5604 test_mxwriter_handlers();
5605 test_mxwriter_startenddocument();
5606 test_mxwriter_startendelement();
5607 test_mxwriter_characters();
5608 test_mxwriter_comment();
5609 test_mxwriter_cdata();
5610 test_mxwriter_pi();
5611 test_mxwriter_ignorablespaces();
5612 test_mxwriter_dtd();
5613 test_mxwriter_properties();
5614 test_mxwriter_flush();
5615 test_mxwriter_stream();
5616 test_mxwriter_encoding();
5617 test_mxwriter_dispex();
5618 test_mxwriter_indent();
5620 else
5621 win_skip("MXXMLWriter not supported\n");
5623 /* SAXAttributes tests */
5624 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5625 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5627 test_mxattr_qi();
5628 test_mxattr_addAttribute();
5629 test_mxattr_clear();
5630 test_mxattr_localname();
5631 test_mxattr_dispex();
5633 else
5634 skip("SAXAttributes not supported\n");
5636 CoUninitialize();