msxml3/tests: Fix test crashes running old versions.
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blobb4d6f7f8c6113e8377c105945b2475082106c518
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 #define EXPECT_HR(hr,hr_exp) \
39 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
41 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
42 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
44 ULONG rc = IUnknown_AddRef(obj);
45 IUnknown_Release(obj);
46 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
49 static LONG get_refcount(void *iface)
51 IUnknown *unk = iface;
52 LONG ref;
54 ref = IUnknown_AddRef(unk);
55 IUnknown_Release(unk);
56 return ref-1;
59 struct msxmlsupported_data_t
61 const GUID *clsid;
62 const char *name;
63 BOOL supported;
66 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
68 while (table->clsid)
70 if (table->clsid == clsid) return table->supported;
71 table++;
73 return FALSE;
76 static BSTR alloc_str_from_narrow(const char *str)
78 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
79 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
80 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
81 return ret;
84 static BSTR alloced_bstrs[512];
85 static int alloced_bstrs_count;
87 static BSTR _bstr_(const char *str)
89 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
90 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
91 return alloced_bstrs[alloced_bstrs_count++];
94 static void free_bstrs(void)
96 int i;
97 for (i = 0; i < alloced_bstrs_count; i++)
98 SysFreeString(alloced_bstrs[i]);
99 alloced_bstrs_count = 0;
102 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, int todo, int *failcount)
104 int len, lenexp, cmp;
105 WCHAR buf[1024];
107 len = SysStringLen(str);
109 if (!expected) {
110 if (str && todo)
112 (*failcount)++;
113 todo_wine
114 ok_(file, line) (!str, "got %p, expected null str\n", str);
116 else
117 ok_(file, line) (!str, "got %p, expected null str\n", str);
119 if (len && todo)
121 (*failcount)++;
122 todo_wine
123 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
125 else
126 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
127 return;
130 lenexp = strlen(expected);
131 if (lenexp != len && todo)
133 (*failcount)++;
134 todo_wine
135 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
137 else
138 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
140 /* exit earlier on length mismatch */
141 if (lenexp != len) return;
143 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
145 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
146 if (cmp && todo)
148 (*failcount)++;
149 todo_wine
150 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
151 wine_dbgstr_wn(str, len), expected);
153 else
154 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
155 wine_dbgstr_wn(str, len), expected);
158 typedef enum _CH {
159 CH_ENDTEST,
160 CH_PUTDOCUMENTLOCATOR,
161 CH_STARTDOCUMENT,
162 CH_ENDDOCUMENT,
163 CH_STARTPREFIXMAPPING,
164 CH_ENDPREFIXMAPPING,
165 CH_STARTELEMENT,
166 CH_ENDELEMENT,
167 CH_CHARACTERS,
168 CH_IGNORABLEWHITESPACE,
169 CH_PROCESSINGINSTRUCTION,
170 CH_SKIPPEDENTITY,
171 EH_ERROR,
172 EH_FATALERROR,
173 EG_IGNORABLEWARNING,
174 EVENT_LAST
175 } CH;
177 static const char *event_names[EVENT_LAST] = {
178 "endtest",
179 "putDocumentLocator",
180 "startDocument",
181 "endDocument",
182 "startPrefixMapping",
183 "endPrefixMapping",
184 "startElement",
185 "endElement",
186 "characters",
187 "ignorableWhitespace",
188 "processingInstruction",
189 "skippedEntity",
190 "error",
191 "fatalError",
192 "ignorableWarning"
195 struct attribute_entry {
196 const char *uri;
197 const char *local;
198 const char *qname;
199 const char *value;
201 /* used for actual call data only, null for expected call data */
202 BSTR uriW;
203 BSTR localW;
204 BSTR qnameW;
205 BSTR valueW;
208 struct call_entry {
209 CH id;
210 int line;
211 int column;
212 HRESULT ret;
213 const char *arg1;
214 const char *arg2;
215 const char *arg3;
217 /* allocated once at startElement callback */
218 struct attribute_entry *attributes;
219 int attr_count;
221 /* used for actual call data only, null for expected call data */
222 BSTR arg1W;
223 BSTR arg2W;
224 BSTR arg3W;
227 struct call_sequence
229 int count;
230 int size;
231 struct call_entry *sequence;
234 #define CONTENT_HANDLER_INDEX 0
235 #define NUM_CALL_SEQUENCES 1
236 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
238 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
240 memset(call, 0, sizeof(*call));
241 ISAXLocator_getLineNumber(locator, &call->line);
242 ISAXLocator_getColumnNumber(locator, &call->column);
245 static void add_call(struct call_sequence **seq, int sequence_index,
246 const struct call_entry *call)
248 struct call_sequence *call_seq = seq[sequence_index];
250 if (!call_seq->sequence)
252 call_seq->size = 10;
253 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
254 call_seq->size * sizeof (struct call_entry));
257 if (call_seq->count == call_seq->size)
259 call_seq->size *= 2;
260 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
261 call_seq->sequence,
262 call_seq->size * sizeof (struct call_entry));
265 assert(call_seq->sequence);
267 call_seq->sequence[call_seq->count].id = call->id;
268 call_seq->sequence[call_seq->count].line = call->line;
269 call_seq->sequence[call_seq->count].column = call->column;
270 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
271 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
272 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
273 call_seq->sequence[call_seq->count].ret = call->ret;
274 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
275 call_seq->sequence[call_seq->count].attributes = call->attributes;
277 call_seq->count++;
280 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
282 int i;
284 struct call_sequence *call_seq = seg[sequence_index];
286 for (i = 0; i < call_seq->count; i++)
288 int j;
290 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
292 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
293 SysFreeString(call_seq->sequence[i].attributes[j].localW);
294 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
297 SysFreeString(call_seq->sequence[i].arg1W);
298 SysFreeString(call_seq->sequence[i].arg2W);
299 SysFreeString(call_seq->sequence[i].arg3W);
302 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
303 call_seq->sequence = NULL;
304 call_seq->count = call_seq->size = 0;
307 static inline void flush_sequences(struct call_sequence **seq, int n)
309 int i;
310 for (i = 0; i < n; i++)
311 flush_sequence(seq, i);
314 static const char *get_event_name(CH event)
316 return event_names[event];
319 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
320 int todo, const char *file, int line, int *failcount)
322 int i, lenexp = 0;
324 /* attribute count is not stored for expected data */
325 if (expected->attributes)
327 struct attribute_entry *ptr = expected->attributes;
328 while (ptr->uri) { lenexp++; ptr++; };
331 /* check count first and exit earlier */
332 if (actual->attr_count != lenexp && todo)
334 (*failcount)++;
335 todo_wine
336 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
337 context, get_event_name(actual->id), lenexp, actual->attr_count);
339 else
340 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
341 context, get_event_name(actual->id), lenexp, actual->attr_count);
343 if (actual->attr_count != lenexp) return;
345 /* now compare all attributes strings */
346 for (i = 0; i < actual->attr_count; i++)
348 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
349 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
350 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
351 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
355 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
356 const struct call_entry *expected, const char *context, int todo,
357 const char *file, int line)
359 struct call_sequence *call_seq = seq[sequence_index];
360 static const struct call_entry end_of_sequence = { CH_ENDTEST };
361 const struct call_entry *actual, *sequence;
362 int failcount = 0;
364 add_call(seq, sequence_index, &end_of_sequence);
366 sequence = call_seq->sequence;
367 actual = sequence;
369 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
371 if (expected->id == actual->id)
373 /* always test position data */
374 if (expected->line != actual->line && todo)
376 todo_wine
378 failcount++;
379 ok_(file, line) (FALSE,
380 "%s: in event %s expecting line %d got %d\n",
381 context, get_event_name(actual->id), expected->line, actual->line);
384 else
386 ok_(file, line) (expected->line == actual->line,
387 "%s: in event %s expecting line %d got %d\n",
388 context, get_event_name(actual->id), expected->line, actual->line);
391 if (expected->column != actual->column && todo)
393 todo_wine
395 failcount++;
396 ok_(file, line) (FALSE,
397 "%s: in event %s expecting column %d got %d\n",
398 context, get_event_name(actual->id), expected->column, actual->column);
401 else
403 ok_(file, line) (expected->column == actual->column,
404 "%s: in event %s expecting column %d got %d\n",
405 context, get_event_name(actual->id), expected->column, actual->column);
408 switch (actual->id)
410 case CH_PUTDOCUMENTLOCATOR:
411 case CH_STARTDOCUMENT:
412 case CH_ENDDOCUMENT:
413 break;
414 case CH_STARTPREFIXMAPPING:
415 /* prefix, uri */
416 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
417 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
418 break;
419 case CH_ENDPREFIXMAPPING:
420 /* prefix */
421 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
422 break;
423 case CH_STARTELEMENT:
424 /* compare attributes */
425 compare_attributes(actual, expected, context, todo, file, line, &failcount);
426 /* fallthrough */
427 case CH_ENDELEMENT:
428 /* uri, localname, qname */
429 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
430 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
431 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
432 break;
433 case CH_CHARACTERS:
434 case CH_IGNORABLEWHITESPACE:
435 /* char data */
436 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
437 break;
438 case CH_PROCESSINGINSTRUCTION:
439 /* target, data */
440 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
441 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
442 break;
443 case CH_SKIPPEDENTITY:
444 /* name */
445 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
446 break;
447 case EH_FATALERROR:
448 /* test return value only */
449 if (expected->ret != actual->ret && todo)
451 failcount++;
452 ok_(file, line) (FALSE,
453 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
454 context, get_event_name(actual->id), expected->ret, actual->ret);
456 else
457 ok_(file, line) (expected->ret == actual->ret,
458 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
459 context, get_event_name(actual->id), expected->ret, actual->ret);
460 break;
461 case EH_ERROR:
462 case EG_IGNORABLEWARNING:
463 default:
464 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
466 expected++;
467 actual++;
469 else if (todo)
471 failcount++;
472 todo_wine
474 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
475 context, get_event_name(expected->id), get_event_name(actual->id));
478 flush_sequence(seq, sequence_index);
479 return;
481 else
483 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
484 context, get_event_name(expected->id), get_event_name(actual->id));
485 expected++;
486 actual++;
490 if (todo)
492 todo_wine
494 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
496 failcount++;
497 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
498 context, get_event_name(expected->id), get_event_name(actual->id));
502 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
504 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
505 context, get_event_name(expected->id), get_event_name(actual->id));
508 if (todo && !failcount) /* succeeded yet marked todo */
510 todo_wine
512 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
516 flush_sequence(seq, sequence_index);
519 #define ok_sequence(seq, index, exp, contx, todo) \
520 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
522 static void init_call_sequences(struct call_sequence **seq, int n)
524 int i;
526 for (i = 0; i < n; i++)
527 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
530 static const WCHAR szSimpleXML[] = {
531 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
532 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
533 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
534 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
535 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
538 static const WCHAR carriage_ret_test[] = {
539 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
540 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
541 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
542 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
543 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
546 static const WCHAR szUtf16XML[] = {
547 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
548 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
549 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
552 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
554 static const CHAR szUtf8XML[] =
555 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
557 static const char utf8xml2[] =
558 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
560 static const CHAR testXML[] =
561 "<?xml version=\"1.0\" ?>\n"
562 "<BankAccount>\n"
563 " <Number>1234</Number>\n"
564 " <Name>Captain Ahab</Name>\n"
565 "</BankAccount>\n";
567 static const char test_attributes[] =
568 "<?xml version=\"1.0\" ?>\n"
569 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
570 "<node1 xmlns:p=\"test\" />"
571 "</document>\n";
573 static struct call_entry content_handler_test1[] = {
574 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
575 { CH_STARTDOCUMENT, 0, 0, S_OK },
576 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
577 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
578 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
579 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
580 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
581 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
582 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
583 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
584 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
585 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
586 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
587 { CH_ENDDOCUMENT, 0, 0, S_OK},
588 { CH_ENDTEST }
591 /* applies to versions 4 and 6 */
592 static struct call_entry content_handler_test1_alternate[] = {
593 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
594 { CH_STARTDOCUMENT, 1, 22, S_OK },
595 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
597 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
598 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
599 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
600 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
601 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
602 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
603 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
604 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
605 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
606 { CH_ENDDOCUMENT, 6, 0, S_OK },
607 { CH_ENDTEST }
610 static struct call_entry content_handler_test2[] = {
611 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
612 { CH_STARTDOCUMENT, 0, 0, S_OK },
613 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
614 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
615 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
616 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
617 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
618 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
619 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
620 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
621 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
622 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
623 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
624 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
625 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
626 { CH_ENDDOCUMENT, 0, 0, S_OK },
627 { CH_ENDTEST }
630 static struct call_entry content_handler_test2_alternate[] = {
631 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
632 { CH_STARTDOCUMENT, 1, 21, S_OK },
633 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
634 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
635 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
636 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
637 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
638 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
639 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
640 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
641 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
642 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
643 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
644 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
645 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
646 { CH_ENDDOCUMENT, 6, 0, S_OK },
647 { CH_ENDTEST }
650 static struct call_entry content_handler_testerror[] = {
651 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
652 { EH_FATALERROR, 0, 0, E_FAIL },
653 { CH_ENDTEST }
656 static struct call_entry content_handler_testerror_alternate[] = {
657 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
658 { EH_FATALERROR, 1, 0, E_FAIL },
659 { CH_ENDTEST }
662 static struct call_entry content_handler_test_callback_rets[] = {
663 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
664 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
665 { EH_FATALERROR, 0, 0, S_FALSE },
666 { CH_ENDTEST }
669 static struct call_entry content_handler_test_callback_rets_alt[] = {
670 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
671 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
672 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
673 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
674 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
675 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
676 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
677 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
678 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
679 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
680 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
681 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
682 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
683 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
684 { CH_ENDTEST }
687 static struct attribute_entry ch_attributes1[] = {
688 { "", "", "xmlns:test", "prefix_test" },
689 { "", "", "xmlns", "prefix" },
690 { "prefix_test", "arg1", "test:arg1", "arg1" },
691 { "", "arg2", "arg2", "arg2" },
692 { "prefix_test", "ar3", "test:ar3", "arg3" },
693 { NULL }
696 static struct attribute_entry ch_attributes2[] = {
697 { "", "", "xmlns:p", "test" },
698 { NULL }
701 static struct call_entry content_handler_test_attributes[] = {
702 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
703 { CH_STARTDOCUMENT, 0, 0, S_OK },
704 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
705 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
706 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
707 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
708 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
709 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
710 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
711 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
712 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
713 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
714 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
715 { CH_ENDDOCUMENT, 0, 0 },
716 { CH_ENDTEST }
719 static struct attribute_entry ch_attributes_alt_4[] = {
720 { "prefix_test", "arg1", "test:arg1", "arg1" },
721 { "", "arg2", "arg2", "arg2" },
722 { "prefix_test", "ar3", "test:ar3", "arg3" },
723 { "", "", "xmlns:test", "prefix_test" },
724 { "", "", "xmlns", "prefix" },
725 { NULL }
728 static struct call_entry content_handler_test_attributes_alternate_4[] = {
729 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
730 { CH_STARTDOCUMENT, 1, 22, S_OK },
731 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
732 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
733 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
734 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
735 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
736 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
737 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
738 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
739 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
740 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
741 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
742 { CH_ENDDOCUMENT, 4, 0, S_OK },
743 { CH_ENDTEST }
746 /* 'namespace' feature switched off */
747 static struct attribute_entry ch_attributes_alt_no_ns[] = {
748 { "", "", "xmlns:test", "prefix_test" },
749 { "", "", "xmlns", "prefix" },
750 { "", "", "test:arg1", "arg1" },
751 { "", "", "arg2", "arg2" },
752 { "", "", "test:ar3", "arg3" },
753 { NULL }
756 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
757 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
758 { CH_STARTDOCUMENT, 1, 22, S_OK },
759 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
760 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
761 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
762 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
763 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
764 { CH_ENDDOCUMENT, 4, 0, S_OK },
765 { CH_ENDTEST }
768 static struct attribute_entry ch_attributes_alt_6[] = {
769 { "prefix_test", "arg1", "test:arg1", "arg1" },
770 { "", "arg2", "arg2", "arg2" },
771 { "prefix_test", "ar3", "test:ar3", "arg3" },
772 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
773 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
774 { NULL }
777 static struct attribute_entry ch_attributes2_6[] = {
778 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
779 { NULL }
782 static struct call_entry content_handler_test_attributes_alternate_6[] = {
783 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
784 { CH_STARTDOCUMENT, 1, 22, S_OK },
785 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
786 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
787 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
788 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
789 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
790 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
791 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
792 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
793 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
794 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
795 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
796 { CH_ENDDOCUMENT, 4, 0, S_OK },
797 { CH_ENDTEST }
800 /* 'namespaces' is on, 'namespace-prefixes' if off */
801 static struct attribute_entry ch_attributes_no_prefix[] = {
802 { "prefix_test", "arg1", "test:arg1", "arg1" },
803 { "", "arg2", "arg2", "arg2" },
804 { "prefix_test", "ar3", "test:ar3", "arg3" },
805 { NULL }
808 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
809 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
810 { CH_STARTDOCUMENT, 1, 22, S_OK },
811 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
812 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
813 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
814 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
815 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
816 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
817 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
818 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
819 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
820 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
821 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
822 { CH_ENDDOCUMENT, 4, 0, S_OK },
823 { CH_ENDTEST }
826 static struct call_entry content_handler_test_attributes_no_prefix[] = {
827 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
828 { CH_STARTDOCUMENT, 0, 0, S_OK },
829 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
830 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
831 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
832 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
833 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
834 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
835 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
836 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
837 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
838 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
839 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
840 { CH_ENDDOCUMENT, 0, 0 },
841 { CH_ENDTEST }
844 static struct attribute_entry xmlspace_attrs[] = {
845 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
846 { NULL }
849 static struct call_entry xmlspaceattr_test[] = {
850 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
851 { CH_STARTDOCUMENT, 0, 0, S_OK },
852 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
853 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
854 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
855 { CH_ENDDOCUMENT, 0, 0, S_OK },
856 { CH_ENDTEST }
859 static struct call_entry xmlspaceattr_test_alternate[] = {
860 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
861 { CH_STARTDOCUMENT, 1, 39, S_OK },
862 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
863 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
864 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
865 { CH_ENDDOCUMENT, 1, 83, S_OK },
866 { CH_ENDTEST }
869 /* attribute value normalization test */
870 static const char attribute_normalize[] =
871 "<?xml version=\"1.0\" ?>\n"
872 "<a attr1=\" \r \n \tattr_value &#65; \t \r \n\r\n \n\"/>\n";
874 static struct attribute_entry attribute_norm_attrs[] = {
875 { "", "attr1", "attr1", " attr_value A " },
876 { NULL }
879 static struct call_entry attribute_norm[] = {
880 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
881 { CH_STARTDOCUMENT, 0, 0, S_OK },
882 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
883 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
884 { CH_ENDDOCUMENT, 0, 0, S_OK },
885 { CH_ENDTEST }
888 static struct call_entry attribute_norm_alt[] = {
889 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
890 { CH_STARTDOCUMENT, 1, 22, S_OK },
891 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
892 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
893 { CH_ENDDOCUMENT, 9, 0, S_OK },
894 { CH_ENDTEST }
897 static const char xmlspace_attr[] =
898 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
899 "<a xml:space=\"preserve\"> Some text data </a>";
901 static struct call_entry *expectCall;
902 static ISAXLocator *locator;
903 static ISAXXMLReader *g_reader;
904 int msxml_version;
906 static void set_expected_seq(struct call_entry *expected)
908 expectCall = expected;
911 /* to be called once on each tested callback return */
912 static HRESULT get_expected_ret(void)
914 HRESULT hr = expectCall->ret;
915 if (expectCall->id != CH_ENDTEST) expectCall++;
916 return hr;
919 static HRESULT WINAPI contentHandler_QueryInterface(
920 ISAXContentHandler* iface,
921 REFIID riid,
922 void **ppvObject)
924 *ppvObject = NULL;
926 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
928 *ppvObject = iface;
930 else
932 return E_NOINTERFACE;
935 return S_OK;
938 static ULONG WINAPI contentHandler_AddRef(
939 ISAXContentHandler* iface)
941 return 2;
944 static ULONG WINAPI contentHandler_Release(
945 ISAXContentHandler* iface)
947 return 1;
950 static HRESULT WINAPI contentHandler_putDocumentLocator(
951 ISAXContentHandler* iface,
952 ISAXLocator *pLocator)
954 struct call_entry call;
955 HRESULT hr;
957 locator = pLocator;
959 memset(&call, 0, sizeof(call));
960 init_call_entry(locator, &call);
961 call.id = CH_PUTDOCUMENTLOCATOR;
962 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
964 if (msxml_version >= 6) {
965 ISAXAttributes *attr, *attr1;
966 IMXAttributes *mxattr;
968 EXPECT_REF(pLocator, 1);
969 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
970 EXPECT_HR(hr, S_OK);
971 EXPECT_REF(pLocator, 2);
972 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
973 EXPECT_HR(hr, S_OK);
974 EXPECT_REF(pLocator, 3);
975 ok(attr == attr1, "got %p, %p\n", attr, attr1);
977 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
978 EXPECT_HR(hr, E_NOINTERFACE);
980 ISAXAttributes_Release(attr);
981 ISAXAttributes_Release(attr1);
984 return get_expected_ret();
987 static ISAXAttributes *test_attr_ptr;
988 static HRESULT WINAPI contentHandler_startDocument(
989 ISAXContentHandler* iface)
991 struct call_entry call;
993 init_call_entry(locator, &call);
994 call.id = CH_STARTDOCUMENT;
995 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
997 test_attr_ptr = NULL;
999 return get_expected_ret();
1002 static HRESULT WINAPI contentHandler_endDocument(
1003 ISAXContentHandler* iface)
1005 struct call_entry call;
1007 init_call_entry(locator, &call);
1008 call.id = CH_ENDDOCUMENT;
1009 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1011 return get_expected_ret();
1014 static HRESULT WINAPI contentHandler_startPrefixMapping(
1015 ISAXContentHandler* iface,
1016 const WCHAR *prefix, int prefix_len,
1017 const WCHAR *uri, int uri_len)
1019 struct call_entry call;
1021 init_call_entry(locator, &call);
1022 call.id = CH_STARTPREFIXMAPPING;
1023 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1024 call.arg2W = SysAllocStringLen(uri, uri_len);
1025 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1027 return get_expected_ret();
1030 static HRESULT WINAPI contentHandler_endPrefixMapping(
1031 ISAXContentHandler* iface,
1032 const WCHAR *prefix, int len)
1034 struct call_entry call;
1036 init_call_entry(locator, &call);
1037 call.id = CH_ENDPREFIXMAPPING;
1038 call.arg1W = SysAllocStringLen(prefix, len);
1039 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1041 return get_expected_ret();
1044 static HRESULT WINAPI contentHandler_startElement(
1045 ISAXContentHandler* iface,
1046 const WCHAR *uri, int uri_len,
1047 const WCHAR *localname, int local_len,
1048 const WCHAR *qname, int qname_len,
1049 ISAXAttributes *saxattr)
1051 struct call_entry call;
1052 IMXAttributes *mxattr;
1053 HRESULT hr;
1054 int len;
1056 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1057 EXPECT_HR(hr, E_NOINTERFACE);
1059 init_call_entry(locator, &call);
1060 call.id = CH_STARTELEMENT;
1061 call.arg1W = SysAllocStringLen(uri, uri_len);
1062 call.arg2W = SysAllocStringLen(localname, local_len);
1063 call.arg3W = SysAllocStringLen(qname, qname_len);
1065 if(!test_attr_ptr)
1066 test_attr_ptr = saxattr;
1067 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1069 /* store actual attributes */
1070 len = 0;
1071 hr = ISAXAttributes_getLength(saxattr, &len);
1072 EXPECT_HR(hr, S_OK);
1074 if (len)
1076 VARIANT_BOOL v;
1077 int i;
1079 struct attribute_entry *attr;
1080 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1082 v = VARIANT_TRUE;
1083 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1084 EXPECT_HR(hr, S_OK);
1086 for (i = 0; i < len; i++)
1088 const WCHAR *value;
1089 int value_len;
1091 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1092 &localname, &local_len, &qname, &qname_len);
1093 EXPECT_HR(hr, S_OK);
1095 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1096 EXPECT_HR(hr, S_OK);
1098 /* if 'namespaces' switched off uri and local name contains garbage */
1099 if (v == VARIANT_FALSE && msxml_version > 0)
1101 attr[i].uriW = SysAllocStringLen(NULL, 0);
1102 attr[i].localW = SysAllocStringLen(NULL, 0);
1104 else
1106 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1107 attr[i].localW = SysAllocStringLen(localname, local_len);
1110 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1111 attr[i].valueW = SysAllocStringLen(value, value_len);
1114 call.attributes = attr;
1115 call.attr_count = len;
1118 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1120 return get_expected_ret();
1123 static HRESULT WINAPI contentHandler_endElement(
1124 ISAXContentHandler* iface,
1125 const WCHAR *uri, int uri_len,
1126 const WCHAR *localname, int local_len,
1127 const WCHAR *qname, int qname_len)
1129 struct call_entry call;
1131 init_call_entry(locator, &call);
1132 call.id = CH_ENDELEMENT;
1133 call.arg1W = SysAllocStringLen(uri, uri_len);
1134 call.arg2W = SysAllocStringLen(localname, local_len);
1135 call.arg3W = SysAllocStringLen(qname, qname_len);
1136 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1138 return get_expected_ret();
1141 static HRESULT WINAPI contentHandler_characters(
1142 ISAXContentHandler* iface,
1143 const WCHAR *chars,
1144 int len)
1146 struct call_entry call;
1148 init_call_entry(locator, &call);
1149 call.id = CH_CHARACTERS;
1150 call.arg1W = SysAllocStringLen(chars, len);
1151 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1153 return get_expected_ret();
1156 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1157 ISAXContentHandler* iface,
1158 const WCHAR *chars, int len)
1160 struct call_entry call;
1162 init_call_entry(locator, &call);
1163 call.id = CH_IGNORABLEWHITESPACE;
1164 call.arg1W = SysAllocStringLen(chars, len);
1165 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1167 return get_expected_ret();
1170 static HRESULT WINAPI contentHandler_processingInstruction(
1171 ISAXContentHandler* iface,
1172 const WCHAR *target, int target_len,
1173 const WCHAR *data, int data_len)
1175 struct call_entry call;
1177 init_call_entry(locator, &call);
1178 call.id = CH_PROCESSINGINSTRUCTION;
1179 call.arg1W = SysAllocStringLen(target, target_len);
1180 call.arg2W = SysAllocStringLen(data, data_len);
1181 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1183 return get_expected_ret();
1186 static HRESULT WINAPI contentHandler_skippedEntity(
1187 ISAXContentHandler* iface,
1188 const WCHAR *name, int len)
1190 struct call_entry call;
1192 init_call_entry(locator, &call);
1193 call.id = CH_SKIPPEDENTITY;
1194 call.arg1W = SysAllocStringLen(name, len);
1196 return get_expected_ret();
1199 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1201 contentHandler_QueryInterface,
1202 contentHandler_AddRef,
1203 contentHandler_Release,
1204 contentHandler_putDocumentLocator,
1205 contentHandler_startDocument,
1206 contentHandler_endDocument,
1207 contentHandler_startPrefixMapping,
1208 contentHandler_endPrefixMapping,
1209 contentHandler_startElement,
1210 contentHandler_endElement,
1211 contentHandler_characters,
1212 contentHandler_ignorableWhitespace,
1213 contentHandler_processingInstruction,
1214 contentHandler_skippedEntity
1217 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1219 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1220 ISAXErrorHandler* iface,
1221 REFIID riid,
1222 void **ppvObject)
1224 *ppvObject = NULL;
1226 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1228 *ppvObject = iface;
1230 else
1232 return E_NOINTERFACE;
1235 return S_OK;
1238 static ULONG WINAPI isaxerrorHandler_AddRef(
1239 ISAXErrorHandler* iface)
1241 return 2;
1244 static ULONG WINAPI isaxerrorHandler_Release(
1245 ISAXErrorHandler* iface)
1247 return 1;
1250 static HRESULT WINAPI isaxerrorHandler_error(
1251 ISAXErrorHandler* iface,
1252 ISAXLocator *pLocator,
1253 const WCHAR *pErrorMessage,
1254 HRESULT hrErrorCode)
1256 ok(0, "unexpected call\n");
1257 return S_OK;
1260 static HRESULT WINAPI isaxerrorHandler_fatalError(
1261 ISAXErrorHandler* iface,
1262 ISAXLocator *pLocator,
1263 const WCHAR *message,
1264 HRESULT hr)
1266 struct call_entry call;
1268 init_call_entry(locator, &call);
1269 call.id = EH_FATALERROR;
1270 call.ret = hr;
1272 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1274 get_expected_ret();
1275 return S_OK;
1278 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1279 ISAXErrorHandler* iface,
1280 ISAXLocator *pLocator,
1281 const WCHAR *pErrorMessage,
1282 HRESULT hrErrorCode)
1284 ok(0, "unexpected call\n");
1285 return S_OK;
1288 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1290 isaxerrorHandler_QueryInterface,
1291 isaxerrorHandler_AddRef,
1292 isaxerrorHandler_Release,
1293 isaxerrorHandler_error,
1294 isaxerrorHandler_fatalError,
1295 isaxerrorHanddler_ignorableWarning
1298 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1300 static HRESULT WINAPI isaxattributes_QueryInterface(
1301 ISAXAttributes* iface,
1302 REFIID riid,
1303 void **ppvObject)
1305 *ppvObject = NULL;
1307 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1309 *ppvObject = iface;
1311 else
1313 return E_NOINTERFACE;
1316 return S_OK;
1319 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1321 return 2;
1324 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1326 return 1;
1329 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1331 *length = 3;
1332 return S_OK;
1335 static HRESULT WINAPI isaxattributes_getURI(
1336 ISAXAttributes* iface,
1337 int nIndex,
1338 const WCHAR **pUrl,
1339 int *pUriSize)
1341 ok(0, "unexpected call\n");
1342 return E_NOTIMPL;
1345 static HRESULT WINAPI isaxattributes_getLocalName(
1346 ISAXAttributes* iface,
1347 int nIndex,
1348 const WCHAR **pLocalName,
1349 int *pLocalNameLength)
1351 ok(0, "unexpected call\n");
1352 return E_NOTIMPL;
1355 static HRESULT WINAPI isaxattributes_getQName(
1356 ISAXAttributes* iface,
1357 int index,
1358 const WCHAR **QName,
1359 int *QNameLength)
1361 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1362 {'a','t','t','r','2','j','u','n','k',0},
1363 {'a','t','t','r','3',0}};
1364 static const int attrqnamelen[] = {7, 5, 5};
1366 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1368 *QName = attrqnamesW[index];
1369 *QNameLength = attrqnamelen[index];
1371 return S_OK;
1374 static HRESULT WINAPI isaxattributes_getName(
1375 ISAXAttributes* iface,
1376 int nIndex,
1377 const WCHAR **pUri,
1378 int * pUriLength,
1379 const WCHAR ** pLocalName,
1380 int * pLocalNameSize,
1381 const WCHAR ** pQName,
1382 int * pQNameLength)
1384 ok(0, "unexpected call\n");
1385 return E_NOTIMPL;
1388 static HRESULT WINAPI isaxattributes_getIndexFromName(
1389 ISAXAttributes* iface,
1390 const WCHAR * pUri,
1391 int cUriLength,
1392 const WCHAR * pLocalName,
1393 int cocalNameLength,
1394 int * index)
1396 ok(0, "unexpected call\n");
1397 return E_NOTIMPL;
1400 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1401 ISAXAttributes* iface,
1402 const WCHAR * pQName,
1403 int nQNameLength,
1404 int * index)
1406 ok(0, "unexpected call\n");
1407 return E_NOTIMPL;
1410 static HRESULT WINAPI isaxattributes_getType(
1411 ISAXAttributes* iface,
1412 int nIndex,
1413 const WCHAR ** pType,
1414 int * pTypeLength)
1416 ok(0, "unexpected call\n");
1417 return E_NOTIMPL;
1420 static HRESULT WINAPI isaxattributes_getTypeFromName(
1421 ISAXAttributes* iface,
1422 const WCHAR * pUri,
1423 int nUri,
1424 const WCHAR * pLocalName,
1425 int nLocalName,
1426 const WCHAR ** pType,
1427 int * nType)
1429 ok(0, "unexpected call\n");
1430 return E_NOTIMPL;
1433 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1434 ISAXAttributes* iface,
1435 const WCHAR * pQName,
1436 int nQName,
1437 const WCHAR ** pType,
1438 int * nType)
1440 ok(0, "unexpected call\n");
1441 return E_NOTIMPL;
1444 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1445 const WCHAR **value, int *nValue)
1447 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1448 {'a','2','j','u','n','k',0},
1449 {'<','&','"','>',0}};
1450 static const int attrvalueslen[] = {2, 2, 4};
1452 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1454 *value = attrvaluesW[index];
1455 *nValue = attrvalueslen[index];
1457 return S_OK;
1460 static HRESULT WINAPI isaxattributes_getValueFromName(
1461 ISAXAttributes* iface,
1462 const WCHAR * pUri,
1463 int nUri,
1464 const WCHAR * pLocalName,
1465 int nLocalName,
1466 const WCHAR ** pValue,
1467 int * nValue)
1469 ok(0, "unexpected call\n");
1470 return E_NOTIMPL;
1473 static HRESULT WINAPI isaxattributes_getValueFromQName(
1474 ISAXAttributes* iface,
1475 const WCHAR * pQName,
1476 int nQName,
1477 const WCHAR ** pValue,
1478 int * nValue)
1480 ok(0, "unexpected call\n");
1481 return E_NOTIMPL;
1484 static const ISAXAttributesVtbl SAXAttributesVtbl =
1486 isaxattributes_QueryInterface,
1487 isaxattributes_AddRef,
1488 isaxattributes_Release,
1489 isaxattributes_getLength,
1490 isaxattributes_getURI,
1491 isaxattributes_getLocalName,
1492 isaxattributes_getQName,
1493 isaxattributes_getName,
1494 isaxattributes_getIndexFromName,
1495 isaxattributes_getIndexFromQName,
1496 isaxattributes_getType,
1497 isaxattributes_getTypeFromName,
1498 isaxattributes_getTypeFromQName,
1499 isaxattributes_getValue,
1500 isaxattributes_getValueFromName,
1501 isaxattributes_getValueFromQName
1504 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1506 struct saxlexicalhandler
1508 ISAXLexicalHandler ISAXLexicalHandler_iface;
1509 LONG ref;
1511 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1514 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1516 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1519 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1521 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1523 *out = NULL;
1525 if (IsEqualGUID(riid, &IID_IUnknown))
1527 *out = iface;
1528 ok(0, "got unexpected IID_IUnknown query\n");
1530 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1532 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1533 *out = iface;
1536 if (*out)
1537 ISAXLexicalHandler_AddRef(iface);
1538 else
1539 return E_NOINTERFACE;
1541 return S_OK;
1544 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1546 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1547 return InterlockedIncrement(&handler->ref);
1550 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1552 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1553 return InterlockedDecrement(&handler->ref);
1556 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1557 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1558 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1560 ok(0, "call not expected\n");
1561 return E_NOTIMPL;
1564 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1566 ok(0, "call not expected\n");
1567 return E_NOTIMPL;
1570 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1571 const WCHAR * pName, int nName)
1573 ok(0, "call not expected\n");
1574 return E_NOTIMPL;
1577 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1578 const WCHAR * pName, int nName)
1580 ok(0, "call not expected\n");
1581 return E_NOTIMPL;
1584 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1586 ok(0, "call not expected\n");
1587 return E_NOTIMPL;
1590 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1592 ok(0, "call not expected\n");
1593 return E_NOTIMPL;
1596 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1597 const WCHAR * pChars, int nChars)
1599 ok(0, "call not expected\n");
1600 return E_NOTIMPL;
1603 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1605 isaxlexical_QueryInterface,
1606 isaxlexical_AddRef,
1607 isaxlexical_Release,
1608 isaxlexical_startDTD,
1609 isaxlexical_endDTD,
1610 isaxlexical_startEntity,
1611 isaxlexical_endEntity,
1612 isaxlexical_startCDATA,
1613 isaxlexical_endCDATA,
1614 isaxlexical_comment
1617 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1619 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1620 handler->ref = 1;
1621 handler->qi_hr = hr;
1624 struct saxdeclhandler
1626 ISAXDeclHandler ISAXDeclHandler_iface;
1627 LONG ref;
1629 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1632 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1634 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1637 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1639 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1641 *out = NULL;
1643 if (IsEqualGUID(riid, &IID_IUnknown))
1645 *out = iface;
1646 ok(0, "got unexpected IID_IUnknown query\n");
1648 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1650 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1651 *out = iface;
1654 if (*out)
1655 ISAXDeclHandler_AddRef(iface);
1656 else
1657 return E_NOINTERFACE;
1659 return S_OK;
1662 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1664 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1665 return InterlockedIncrement(&handler->ref);
1668 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1670 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1671 return InterlockedDecrement(&handler->ref);
1674 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1675 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1677 ok(0, "call not expected\n");
1678 return E_NOTIMPL;
1681 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1682 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1683 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1684 int nValueDefault, const WCHAR * pValue, int nValue)
1686 ok(0, "call not expected\n");
1687 return E_NOTIMPL;
1690 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1691 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1693 ok(0, "call not expected\n");
1694 return E_NOTIMPL;
1697 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1698 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1699 const WCHAR * pSystemId, int nSystemId)
1701 ok(0, "call not expected\n");
1702 return E_NOTIMPL;
1705 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1707 isaxdecl_QueryInterface,
1708 isaxdecl_AddRef,
1709 isaxdecl_Release,
1710 isaxdecl_elementDecl,
1711 isaxdecl_attributeDecl,
1712 isaxdecl_internalEntityDecl,
1713 isaxdecl_externalEntityDecl
1716 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1718 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1719 handler->ref = 1;
1720 handler->qi_hr = hr;
1723 typedef struct mxwriter_write_test_t {
1724 BOOL last;
1725 const BYTE *data;
1726 DWORD cb;
1727 BOOL null_written;
1728 BOOL fail_write;
1729 } mxwriter_write_test;
1731 typedef struct mxwriter_stream_test_t {
1732 VARIANT_BOOL bom;
1733 const char *encoding;
1734 mxwriter_write_test expected_writes[4];
1735 } mxwriter_stream_test;
1737 static const mxwriter_write_test *current_write_test;
1738 static DWORD current_stream_test_index;
1740 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1742 *ppvObject = NULL;
1744 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1745 *ppvObject = iface;
1746 else
1747 return E_NOINTERFACE;
1749 return S_OK;
1752 static ULONG WINAPI istream_AddRef(IStream *iface)
1754 return 2;
1757 static ULONG WINAPI istream_Release(IStream *iface)
1759 return 1;
1762 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1764 ok(0, "unexpected call\n");
1765 return E_NOTIMPL;
1768 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1770 BOOL fail = FALSE;
1772 ok(pv != NULL, "pv == NULL\n");
1774 if(current_write_test->last) {
1775 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1776 return E_FAIL;
1779 fail = current_write_test->fail_write;
1781 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1782 current_write_test->cb, cb, current_stream_test_index);
1784 if(!pcbWritten)
1785 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1786 else
1787 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1789 ++current_write_test;
1791 if(pcbWritten)
1792 *pcbWritten = cb;
1794 return fail ? E_FAIL : S_OK;
1797 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1798 ULARGE_INTEGER *plibNewPosition)
1800 ok(0, "unexpected call\n");
1801 return E_NOTIMPL;
1804 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1806 ok(0, "unexpected call\n");
1807 return E_NOTIMPL;
1810 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1811 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1813 ok(0, "unexpected call\n");
1814 return E_NOTIMPL;
1817 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1819 ok(0, "unexpected call\n");
1820 return E_NOTIMPL;
1823 static HRESULT WINAPI istream_Revert(IStream *iface)
1825 ok(0, "unexpected call\n");
1826 return E_NOTIMPL;
1829 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1830 ULARGE_INTEGER cb, DWORD dwLockType)
1832 ok(0, "unexpected call\n");
1833 return E_NOTIMPL;
1836 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1837 ULARGE_INTEGER cb, DWORD dwLockType)
1839 ok(0, "unexpected call\n");
1840 return E_NOTIMPL;
1843 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1845 ok(0, "unexpected call\n");
1846 return E_NOTIMPL;
1849 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1851 ok(0, "unexpected call\n");
1852 return E_NOTIMPL;
1855 static const IStreamVtbl StreamVtbl = {
1856 istream_QueryInterface,
1857 istream_AddRef,
1858 istream_Release,
1859 istream_Read,
1860 istream_Write,
1861 istream_Seek,
1862 istream_SetSize,
1863 istream_CopyTo,
1864 istream_Commit,
1865 istream_Revert,
1866 istream_LockRegion,
1867 istream_UnlockRegion,
1868 istream_Stat,
1869 istream_Clone
1872 static IStream mxstream = { &StreamVtbl };
1874 static struct msxmlsupported_data_t reader_support_data[] =
1876 { &CLSID_SAXXMLReader, "SAXReader" },
1877 { &CLSID_SAXXMLReader30, "SAXReader30" },
1878 { &CLSID_SAXXMLReader40, "SAXReader40" },
1879 { &CLSID_SAXXMLReader60, "SAXReader60" },
1880 { NULL }
1883 static void test_saxreader(void)
1885 const struct msxmlsupported_data_t *table = reader_support_data;
1886 HRESULT hr;
1887 ISAXXMLReader *reader = NULL;
1888 VARIANT var;
1889 ISAXContentHandler *content;
1890 ISAXErrorHandler *lpErrorHandler;
1891 SAFEARRAY *sa;
1892 SAFEARRAYBOUND SADim[1];
1893 char *ptr = NULL;
1894 IStream *stream;
1895 ULARGE_INTEGER size;
1896 LARGE_INTEGER pos;
1897 ULONG written;
1898 HANDLE file;
1899 static const CHAR testXmlA[] = "test.xml";
1900 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1901 IXMLDOMDocument *doc;
1902 VARIANT_BOOL v;
1904 while (table->clsid)
1906 struct call_entry *test_seq;
1907 BSTR str;
1909 if (!is_clsid_supported(table->clsid, reader_support_data))
1911 table++;
1912 continue;
1915 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1916 EXPECT_HR(hr, S_OK);
1917 g_reader = reader;
1919 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1920 msxml_version = 4;
1921 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1922 msxml_version = 6;
1923 else
1924 msxml_version = 0;
1926 /* crashes on old versions */
1927 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1928 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1930 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1931 EXPECT_HR(hr, E_POINTER);
1933 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1934 EXPECT_HR(hr, E_POINTER);
1937 hr = ISAXXMLReader_getContentHandler(reader, &content);
1938 EXPECT_HR(hr, S_OK);
1939 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1941 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1942 EXPECT_HR(hr, S_OK);
1943 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1945 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1946 EXPECT_HR(hr, S_OK);
1948 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1949 EXPECT_HR(hr, S_OK);
1951 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1952 EXPECT_HR(hr, S_OK);
1954 hr = ISAXXMLReader_getContentHandler(reader, &content);
1955 EXPECT_HR(hr, S_OK);
1956 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1958 V_VT(&var) = VT_BSTR;
1959 V_BSTR(&var) = SysAllocString(szSimpleXML);
1961 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1962 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1963 test_seq = content_handler_test1_alternate;
1964 else
1965 test_seq = content_handler_test1;
1966 set_expected_seq(test_seq);
1967 hr = ISAXXMLReader_parse(reader, var);
1968 EXPECT_HR(hr, S_OK);
1969 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1971 VariantClear(&var);
1973 SADim[0].lLbound = 0;
1974 SADim[0].cElements = sizeof(testXML)-1;
1975 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1976 SafeArrayAccessData(sa, (void**)&ptr);
1977 memcpy(ptr, testXML, sizeof(testXML)-1);
1978 SafeArrayUnaccessData(sa);
1979 V_VT(&var) = VT_ARRAY|VT_UI1;
1980 V_ARRAY(&var) = sa;
1982 set_expected_seq(test_seq);
1983 hr = ISAXXMLReader_parse(reader, var);
1984 EXPECT_HR(hr, S_OK);
1985 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1987 SafeArrayDestroy(sa);
1989 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1990 size.QuadPart = strlen(testXML);
1991 IStream_SetSize(stream, size);
1992 IStream_Write(stream, testXML, strlen(testXML), &written);
1993 pos.QuadPart = 0;
1994 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1995 V_VT(&var) = VT_UNKNOWN;
1996 V_UNKNOWN(&var) = (IUnknown*)stream;
1998 set_expected_seq(test_seq);
1999 hr = ISAXXMLReader_parse(reader, var);
2000 EXPECT_HR(hr, S_OK);
2001 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2003 IStream_Release(stream);
2005 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2006 size.QuadPart = strlen(test_attributes);
2007 IStream_SetSize(stream, size);
2008 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2009 pos.QuadPart = 0;
2010 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2011 V_VT(&var) = VT_UNKNOWN;
2012 V_UNKNOWN(&var) = (IUnknown*)stream;
2014 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2015 test_seq = content_handler_test_attributes_alternate_4;
2016 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2017 test_seq = content_handler_test_attributes_alternate_6;
2018 else
2019 test_seq = content_handler_test_attributes;
2021 set_expected_seq(test_seq);
2022 hr = ISAXXMLReader_parse(reader, var);
2023 EXPECT_HR(hr, S_OK);
2025 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2026 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2027 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2028 else
2029 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2031 IStream_Release(stream);
2033 V_VT(&var) = VT_BSTR;
2034 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2036 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2037 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2038 test_seq = content_handler_test2_alternate;
2039 else
2040 test_seq = content_handler_test2;
2042 set_expected_seq(test_seq);
2043 hr = ISAXXMLReader_parse(reader, var);
2044 EXPECT_HR(hr, S_OK);
2045 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2047 VariantClear(&var);
2049 /* from file url */
2050 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2051 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2052 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2053 CloseHandle(file);
2055 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2056 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2057 test_seq = content_handler_test1_alternate;
2058 else
2059 test_seq = content_handler_test1;
2060 set_expected_seq(test_seq);
2061 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2062 EXPECT_HR(hr, S_OK);
2063 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2065 /* error handler */
2066 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2067 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2068 test_seq = content_handler_testerror_alternate;
2069 else
2070 test_seq = content_handler_testerror;
2071 set_expected_seq(test_seq);
2072 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2073 EXPECT_HR(hr, E_FAIL);
2074 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2076 /* callback ret values */
2077 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2078 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2080 test_seq = content_handler_test_callback_rets_alt;
2081 set_expected_seq(test_seq);
2082 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2083 EXPECT_HR(hr, S_OK);
2085 else
2087 test_seq = content_handler_test_callback_rets;
2088 set_expected_seq(test_seq);
2089 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2090 EXPECT_HR(hr, S_FALSE);
2092 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2094 DeleteFileA(testXmlA);
2096 /* parse from IXMLDOMDocument */
2097 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2098 &IID_IXMLDOMDocument, (void**)&doc);
2099 EXPECT_HR(hr, S_OK);
2101 str = SysAllocString(szSimpleXML);
2102 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2103 EXPECT_HR(hr, S_OK);
2104 SysFreeString(str);
2106 V_VT(&var) = VT_UNKNOWN;
2107 V_UNKNOWN(&var) = (IUnknown*)doc;
2109 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2110 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2111 test_seq = content_handler_test2_alternate;
2112 else
2113 test_seq = content_handler_test2;
2115 set_expected_seq(test_seq);
2116 hr = ISAXXMLReader_parse(reader, var);
2117 EXPECT_HR(hr, S_OK);
2118 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2119 IXMLDOMDocument_Release(doc);
2121 /* xml:space test */
2122 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2123 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2125 test_seq = xmlspaceattr_test_alternate;
2127 else
2128 test_seq = xmlspaceattr_test;
2130 set_expected_seq(test_seq);
2131 V_VT(&var) = VT_BSTR;
2132 V_BSTR(&var) = _bstr_(xmlspace_attr);
2133 hr = ISAXXMLReader_parse(reader, var);
2134 EXPECT_HR(hr, S_OK);
2136 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2137 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2139 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2141 else
2142 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2144 /* switch off 'namespaces' feature */
2145 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2146 EXPECT_HR(hr, S_OK);
2148 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2149 size.QuadPart = strlen(test_attributes);
2150 IStream_SetSize(stream, size);
2151 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2152 pos.QuadPart = 0;
2153 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2154 V_VT(&var) = VT_UNKNOWN;
2155 V_UNKNOWN(&var) = (IUnknown*)stream;
2157 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2158 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2160 test_seq = content_handler_test_attributes_alt_no_ns;
2162 else
2163 test_seq = content_handler_test_attributes;
2165 set_expected_seq(test_seq);
2166 hr = ISAXXMLReader_parse(reader, var);
2167 EXPECT_HR(hr, S_OK);
2168 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2169 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2170 EXPECT_HR(hr, S_OK);
2172 /* switch off 'namespace-prefixes' feature */
2173 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2174 EXPECT_HR(hr, S_OK);
2176 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2177 size.QuadPart = strlen(test_attributes);
2178 IStream_SetSize(stream, size);
2179 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2180 pos.QuadPart = 0;
2181 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2182 V_VT(&var) = VT_UNKNOWN;
2183 V_UNKNOWN(&var) = (IUnknown*)stream;
2185 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2186 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2188 test_seq = content_handler_test_attributes_alt_no_prefix;
2190 else
2191 test_seq = content_handler_test_attributes_no_prefix;
2193 set_expected_seq(test_seq);
2194 hr = ISAXXMLReader_parse(reader, var);
2195 EXPECT_HR(hr, S_OK);
2196 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2198 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2199 EXPECT_HR(hr, S_OK);
2201 /* attribute normalization */
2202 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2203 size.QuadPart = strlen(attribute_normalize);
2204 IStream_SetSize(stream, size);
2205 IStream_Write(stream, attribute_normalize, strlen(attribute_normalize), &written);
2206 pos.QuadPart = 0;
2207 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2208 V_VT(&var) = VT_UNKNOWN;
2209 V_UNKNOWN(&var) = (IUnknown*)stream;
2211 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2212 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2214 test_seq = attribute_norm_alt;
2216 else
2217 test_seq = attribute_norm;
2219 set_expected_seq(test_seq);
2220 hr = ISAXXMLReader_parse(reader, var);
2221 EXPECT_HR(hr, S_OK);
2222 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2224 ISAXXMLReader_Release(reader);
2225 table++;
2228 free_bstrs();
2231 struct saxreader_props_test_t
2233 const char *prop_name;
2234 IUnknown *iface;
2237 static struct saxlexicalhandler lexicalhandler;
2238 static struct saxdeclhandler declhandler;
2240 static const struct saxreader_props_test_t props_test_data[] = {
2241 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2242 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2243 { 0 }
2246 static void test_saxreader_properties(void)
2248 const struct saxreader_props_test_t *ptr = props_test_data;
2249 ISAXXMLReader *reader;
2250 HRESULT hr;
2252 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2253 &IID_ISAXXMLReader, (void**)&reader);
2254 EXPECT_HR(hr, S_OK);
2256 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2257 EXPECT_HR(hr, E_POINTER);
2259 while (ptr->prop_name)
2261 VARIANT v;
2262 LONG ref;
2264 init_saxlexicalhandler(&lexicalhandler, S_OK);
2265 init_saxdeclhandler(&declhandler, S_OK);
2267 V_VT(&v) = VT_EMPTY;
2268 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2269 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2270 EXPECT_HR(hr, S_OK);
2271 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2272 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2274 V_VT(&v) = VT_UNKNOWN;
2275 V_UNKNOWN(&v) = ptr->iface;
2276 ref = get_refcount(ptr->iface);
2277 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2278 EXPECT_HR(hr, S_OK);
2279 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2281 V_VT(&v) = VT_EMPTY;
2282 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2284 ref = get_refcount(ptr->iface);
2285 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2286 EXPECT_HR(hr, S_OK);
2287 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2288 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2289 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2290 VariantClear(&v);
2292 V_VT(&v) = VT_EMPTY;
2293 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2294 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2295 EXPECT_HR(hr, S_OK);
2297 V_VT(&v) = VT_EMPTY;
2298 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2299 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2300 EXPECT_HR(hr, S_OK);
2301 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2302 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2304 V_VT(&v) = VT_UNKNOWN;
2305 V_UNKNOWN(&v) = ptr->iface;
2306 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2307 EXPECT_HR(hr, S_OK);
2309 /* only VT_EMPTY seems to be valid to reset property */
2310 V_VT(&v) = VT_I4;
2311 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2312 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2313 EXPECT_HR(hr, E_INVALIDARG);
2315 V_VT(&v) = VT_EMPTY;
2316 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2317 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2318 EXPECT_HR(hr, S_OK);
2319 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2320 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2321 VariantClear(&v);
2323 V_VT(&v) = VT_UNKNOWN;
2324 V_UNKNOWN(&v) = NULL;
2325 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2326 EXPECT_HR(hr, S_OK);
2328 V_VT(&v) = VT_EMPTY;
2329 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2330 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2331 EXPECT_HR(hr, S_OK);
2332 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2333 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2335 /* block QueryInterface on handler riid */
2336 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2337 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2339 V_VT(&v) = VT_UNKNOWN;
2340 V_UNKNOWN(&v) = ptr->iface;
2341 EXPECT_REF(ptr->iface, 1);
2342 ref = get_refcount(ptr->iface);
2343 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2344 EXPECT_HR(hr, E_NOINTERFACE);
2345 EXPECT_REF(ptr->iface, 1);
2347 ptr++;
2350 ISAXXMLReader_Release(reader);
2351 free_bstrs();
2354 struct feature_ns_entry_t {
2355 const GUID *guid;
2356 const char *clsid;
2357 VARIANT_BOOL value;
2358 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2361 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2362 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2363 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2364 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2365 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2366 { 0 }
2369 static const char *feature_names[] = {
2370 "http://xml.org/sax/features/namespaces",
2371 "http://xml.org/sax/features/namespace-prefixes",
2375 static void test_saxreader_features(void)
2377 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2378 ISAXXMLReader *reader;
2380 while (entry->guid)
2382 VARIANT_BOOL value;
2383 const char **name;
2384 HRESULT hr;
2386 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2387 if (hr != S_OK)
2389 win_skip("can't create %s instance\n", entry->clsid);
2390 entry++;
2391 continue;
2394 name = feature_names;
2395 while (*name)
2397 value = 0xc;
2398 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2399 EXPECT_HR(hr, S_OK);
2400 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2402 value = 0xc;
2403 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2404 EXPECT_HR(hr, S_OK);
2406 value = 0xd;
2407 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2408 EXPECT_HR(hr, S_OK);
2409 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2411 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2412 EXPECT_HR(hr, S_OK);
2413 value = 0xd;
2414 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2415 EXPECT_HR(hr, S_OK);
2416 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2418 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2419 EXPECT_HR(hr, S_OK);
2420 value = 0xd;
2421 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2422 EXPECT_HR(hr, S_OK);
2423 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2425 name++;
2428 ISAXXMLReader_Release(reader);
2430 entry++;
2434 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2435 static const CHAR UTF8BOMTest[] =
2436 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2437 "<a></a>\n";
2439 struct enc_test_entry_t {
2440 const GUID *guid;
2441 const char *clsid;
2442 const char *data;
2443 HRESULT hr;
2444 int todo;
2447 static const struct enc_test_entry_t encoding_test_data[] = {
2448 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2449 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2450 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2451 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2452 { 0 }
2455 static void test_saxreader_encoding(void)
2457 const struct enc_test_entry_t *entry = encoding_test_data;
2458 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2459 static const CHAR testXmlA[] = "test.xml";
2461 while (entry->guid)
2463 ISAXXMLReader *reader;
2464 VARIANT input;
2465 DWORD written;
2466 HANDLE file;
2467 HRESULT hr;
2469 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2470 if (hr != S_OK)
2472 win_skip("can't create %s instance\n", entry->clsid);
2473 entry++;
2474 continue;
2477 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2478 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2479 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2480 CloseHandle(file);
2482 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2483 if (entry->todo)
2484 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2485 else
2486 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2488 DeleteFileA(testXmlA);
2490 /* try BSTR input with no BOM or '<?xml' instruction */
2491 V_VT(&input) = VT_BSTR;
2492 V_BSTR(&input) = _bstr_("<element></element>");
2493 hr = ISAXXMLReader_parse(reader, input);
2494 EXPECT_HR(hr, S_OK);
2496 ISAXXMLReader_Release(reader);
2498 free_bstrs();
2499 entry++;
2503 static void test_mxwriter_handlers(void)
2505 ISAXContentHandler *handler;
2506 IMXWriter *writer, *writer2;
2507 ISAXDeclHandler *decl;
2508 ISAXLexicalHandler *lh;
2509 HRESULT hr;
2511 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2512 &IID_IMXWriter, (void**)&writer);
2513 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2515 EXPECT_REF(writer, 1);
2517 /* ISAXContentHandler */
2518 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2519 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2520 EXPECT_REF(writer, 2);
2521 EXPECT_REF(handler, 2);
2523 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2524 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2525 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2526 EXPECT_REF(writer, 3);
2527 EXPECT_REF(writer2, 3);
2528 IMXWriter_Release(writer2);
2529 ISAXContentHandler_Release(handler);
2531 /* ISAXLexicalHandler */
2532 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2533 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2534 EXPECT_REF(writer, 2);
2535 EXPECT_REF(lh, 2);
2537 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2538 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2539 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2540 EXPECT_REF(writer, 3);
2541 EXPECT_REF(writer2, 3);
2542 IMXWriter_Release(writer2);
2543 ISAXLexicalHandler_Release(lh);
2545 /* ISAXDeclHandler */
2546 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2547 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2548 EXPECT_REF(writer, 2);
2549 EXPECT_REF(lh, 2);
2551 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2552 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2553 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2554 EXPECT_REF(writer, 3);
2555 EXPECT_REF(writer2, 3);
2556 IMXWriter_Release(writer2);
2557 ISAXDeclHandler_Release(decl);
2559 IMXWriter_Release(writer);
2563 static struct msxmlsupported_data_t mxwriter_support_data[] =
2565 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2566 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2567 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2568 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2569 { NULL }
2572 static struct msxmlsupported_data_t mxattributes_support_data[] =
2574 { &CLSID_SAXAttributes, "SAXAttributes" },
2575 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2576 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2577 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2578 { NULL }
2581 struct mxwriter_props_t
2583 const GUID *clsid;
2584 VARIANT_BOOL bom;
2585 VARIANT_BOOL disable_escape;
2586 VARIANT_BOOL indent;
2587 VARIANT_BOOL omitdecl;
2588 VARIANT_BOOL standalone;
2589 const char *encoding;
2592 static const struct mxwriter_props_t mxwriter_default_props[] =
2594 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2595 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2596 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2597 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2598 { NULL }
2601 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2603 int i = 0;
2605 while (table->clsid)
2607 IMXWriter *writer;
2608 VARIANT_BOOL b;
2609 BSTR encoding;
2610 HRESULT hr;
2612 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2614 table++;
2615 i++;
2616 continue;
2619 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2620 &IID_IMXWriter, (void**)&writer);
2621 EXPECT_HR(hr, S_OK);
2623 b = !table->bom;
2624 hr = IMXWriter_get_byteOrderMark(writer, &b);
2625 EXPECT_HR(hr, S_OK);
2626 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2628 b = !table->disable_escape;
2629 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2630 EXPECT_HR(hr, S_OK);
2631 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2632 table->disable_escape);
2634 b = !table->indent;
2635 hr = IMXWriter_get_indent(writer, &b);
2636 EXPECT_HR(hr, S_OK);
2637 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2639 b = !table->omitdecl;
2640 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2641 EXPECT_HR(hr, S_OK);
2642 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2644 b = !table->standalone;
2645 hr = IMXWriter_get_standalone(writer, &b);
2646 EXPECT_HR(hr, S_OK);
2647 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2649 hr = IMXWriter_get_encoding(writer, &encoding);
2650 EXPECT_HR(hr, S_OK);
2651 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2652 i, wine_dbgstr_w(encoding), table->encoding);
2653 SysFreeString(encoding);
2655 IMXWriter_Release(writer);
2657 table++;
2658 i++;
2662 static void test_mxwriter_properties(void)
2664 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2665 static const WCHAR emptyW[] = {0};
2666 static const WCHAR testW[] = {'t','e','s','t',0};
2667 ISAXContentHandler *content;
2668 IMXWriter *writer;
2669 VARIANT_BOOL b;
2670 HRESULT hr;
2671 BSTR str, str2;
2672 VARIANT dest;
2674 test_mxwriter_default_properties(mxwriter_default_props);
2676 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2677 &IID_IMXWriter, (void**)&writer);
2678 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2680 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2681 ok(hr == E_POINTER, "got %08x\n", hr);
2683 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2684 ok(hr == E_POINTER, "got %08x\n", hr);
2686 hr = IMXWriter_get_indent(writer, NULL);
2687 ok(hr == E_POINTER, "got %08x\n", hr);
2689 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2690 ok(hr == E_POINTER, "got %08x\n", hr);
2692 hr = IMXWriter_get_standalone(writer, NULL);
2693 ok(hr == E_POINTER, "got %08x\n", hr);
2695 /* set and check */
2696 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2697 ok(hr == S_OK, "got %08x\n", hr);
2699 b = VARIANT_FALSE;
2700 hr = IMXWriter_get_standalone(writer, &b);
2701 ok(hr == S_OK, "got %08x\n", hr);
2702 ok(b == VARIANT_TRUE, "got %d\n", b);
2704 hr = IMXWriter_get_encoding(writer, NULL);
2705 EXPECT_HR(hr, E_POINTER);
2707 /* UTF-16 is a default setting apparently */
2708 str = (void*)0xdeadbeef;
2709 hr = IMXWriter_get_encoding(writer, &str);
2710 EXPECT_HR(hr, S_OK);
2711 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2713 str2 = (void*)0xdeadbeef;
2714 hr = IMXWriter_get_encoding(writer, &str2);
2715 ok(hr == S_OK, "got %08x\n", hr);
2716 ok(str != str2, "expected newly allocated, got same %p\n", str);
2718 SysFreeString(str2);
2719 SysFreeString(str);
2721 /* put empty string */
2722 str = SysAllocString(emptyW);
2723 hr = IMXWriter_put_encoding(writer, str);
2724 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2725 SysFreeString(str);
2727 str = (void*)0xdeadbeef;
2728 hr = IMXWriter_get_encoding(writer, &str);
2729 EXPECT_HR(hr, S_OK);
2730 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2731 SysFreeString(str);
2733 /* invalid encoding name */
2734 str = SysAllocString(testW);
2735 hr = IMXWriter_put_encoding(writer, str);
2736 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2737 SysFreeString(str);
2739 /* test case sensivity */
2740 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2741 EXPECT_HR(hr, S_OK);
2742 str = (void*)0xdeadbeef;
2743 hr = IMXWriter_get_encoding(writer, &str);
2744 EXPECT_HR(hr, S_OK);
2745 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2746 SysFreeString(str);
2748 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2749 EXPECT_HR(hr, S_OK);
2750 str = (void*)0xdeadbeef;
2751 hr = IMXWriter_get_encoding(writer, &str);
2752 EXPECT_HR(hr, S_OK);
2753 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2754 SysFreeString(str);
2756 /* how it affects document creation */
2757 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2758 EXPECT_HR(hr, S_OK);
2760 hr = ISAXContentHandler_startDocument(content);
2761 EXPECT_HR(hr, S_OK);
2762 hr = ISAXContentHandler_endDocument(content);
2763 EXPECT_HR(hr, S_OK);
2765 V_VT(&dest) = VT_EMPTY;
2766 hr = IMXWriter_get_output(writer, &dest);
2767 EXPECT_HR(hr, S_OK);
2768 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2769 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2770 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2771 VariantClear(&dest);
2772 ISAXContentHandler_Release(content);
2774 hr = IMXWriter_get_version(writer, NULL);
2775 ok(hr == E_POINTER, "got %08x\n", hr);
2776 /* default version is 'surprisingly' 1.0 */
2777 hr = IMXWriter_get_version(writer, &str);
2778 ok(hr == S_OK, "got %08x\n", hr);
2779 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2780 SysFreeString(str);
2782 /* store version string as is */
2783 hr = IMXWriter_put_version(writer, NULL);
2784 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2786 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2787 ok(hr == S_OK, "got %08x\n", hr);
2789 hr = IMXWriter_put_version(writer, _bstr_(""));
2790 ok(hr == S_OK, "got %08x\n", hr);
2791 hr = IMXWriter_get_version(writer, &str);
2792 ok(hr == S_OK, "got %08x\n", hr);
2793 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2794 SysFreeString(str);
2796 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2797 ok(hr == S_OK, "got %08x\n", hr);
2798 hr = IMXWriter_get_version(writer, &str);
2799 ok(hr == S_OK, "got %08x\n", hr);
2800 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2801 SysFreeString(str);
2803 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2804 ok(hr == S_OK, "got %08x\n", hr);
2805 hr = IMXWriter_get_version(writer, &str);
2806 ok(hr == S_OK, "got %08x\n", hr);
2807 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2808 SysFreeString(str);
2810 IMXWriter_Release(writer);
2811 free_bstrs();
2814 static void test_mxwriter_flush(void)
2816 ISAXContentHandler *content;
2817 IMXWriter *writer;
2818 LARGE_INTEGER pos;
2819 ULARGE_INTEGER pos2;
2820 IStream *stream;
2821 VARIANT dest;
2822 HRESULT hr;
2824 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2825 &IID_IMXWriter, (void**)&writer);
2826 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2828 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2829 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2830 EXPECT_REF(stream, 1);
2832 /* detach when nothing was attached */
2833 V_VT(&dest) = VT_EMPTY;
2834 hr = IMXWriter_put_output(writer, dest);
2835 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2837 /* attach stream */
2838 V_VT(&dest) = VT_UNKNOWN;
2839 V_UNKNOWN(&dest) = (IUnknown*)stream;
2840 hr = IMXWriter_put_output(writer, dest);
2841 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2842 todo_wine EXPECT_REF(stream, 3);
2844 /* detach setting VT_EMPTY destination */
2845 V_VT(&dest) = VT_EMPTY;
2846 hr = IMXWriter_put_output(writer, dest);
2847 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2848 EXPECT_REF(stream, 1);
2850 V_VT(&dest) = VT_UNKNOWN;
2851 V_UNKNOWN(&dest) = (IUnknown*)stream;
2852 hr = IMXWriter_put_output(writer, dest);
2853 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2855 /* flush() doesn't detach a stream */
2856 hr = IMXWriter_flush(writer);
2857 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2858 todo_wine EXPECT_REF(stream, 3);
2860 pos.QuadPart = 0;
2861 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2862 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2863 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2865 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2866 ok(hr == S_OK, "got %08x\n", hr);
2868 hr = ISAXContentHandler_startDocument(content);
2869 ok(hr == S_OK, "got %08x\n", hr);
2871 pos.QuadPart = 0;
2872 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2873 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2874 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2876 /* already started */
2877 hr = ISAXContentHandler_startDocument(content);
2878 ok(hr == S_OK, "got %08x\n", hr);
2880 hr = ISAXContentHandler_endDocument(content);
2881 ok(hr == S_OK, "got %08x\n", hr);
2883 /* flushed on endDocument() */
2884 pos.QuadPart = 0;
2885 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2886 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2887 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2889 ISAXContentHandler_Release(content);
2890 IStream_Release(stream);
2891 IMXWriter_Release(writer);
2894 static void test_mxwriter_startenddocument(void)
2896 ISAXContentHandler *content;
2897 IMXWriter *writer;
2898 VARIANT dest;
2899 HRESULT hr;
2901 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2902 &IID_IMXWriter, (void**)&writer);
2903 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2905 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2906 ok(hr == S_OK, "got %08x\n", hr);
2908 hr = ISAXContentHandler_startDocument(content);
2909 ok(hr == S_OK, "got %08x\n", hr);
2911 hr = ISAXContentHandler_endDocument(content);
2912 ok(hr == S_OK, "got %08x\n", hr);
2914 V_VT(&dest) = VT_EMPTY;
2915 hr = IMXWriter_get_output(writer, &dest);
2916 ok(hr == S_OK, "got %08x\n", hr);
2917 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2918 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2919 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2920 VariantClear(&dest);
2922 /* now try another startDocument */
2923 hr = ISAXContentHandler_startDocument(content);
2924 ok(hr == S_OK, "got %08x\n", hr);
2925 /* and get duplicated prolog */
2926 V_VT(&dest) = VT_EMPTY;
2927 hr = IMXWriter_get_output(writer, &dest);
2928 ok(hr == S_OK, "got %08x\n", hr);
2929 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2930 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
2931 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2932 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2933 VariantClear(&dest);
2935 ISAXContentHandler_Release(content);
2936 IMXWriter_Release(writer);
2938 /* now with omitted declaration */
2939 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2940 &IID_IMXWriter, (void**)&writer);
2941 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2943 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2944 ok(hr == S_OK, "got %08x\n", hr);
2946 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2947 ok(hr == S_OK, "got %08x\n", hr);
2949 hr = ISAXContentHandler_startDocument(content);
2950 ok(hr == S_OK, "got %08x\n", hr);
2952 hr = ISAXContentHandler_endDocument(content);
2953 ok(hr == S_OK, "got %08x\n", hr);
2955 V_VT(&dest) = VT_EMPTY;
2956 hr = IMXWriter_get_output(writer, &dest);
2957 ok(hr == S_OK, "got %08x\n", hr);
2958 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2959 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2960 VariantClear(&dest);
2962 ISAXContentHandler_Release(content);
2963 IMXWriter_Release(writer);
2965 free_bstrs();
2968 enum startendtype
2970 StartElement = 0x001,
2971 EndElement = 0x010,
2972 StartEndElement = 0x011,
2973 DisableEscaping = 0x100
2976 struct writer_startendelement_t {
2977 const GUID *clsid;
2978 enum startendtype type;
2979 const char *uri;
2980 const char *local_name;
2981 const char *qname;
2982 const char *output;
2983 HRESULT hr;
2984 ISAXAttributes *attr;
2987 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\">";
2988 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\"/>";
2989 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
2991 static const struct writer_startendelement_t writer_startendelement[] = {
2992 /* 0 */
2993 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2994 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2995 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2996 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
2997 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2998 /* 5 */
2999 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3000 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3001 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3002 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3003 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3004 /* 10 */
3005 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3006 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3007 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3008 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3009 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3010 /* 15 */
3011 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3012 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3013 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3014 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3015 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3016 /* 20 */
3017 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3018 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3019 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3020 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3021 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3022 /* 25 */
3023 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3024 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3025 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3026 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3027 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3028 /* 30 */
3029 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3030 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3031 /* endElement tests */
3032 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3033 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3034 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3035 /* 35 */
3036 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3037 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3038 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3039 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3040 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3041 /* 40 */
3042 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3043 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3044 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3045 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3046 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3047 /* 45 */
3048 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3049 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3050 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3051 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3052 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3053 /* 50 */
3054 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3055 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3056 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3057 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3058 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3059 /* 55 */
3060 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3061 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3062 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3063 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3064 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3065 /* 60 */
3066 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3067 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3068 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3069 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3071 /* with attributes */
3072 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3073 /* 65 */
3074 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3075 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3076 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3077 /* empty elements */
3078 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3079 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3080 /* 70 */
3081 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3082 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3083 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3084 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3085 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3086 /* 75 */
3087 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3089 /* with disabled output escaping */
3090 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3091 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3092 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3093 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3095 { NULL }
3098 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3100 while (table->clsid)
3102 IUnknown *unk;
3103 HRESULT hr;
3105 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3106 if (hr == S_OK) IUnknown_Release(unk);
3108 table->supported = hr == S_OK;
3109 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3111 table++;
3115 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3117 int i = 0;
3119 while (table->clsid)
3121 ISAXContentHandler *content;
3122 IMXWriter *writer;
3123 HRESULT hr;
3125 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3127 table++;
3128 i++;
3129 continue;
3132 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3133 &IID_IMXWriter, (void**)&writer);
3134 EXPECT_HR(hr, S_OK);
3136 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3137 EXPECT_HR(hr, S_OK);
3139 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3140 EXPECT_HR(hr, S_OK);
3142 hr = ISAXContentHandler_startDocument(content);
3143 EXPECT_HR(hr, S_OK);
3145 if (table->type & DisableEscaping)
3147 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3148 EXPECT_HR(hr, S_OK);
3151 if (table->type & StartElement)
3153 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3154 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3155 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3158 if (table->type & EndElement)
3160 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3161 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3162 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3165 /* test output */
3166 if (hr == S_OK)
3168 VARIANT dest;
3170 V_VT(&dest) = VT_EMPTY;
3171 hr = IMXWriter_get_output(writer, &dest);
3172 EXPECT_HR(hr, S_OK);
3173 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3174 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3175 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3176 VariantClear(&dest);
3179 ISAXContentHandler_Release(content);
3180 IMXWriter_Release(writer);
3182 table++;
3183 i++;
3186 free_bstrs();
3189 static void test_mxwriter_startendelement(void)
3191 ISAXContentHandler *content;
3192 IMXWriter *writer;
3193 VARIANT dest;
3194 HRESULT hr;
3196 test_mxwriter_startendelement_batch(writer_startendelement);
3198 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3199 &IID_IMXWriter, (void**)&writer);
3200 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3202 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3203 ok(hr == S_OK, "got %08x\n", hr);
3205 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3206 ok(hr == S_OK, "got %08x\n", hr);
3208 hr = ISAXContentHandler_startDocument(content);
3209 ok(hr == S_OK, "got %08x\n", hr);
3211 /* all string pointers should be not null */
3212 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3213 ok(hr == S_OK, "got %08x\n", hr);
3215 V_VT(&dest) = VT_EMPTY;
3216 hr = IMXWriter_get_output(writer, &dest);
3217 ok(hr == S_OK, "got %08x\n", hr);
3218 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3219 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3220 VariantClear(&dest);
3222 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3223 ok(hr == S_OK, "got %08x\n", hr);
3225 V_VT(&dest) = VT_EMPTY;
3226 hr = IMXWriter_get_output(writer, &dest);
3227 ok(hr == S_OK, "got %08x\n", hr);
3228 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3229 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3230 VariantClear(&dest);
3232 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3233 EXPECT_HR(hr, E_INVALIDARG);
3235 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3236 EXPECT_HR(hr, E_INVALIDARG);
3238 /* only local name is an error too */
3239 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3240 EXPECT_HR(hr, E_INVALIDARG);
3242 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3243 EXPECT_HR(hr, S_OK);
3245 V_VT(&dest) = VT_EMPTY;
3246 hr = IMXWriter_get_output(writer, &dest);
3247 EXPECT_HR(hr, S_OK);
3248 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3249 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3250 VariantClear(&dest);
3252 hr = ISAXContentHandler_endDocument(content);
3253 EXPECT_HR(hr, S_OK);
3255 V_VT(&dest) = VT_EMPTY;
3256 hr = IMXWriter_put_output(writer, dest);
3257 EXPECT_HR(hr, S_OK);
3259 V_VT(&dest) = VT_EMPTY;
3260 hr = IMXWriter_get_output(writer, &dest);
3261 EXPECT_HR(hr, S_OK);
3262 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3263 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3264 VariantClear(&dest);
3266 hr = ISAXContentHandler_startDocument(content);
3267 EXPECT_HR(hr, S_OK);
3269 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3270 EXPECT_HR(hr, S_OK);
3272 V_VT(&dest) = VT_EMPTY;
3273 hr = IMXWriter_get_output(writer, &dest);
3274 EXPECT_HR(hr, S_OK);
3275 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3276 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3277 VariantClear(&dest);
3279 ISAXContentHandler_endDocument(content);
3280 IMXWriter_flush(writer);
3282 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3283 EXPECT_HR(hr, S_OK);
3284 V_VT(&dest) = VT_EMPTY;
3285 hr = IMXWriter_get_output(writer, &dest);
3286 EXPECT_HR(hr, S_OK);
3287 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3288 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3289 VariantClear(&dest);
3291 ISAXContentHandler_Release(content);
3292 IMXWriter_Release(writer);
3293 free_bstrs();
3296 struct writer_characters_t {
3297 const GUID *clsid;
3298 const char *data;
3299 const char *output;
3302 static const struct writer_characters_t writer_characters[] = {
3303 { &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
3304 { &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
3305 { &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
3306 { &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
3307 { NULL }
3310 static void test_mxwriter_characters(void)
3312 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3313 const struct writer_characters_t *table = writer_characters;
3314 ISAXContentHandler *content;
3315 IMXWriter *writer;
3316 VARIANT dest;
3317 HRESULT hr;
3318 int i = 0;
3320 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3321 &IID_IMXWriter, (void**)&writer);
3322 EXPECT_HR(hr, S_OK);
3324 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3325 EXPECT_HR(hr, S_OK);
3327 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3328 EXPECT_HR(hr, S_OK);
3330 hr = ISAXContentHandler_startDocument(content);
3331 EXPECT_HR(hr, S_OK);
3333 hr = ISAXContentHandler_characters(content, NULL, 0);
3334 EXPECT_HR(hr, E_INVALIDARG);
3336 hr = ISAXContentHandler_characters(content, chardataW, 0);
3337 EXPECT_HR(hr, S_OK);
3339 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3340 EXPECT_HR(hr, S_OK);
3342 V_VT(&dest) = VT_EMPTY;
3343 hr = IMXWriter_get_output(writer, &dest);
3344 EXPECT_HR(hr, S_OK);
3345 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3346 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3347 VariantClear(&dest);
3349 hr = ISAXContentHandler_endDocument(content);
3350 EXPECT_HR(hr, S_OK);
3352 ISAXContentHandler_Release(content);
3353 IMXWriter_Release(writer);
3355 /* try empty characters data to see if element is closed */
3356 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3357 &IID_IMXWriter, (void**)&writer);
3358 EXPECT_HR(hr, S_OK);
3360 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3361 EXPECT_HR(hr, S_OK);
3363 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3364 EXPECT_HR(hr, S_OK);
3366 hr = ISAXContentHandler_startDocument(content);
3367 EXPECT_HR(hr, S_OK);
3369 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3370 EXPECT_HR(hr, S_OK);
3372 hr = ISAXContentHandler_characters(content, chardataW, 0);
3373 EXPECT_HR(hr, S_OK);
3375 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3376 EXPECT_HR(hr, S_OK);
3378 V_VT(&dest) = VT_EMPTY;
3379 hr = IMXWriter_get_output(writer, &dest);
3380 EXPECT_HR(hr, S_OK);
3381 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3382 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3383 VariantClear(&dest);
3385 ISAXContentHandler_Release(content);
3386 IMXWriter_Release(writer);
3388 /* batch tests */
3389 while (table->clsid)
3391 ISAXContentHandler *content;
3392 IMXWriter *writer;
3393 VARIANT dest;
3394 HRESULT hr;
3396 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3398 table++;
3399 i++;
3400 continue;
3403 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3404 &IID_IMXWriter, (void**)&writer);
3405 EXPECT_HR(hr, S_OK);
3407 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3408 EXPECT_HR(hr, S_OK);
3410 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3411 EXPECT_HR(hr, S_OK);
3413 hr = ISAXContentHandler_startDocument(content);
3414 EXPECT_HR(hr, S_OK);
3416 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3417 EXPECT_HR(hr, S_OK);
3419 /* test output */
3420 if (hr == S_OK)
3422 V_VT(&dest) = VT_EMPTY;
3423 hr = IMXWriter_get_output(writer, &dest);
3424 EXPECT_HR(hr, S_OK);
3425 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3426 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3427 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3428 VariantClear(&dest);
3431 /* with disabled escaping */
3432 V_VT(&dest) = VT_EMPTY;
3433 hr = IMXWriter_put_output(writer, dest);
3434 EXPECT_HR(hr, S_OK);
3436 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3437 EXPECT_HR(hr, S_OK);
3439 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3440 EXPECT_HR(hr, S_OK);
3442 /* test output */
3443 if (hr == S_OK)
3445 V_VT(&dest) = VT_EMPTY;
3446 hr = IMXWriter_get_output(writer, &dest);
3447 EXPECT_HR(hr, S_OK);
3448 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3449 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3450 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3451 VariantClear(&dest);
3454 ISAXContentHandler_Release(content);
3455 IMXWriter_Release(writer);
3457 table++;
3458 i++;
3461 free_bstrs();
3464 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3466 VARIANT_TRUE,"UTF-16",
3468 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3469 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3470 {TRUE}
3474 VARIANT_FALSE,"UTF-16",
3476 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3477 {TRUE}
3481 VARIANT_TRUE,"UTF-8",
3483 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3484 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3485 * and the writer is released.
3487 {FALSE,NULL,0},
3488 {TRUE}
3492 VARIANT_TRUE,"utf-8",
3494 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3495 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3496 * and the writer is released.
3498 {FALSE,NULL,0},
3499 {TRUE}
3503 VARIANT_TRUE,"UTF-16",
3505 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3506 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3507 {TRUE}
3511 VARIANT_TRUE,"UTF-16",
3513 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3514 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3515 {TRUE}
3520 static void test_mxwriter_stream(void)
3522 IMXWriter *writer;
3523 ISAXContentHandler *content;
3524 HRESULT hr;
3525 VARIANT dest;
3526 IStream *stream;
3527 LARGE_INTEGER pos;
3528 ULARGE_INTEGER pos2;
3529 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3531 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3532 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3534 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3535 &IID_IMXWriter, (void**)&writer);
3536 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3538 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3539 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3541 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3542 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3544 V_VT(&dest) = VT_UNKNOWN;
3545 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3546 hr = IMXWriter_put_output(writer, dest);
3547 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3548 VariantClear(&dest);
3550 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3551 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3553 current_write_test = test->expected_writes;
3555 hr = ISAXContentHandler_startDocument(content);
3556 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3558 hr = ISAXContentHandler_endDocument(content);
3559 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3561 ISAXContentHandler_Release(content);
3562 IMXWriter_Release(writer);
3564 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3565 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3568 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3569 &IID_IMXWriter, (void**)&writer);
3570 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3572 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3573 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3575 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3576 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3578 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3579 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3581 V_VT(&dest) = VT_UNKNOWN;
3582 V_UNKNOWN(&dest) = (IUnknown*)stream;
3583 hr = IMXWriter_put_output(writer, dest);
3584 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3586 hr = ISAXContentHandler_startDocument(content);
3587 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3589 /* Setting output of the mxwriter causes the current output to be flushed,
3590 * and the writer to start over.
3592 V_VT(&dest) = VT_EMPTY;
3593 hr = IMXWriter_put_output(writer, dest);
3594 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3596 pos.QuadPart = 0;
3597 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3598 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3599 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3601 hr = ISAXContentHandler_startDocument(content);
3602 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3604 hr = ISAXContentHandler_endDocument(content);
3605 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3607 V_VT(&dest) = VT_EMPTY;
3608 hr = IMXWriter_get_output(writer, &dest);
3609 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3610 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3611 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3612 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3613 VariantClear(&dest);
3615 /* test when BOM is written to output stream */
3616 V_VT(&dest) = VT_EMPTY;
3617 hr = IMXWriter_put_output(writer, dest);
3618 EXPECT_HR(hr, S_OK);
3620 pos.QuadPart = 0;
3621 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3622 EXPECT_HR(hr, S_OK);
3624 V_VT(&dest) = VT_UNKNOWN;
3625 V_UNKNOWN(&dest) = (IUnknown*)stream;
3626 hr = IMXWriter_put_output(writer, dest);
3627 EXPECT_HR(hr, S_OK);
3629 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3630 EXPECT_HR(hr, S_OK);
3632 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3633 EXPECT_HR(hr, S_OK);
3635 hr = ISAXContentHandler_startDocument(content);
3636 EXPECT_HR(hr, S_OK);
3638 pos.QuadPart = 0;
3639 pos2.QuadPart = 0;
3640 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3641 EXPECT_HR(hr, S_OK);
3642 ok(pos2.QuadPart == 2, "got wrong position\n");
3644 ISAXContentHandler_Release(content);
3645 IMXWriter_Release(writer);
3647 free_bstrs();
3650 static const char *encoding_names[] = {
3651 "iso-8859-1",
3652 "iso-8859-2",
3653 "iso-8859-3",
3654 "iso-8859-4",
3655 "iso-8859-5",
3656 "iso-8859-7",
3657 "iso-8859-9",
3658 "iso-8859-13",
3659 "iso-8859-15",
3660 NULL
3663 static void test_mxwriter_encoding(void)
3665 ISAXContentHandler *content;
3666 IMXWriter *writer;
3667 IStream *stream;
3668 const char *enc;
3669 VARIANT dest;
3670 HRESULT hr;
3671 HGLOBAL g;
3672 char *ptr;
3673 BSTR s;
3674 int i;
3676 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3677 &IID_IMXWriter, (void**)&writer);
3678 EXPECT_HR(hr, S_OK);
3680 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3681 EXPECT_HR(hr, S_OK);
3683 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3684 EXPECT_HR(hr, S_OK);
3686 hr = ISAXContentHandler_startDocument(content);
3687 EXPECT_HR(hr, S_OK);
3689 hr = ISAXContentHandler_endDocument(content);
3690 EXPECT_HR(hr, S_OK);
3692 /* The content is always re-encoded to UTF-16 when the output is
3693 * retrieved as a BSTR.
3695 V_VT(&dest) = VT_EMPTY;
3696 hr = IMXWriter_get_output(writer, &dest);
3697 EXPECT_HR(hr, S_OK);
3698 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3699 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3700 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3701 VariantClear(&dest);
3703 /* switch encoding when something is written already */
3704 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3705 EXPECT_HR(hr, S_OK);
3707 V_VT(&dest) = VT_UNKNOWN;
3708 V_UNKNOWN(&dest) = (IUnknown*)stream;
3709 hr = IMXWriter_put_output(writer, dest);
3710 EXPECT_HR(hr, S_OK);
3712 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3713 EXPECT_HR(hr, S_OK);
3715 /* write empty element */
3716 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3717 EXPECT_HR(hr, S_OK);
3719 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3720 EXPECT_HR(hr, S_OK);
3722 /* switch */
3723 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3724 EXPECT_HR(hr, S_OK);
3726 hr = IMXWriter_flush(writer);
3727 EXPECT_HR(hr, S_OK);
3729 hr = GetHGlobalFromStream(stream, &g);
3730 EXPECT_HR(hr, S_OK);
3732 ptr = GlobalLock(g);
3733 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3734 GlobalUnlock(g);
3736 /* so output is unaffected, encoding name is stored however */
3737 hr = IMXWriter_get_encoding(writer, &s);
3738 EXPECT_HR(hr, S_OK);
3739 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3740 SysFreeString(s);
3742 IStream_Release(stream);
3744 i = 0;
3745 enc = encoding_names[i];
3746 while (enc)
3748 char expectedA[200];
3750 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3751 EXPECT_HR(hr, S_OK);
3753 V_VT(&dest) = VT_UNKNOWN;
3754 V_UNKNOWN(&dest) = (IUnknown*)stream;
3755 hr = IMXWriter_put_output(writer, dest);
3756 EXPECT_HR(hr, S_OK);
3758 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
3759 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
3760 "%s: encoding not accepted\n", enc);
3761 if (hr != S_OK)
3763 enc = encoding_names[++i];
3764 IStream_Release(stream);
3765 continue;
3768 hr = ISAXContentHandler_startDocument(content);
3769 EXPECT_HR(hr, S_OK);
3771 hr = ISAXContentHandler_endDocument(content);
3772 EXPECT_HR(hr, S_OK);
3774 hr = IMXWriter_flush(writer);
3775 EXPECT_HR(hr, S_OK);
3777 /* prepare expected string */
3778 *expectedA = 0;
3779 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
3780 strcat(expectedA, enc);
3781 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
3783 hr = GetHGlobalFromStream(stream, &g);
3784 EXPECT_HR(hr, S_OK);
3786 ptr = GlobalLock(g);
3787 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
3788 GlobalUnlock(g);
3790 V_VT(&dest) = VT_EMPTY;
3791 hr = IMXWriter_put_output(writer, dest);
3792 EXPECT_HR(hr, S_OK);
3794 IStream_Release(stream);
3796 enc = encoding_names[++i];
3799 ISAXContentHandler_Release(content);
3800 IMXWriter_Release(writer);
3802 free_bstrs();
3805 static void test_obj_dispex(IUnknown *obj)
3807 static const WCHAR starW[] = {'*',0};
3808 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
3809 IDispatchEx *dispex;
3810 IUnknown *unk;
3811 DWORD props;
3812 UINT ticnt;
3813 HRESULT hr;
3814 BSTR name;
3816 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
3817 EXPECT_HR(hr, S_OK);
3818 if (FAILED(hr)) return;
3820 ticnt = 0;
3821 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
3822 EXPECT_HR(hr, S_OK);
3823 ok(ticnt == 1, "ticnt=%u\n", ticnt);
3825 name = SysAllocString(starW);
3826 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
3827 EXPECT_HR(hr, E_NOTIMPL);
3828 SysFreeString(name);
3830 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
3831 EXPECT_HR(hr, E_NOTIMPL);
3833 props = 0;
3834 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
3835 EXPECT_HR(hr, E_NOTIMPL);
3836 ok(props == 0, "expected 0 got %d\n", props);
3838 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
3839 EXPECT_HR(hr, E_NOTIMPL);
3840 if (SUCCEEDED(hr)) SysFreeString(name);
3842 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
3843 EXPECT_HR(hr, E_NOTIMPL);
3845 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
3846 EXPECT_HR(hr, E_NOTIMPL);
3847 if (hr == S_OK && unk) IUnknown_Release(unk);
3849 IDispatchEx_Release(dispex);
3852 static void test_dispex(void)
3854 IVBSAXXMLReader *vbreader;
3855 ISAXXMLReader *reader;
3856 IUnknown *unk;
3857 HRESULT hr;
3859 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
3860 &IID_ISAXXMLReader, (void**)&reader);
3861 EXPECT_HR(hr, S_OK);
3863 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
3864 EXPECT_HR(hr, S_OK);
3865 test_obj_dispex(unk);
3866 IUnknown_Release(unk);
3868 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
3869 EXPECT_HR(hr, S_OK);
3870 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
3871 EXPECT_HR(hr, S_OK);
3872 test_obj_dispex(unk);
3873 IUnknown_Release(unk);
3874 IVBSAXXMLReader_Release(vbreader);
3876 ISAXXMLReader_Release(reader);
3879 static void test_mxwriter_dispex(void)
3881 IDispatchEx *dispex;
3882 IMXWriter *writer;
3883 IUnknown *unk;
3884 HRESULT hr;
3886 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3887 &IID_IMXWriter, (void**)&writer);
3888 EXPECT_HR(hr, S_OK);
3890 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
3891 EXPECT_HR(hr, S_OK);
3892 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
3893 test_obj_dispex(unk);
3894 IUnknown_Release(unk);
3895 IDispatchEx_Release(dispex);
3897 IMXWriter_Release(writer);
3900 static void test_mxwriter_comment(void)
3902 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
3903 ISAXContentHandler *content;
3904 ISAXLexicalHandler *lexical;
3905 IMXWriter *writer;
3906 VARIANT dest;
3907 HRESULT hr;
3909 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3910 &IID_IMXWriter, (void**)&writer);
3911 EXPECT_HR(hr, S_OK);
3913 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3914 EXPECT_HR(hr, S_OK);
3916 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3917 EXPECT_HR(hr, S_OK);
3919 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3920 EXPECT_HR(hr, S_OK);
3922 hr = ISAXContentHandler_startDocument(content);
3923 EXPECT_HR(hr, S_OK);
3925 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
3926 EXPECT_HR(hr, E_INVALIDARG);
3928 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
3929 EXPECT_HR(hr, S_OK);
3931 V_VT(&dest) = VT_EMPTY;
3932 hr = IMXWriter_get_output(writer, &dest);
3933 EXPECT_HR(hr, S_OK);
3934 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3935 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3936 VariantClear(&dest);
3938 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
3939 EXPECT_HR(hr, S_OK);
3941 V_VT(&dest) = VT_EMPTY;
3942 hr = IMXWriter_get_output(writer, &dest);
3943 EXPECT_HR(hr, S_OK);
3944 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3945 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3946 VariantClear(&dest);
3948 ISAXContentHandler_Release(content);
3949 ISAXLexicalHandler_Release(lexical);
3950 IMXWriter_Release(writer);
3951 free_bstrs();
3954 static void test_mxwriter_cdata(void)
3956 ISAXContentHandler *content;
3957 ISAXLexicalHandler *lexical;
3958 IMXWriter *writer;
3959 VARIANT dest;
3960 HRESULT hr;
3962 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3963 &IID_IMXWriter, (void**)&writer);
3964 EXPECT_HR(hr, S_OK);
3966 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3967 EXPECT_HR(hr, S_OK);
3969 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3970 EXPECT_HR(hr, S_OK);
3972 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3973 EXPECT_HR(hr, S_OK);
3975 hr = ISAXContentHandler_startDocument(content);
3976 EXPECT_HR(hr, S_OK);
3978 hr = ISAXLexicalHandler_startCDATA(lexical);
3979 EXPECT_HR(hr, S_OK);
3981 V_VT(&dest) = VT_EMPTY;
3982 hr = IMXWriter_get_output(writer, &dest);
3983 EXPECT_HR(hr, S_OK);
3984 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3985 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3986 VariantClear(&dest);
3988 hr = ISAXLexicalHandler_startCDATA(lexical);
3989 EXPECT_HR(hr, S_OK);
3991 /* all these are escaped for text nodes */
3992 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
3993 EXPECT_HR(hr, S_OK);
3995 hr = ISAXLexicalHandler_endCDATA(lexical);
3996 EXPECT_HR(hr, S_OK);
3998 V_VT(&dest) = VT_EMPTY;
3999 hr = IMXWriter_get_output(writer, &dest);
4000 EXPECT_HR(hr, S_OK);
4001 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4002 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4003 VariantClear(&dest);
4005 ISAXContentHandler_Release(content);
4006 ISAXLexicalHandler_Release(lexical);
4007 IMXWriter_Release(writer);
4008 free_bstrs();
4011 static void test_mxwriter_pi(void)
4013 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4014 static const WCHAR dataW[] = {'d','a','t','a',0};
4015 ISAXContentHandler *content;
4016 IMXWriter *writer;
4017 VARIANT dest;
4018 HRESULT hr;
4020 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4021 &IID_IMXWriter, (void**)&writer);
4022 EXPECT_HR(hr, S_OK);
4024 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4025 EXPECT_HR(hr, S_OK);
4027 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4028 EXPECT_HR(hr, E_INVALIDARG);
4030 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4031 EXPECT_HR(hr, S_OK);
4033 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4034 EXPECT_HR(hr, S_OK);
4036 V_VT(&dest) = VT_EMPTY;
4037 hr = IMXWriter_get_output(writer, &dest);
4038 EXPECT_HR(hr, S_OK);
4039 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4040 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4041 VariantClear(&dest);
4043 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4044 EXPECT_HR(hr, S_OK);
4046 V_VT(&dest) = VT_EMPTY;
4047 hr = IMXWriter_get_output(writer, &dest);
4048 EXPECT_HR(hr, S_OK);
4049 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4050 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)));
4051 VariantClear(&dest);
4053 V_VT(&dest) = VT_EMPTY;
4054 hr = IMXWriter_put_output(writer, dest);
4055 EXPECT_HR(hr, S_OK);
4057 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4058 EXPECT_HR(hr, S_OK);
4060 V_VT(&dest) = VT_EMPTY;
4061 hr = IMXWriter_get_output(writer, &dest);
4062 EXPECT_HR(hr, S_OK);
4063 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4064 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4065 VariantClear(&dest);
4068 ISAXContentHandler_Release(content);
4069 IMXWriter_Release(writer);
4072 static void test_mxwriter_ignorablespaces(void)
4074 static const WCHAR dataW[] = {'d','a','t','a',0};
4075 ISAXContentHandler *content;
4076 IMXWriter *writer;
4077 VARIANT dest;
4078 HRESULT hr;
4080 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4081 &IID_IMXWriter, (void**)&writer);
4082 EXPECT_HR(hr, S_OK);
4084 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4085 EXPECT_HR(hr, S_OK);
4087 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4088 EXPECT_HR(hr, E_INVALIDARG);
4090 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4091 EXPECT_HR(hr, S_OK);
4093 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4094 EXPECT_HR(hr, S_OK);
4096 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4097 EXPECT_HR(hr, S_OK);
4099 V_VT(&dest) = VT_EMPTY;
4100 hr = IMXWriter_get_output(writer, &dest);
4101 EXPECT_HR(hr, S_OK);
4102 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4103 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4104 VariantClear(&dest);
4106 ISAXContentHandler_Release(content);
4107 IMXWriter_Release(writer);
4110 static void test_mxwriter_dtd(void)
4112 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4113 static const WCHAR nameW[] = {'n','a','m','e'};
4114 static const WCHAR pubW[] = {'p','u','b'};
4115 static const WCHAR sysW[] = {'s','y','s'};
4116 ISAXContentHandler *content;
4117 ISAXLexicalHandler *lexical;
4118 ISAXDeclHandler *decl;
4119 IMXWriter *writer;
4120 VARIANT dest;
4121 HRESULT hr;
4123 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4124 &IID_IMXWriter, (void**)&writer);
4125 EXPECT_HR(hr, S_OK);
4127 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4128 EXPECT_HR(hr, S_OK);
4130 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4131 EXPECT_HR(hr, S_OK);
4133 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4134 EXPECT_HR(hr, S_OK);
4136 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4137 EXPECT_HR(hr, S_OK);
4139 hr = ISAXContentHandler_startDocument(content);
4140 EXPECT_HR(hr, S_OK);
4142 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4143 EXPECT_HR(hr, E_INVALIDARG);
4145 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4146 EXPECT_HR(hr, E_INVALIDARG);
4148 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4149 EXPECT_HR(hr, E_INVALIDARG);
4151 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4152 EXPECT_HR(hr, E_INVALIDARG);
4154 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4155 EXPECT_HR(hr, S_OK);
4157 V_VT(&dest) = VT_EMPTY;
4158 hr = IMXWriter_get_output(writer, &dest);
4159 EXPECT_HR(hr, S_OK);
4160 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4161 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4162 VariantClear(&dest);
4164 /* system id is required if public is present */
4165 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4166 EXPECT_HR(hr, E_INVALIDARG);
4168 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4169 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4170 EXPECT_HR(hr, S_OK);
4172 V_VT(&dest) = VT_EMPTY;
4173 hr = IMXWriter_get_output(writer, &dest);
4174 EXPECT_HR(hr, S_OK);
4175 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4176 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4177 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4178 VariantClear(&dest);
4180 hr = ISAXLexicalHandler_endDTD(lexical);
4181 EXPECT_HR(hr, S_OK);
4183 hr = ISAXLexicalHandler_endDTD(lexical);
4184 EXPECT_HR(hr, S_OK);
4186 V_VT(&dest) = VT_EMPTY;
4187 hr = IMXWriter_get_output(writer, &dest);
4188 EXPECT_HR(hr, S_OK);
4189 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4190 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4191 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4192 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4193 VariantClear(&dest);
4195 /* element declaration */
4196 V_VT(&dest) = VT_EMPTY;
4197 hr = IMXWriter_put_output(writer, dest);
4198 EXPECT_HR(hr, S_OK);
4200 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4201 EXPECT_HR(hr, E_INVALIDARG);
4203 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4204 EXPECT_HR(hr, E_INVALIDARG);
4206 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4207 EXPECT_HR(hr, S_OK);
4209 V_VT(&dest) = VT_EMPTY;
4210 hr = IMXWriter_get_output(writer, &dest);
4211 EXPECT_HR(hr, S_OK);
4212 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4213 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4214 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4215 VariantClear(&dest);
4217 V_VT(&dest) = VT_EMPTY;
4218 hr = IMXWriter_put_output(writer, dest);
4219 EXPECT_HR(hr, S_OK);
4221 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4222 EXPECT_HR(hr, S_OK);
4224 V_VT(&dest) = VT_EMPTY;
4225 hr = IMXWriter_get_output(writer, &dest);
4226 EXPECT_HR(hr, S_OK);
4227 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4228 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4229 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4230 VariantClear(&dest);
4232 ISAXContentHandler_Release(content);
4233 ISAXLexicalHandler_Release(lexical);
4234 ISAXDeclHandler_Release(decl);
4235 IMXWriter_Release(writer);
4236 free_bstrs();
4239 typedef struct {
4240 const CLSID *clsid;
4241 const char *uri;
4242 const char *local;
4243 const char *qname;
4244 const char *type;
4245 const char *value;
4246 HRESULT hr;
4247 } addattribute_test_t;
4249 static const addattribute_test_t addattribute_data[] = {
4250 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4251 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4252 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4253 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4255 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4256 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4257 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4258 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4260 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4261 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4262 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4263 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4265 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4266 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4267 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4268 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4270 { NULL }
4273 static void test_mxattr_addAttribute(void)
4275 const addattribute_test_t *table = addattribute_data;
4276 int i = 0;
4278 while (table->clsid)
4280 ISAXAttributes *saxattr;
4281 IMXAttributes *mxattr;
4282 const WCHAR *value;
4283 int len, index;
4284 HRESULT hr;
4286 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4288 table++;
4289 i++;
4290 continue;
4293 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4294 &IID_IMXAttributes, (void**)&mxattr);
4295 EXPECT_HR(hr, S_OK);
4297 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4298 EXPECT_HR(hr, S_OK);
4300 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4301 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4302 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4304 hr = ISAXAttributes_getLength(saxattr, NULL);
4305 EXPECT_HR(hr, E_POINTER);
4308 len = -1;
4309 hr = ISAXAttributes_getLength(saxattr, &len);
4310 EXPECT_HR(hr, S_OK);
4311 ok(len == 0, "got %d\n", len);
4313 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4314 EXPECT_HR(hr, E_INVALIDARG);
4316 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4317 EXPECT_HR(hr, E_INVALIDARG);
4319 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4320 EXPECT_HR(hr, E_INVALIDARG);
4322 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4323 EXPECT_HR(hr, E_INVALIDARG);
4325 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4326 EXPECT_HR(hr, E_INVALIDARG);
4328 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4329 EXPECT_HR(hr, E_INVALIDARG);
4331 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4332 EXPECT_HR(hr, E_INVALIDARG);
4334 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4335 EXPECT_HR(hr, E_INVALIDARG);
4337 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4338 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4339 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4341 if (hr == S_OK)
4343 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4344 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4345 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4347 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4348 EXPECT_HR(hr, E_POINTER);
4350 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4351 EXPECT_HR(hr, E_POINTER);
4353 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4354 EXPECT_HR(hr, E_POINTER);
4356 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4357 EXPECT_HR(hr, E_POINTER);
4359 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4360 EXPECT_HR(hr, E_POINTER);
4362 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4363 EXPECT_HR(hr, E_POINTER);
4366 len = -1;
4367 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4368 EXPECT_HR(hr, S_OK);
4369 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4370 table->value);
4371 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4373 len = -1;
4374 value = (void*)0xdeadbeef;
4375 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4376 EXPECT_HR(hr, S_OK);
4378 if (table->type)
4380 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4381 table->type);
4382 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4384 else
4386 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4387 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4390 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4391 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4392 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4394 EXPECT_HR(hr, E_POINTER);
4396 else
4397 EXPECT_HR(hr, E_INVALIDARG);
4399 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4400 EXPECT_HR(hr, E_INVALIDARG);
4402 index = -1;
4403 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4404 EXPECT_HR(hr, E_INVALIDARG);
4405 ok(index == -1, "%d: got wrong index %d\n", i, index);
4407 index = -1;
4408 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4409 EXPECT_HR(hr, E_INVALIDARG);
4410 ok(index == -1, "%d: got wrong index %d\n", i, index);
4412 index = -1;
4413 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4414 EXPECT_HR(hr, S_OK);
4415 ok(index == 0, "%d: got wrong index %d\n", i, index);
4417 index = -1;
4418 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4419 EXPECT_HR(hr, E_INVALIDARG);
4420 ok(index == -1, "%d: got wrong index %d\n", i, index);
4422 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4423 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4425 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4426 EXPECT_HR(hr, E_INVALIDARG);
4428 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4429 EXPECT_HR(hr, E_INVALIDARG);
4431 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4432 EXPECT_HR(hr, E_INVALIDARG);
4434 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4435 EXPECT_HR(hr, E_INVALIDARG);
4437 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4438 EXPECT_HR(hr, E_INVALIDARG);
4440 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4441 EXPECT_HR(hr, E_INVALIDARG);
4443 else
4445 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4446 EXPECT_HR(hr, E_POINTER);
4448 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4449 EXPECT_HR(hr, E_POINTER);
4451 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4452 EXPECT_HR(hr, E_POINTER);
4454 /* versions 4 and 6 crash */
4455 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4456 EXPECT_HR(hr, E_POINTER);
4458 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4459 EXPECT_HR(hr, E_POINTER);
4461 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4462 EXPECT_HR(hr, E_POINTER);
4464 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4465 EXPECT_HR(hr, E_POINTER);
4467 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4468 EXPECT_HR(hr, E_POINTER);
4470 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4471 EXPECT_HR(hr, E_POINTER);
4473 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4474 EXPECT_HR(hr, E_POINTER);
4476 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4477 strlen(table->local), NULL, NULL);
4478 EXPECT_HR(hr, E_POINTER);
4481 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4482 EXPECT_HR(hr, S_OK);
4483 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4484 table->value);
4485 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4487 if (table->uri) {
4488 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4489 _bstr_(table->local), strlen(table->local), &value, &len);
4490 EXPECT_HR(hr, S_OK);
4491 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4492 table->value);
4493 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4497 len = -1;
4498 hr = ISAXAttributes_getLength(saxattr, &len);
4499 EXPECT_HR(hr, S_OK);
4500 if (table->hr == S_OK)
4501 ok(len == 1, "%d: got %d length, expected 0\n", i, len);
4502 else
4503 ok(len == 0, "%d: got %d length, expected 1\n", i, len);
4505 ISAXAttributes_Release(saxattr);
4506 IMXAttributes_Release(mxattr);
4508 table++;
4509 i++;
4512 free_bstrs();
4515 static void test_mxattr_clear(void)
4517 ISAXAttributes *saxattr;
4518 IMXAttributes *mxattr;
4519 const WCHAR *ptr;
4520 HRESULT hr;
4521 int len;
4523 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4524 &IID_IMXAttributes, (void**)&mxattr);
4525 EXPECT_HR(hr, S_OK);
4527 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4528 EXPECT_HR(hr, S_OK);
4530 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4531 EXPECT_HR(hr, E_INVALIDARG);
4533 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4534 EXPECT_HR(hr, E_INVALIDARG);
4536 hr = IMXAttributes_clear(mxattr);
4537 EXPECT_HR(hr, S_OK);
4539 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4540 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4541 EXPECT_HR(hr, S_OK);
4543 len = -1;
4544 hr = ISAXAttributes_getLength(saxattr, &len);
4545 EXPECT_HR(hr, S_OK);
4546 ok(len == 1, "got %d\n", len);
4548 len = -1;
4549 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4550 EXPECT_HR(hr, E_POINTER);
4551 ok(len == -1, "got %d\n", len);
4553 ptr = (void*)0xdeadbeef;
4554 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4555 EXPECT_HR(hr, E_POINTER);
4556 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4558 len = 0;
4559 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4560 EXPECT_HR(hr, S_OK);
4561 ok(len == 5, "got %d\n", len);
4562 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4564 hr = IMXAttributes_clear(mxattr);
4565 EXPECT_HR(hr, S_OK);
4567 len = -1;
4568 hr = ISAXAttributes_getLength(saxattr, &len);
4569 EXPECT_HR(hr, S_OK);
4570 ok(len == 0, "got %d\n", len);
4572 len = -1;
4573 ptr = (void*)0xdeadbeef;
4574 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4575 EXPECT_HR(hr, E_INVALIDARG);
4576 ok(len == -1, "got %d\n", len);
4577 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4579 IMXAttributes_Release(mxattr);
4580 ISAXAttributes_Release(saxattr);
4581 free_bstrs();
4584 static void test_mxattr_dispex(void)
4586 IMXAttributes *mxattr;
4587 IDispatchEx *dispex;
4588 IUnknown *unk;
4589 HRESULT hr;
4591 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4592 &IID_IMXAttributes, (void**)&mxattr);
4593 EXPECT_HR(hr, S_OK);
4595 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4596 EXPECT_HR(hr, S_OK);
4597 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4598 test_obj_dispex(unk);
4599 IUnknown_Release(unk);
4600 IDispatchEx_Release(dispex);
4602 IMXAttributes_Release(mxattr);
4605 static void test_mxattr_qi(void)
4607 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4608 ISAXAttributes *saxattr;
4609 IMXAttributes *mxattr;
4610 HRESULT hr;
4612 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4613 &IID_IMXAttributes, (void**)&mxattr);
4614 EXPECT_HR(hr, S_OK);
4616 EXPECT_REF(mxattr, 1);
4617 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4618 EXPECT_HR(hr, S_OK);
4620 EXPECT_REF(mxattr, 2);
4621 EXPECT_REF(saxattr, 2);
4623 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4624 EXPECT_HR(hr, S_OK);
4626 EXPECT_REF(vbsaxattr, 3);
4627 EXPECT_REF(mxattr, 3);
4628 EXPECT_REF(saxattr, 3);
4630 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4631 EXPECT_HR(hr, S_OK);
4633 EXPECT_REF(vbsaxattr, 4);
4634 EXPECT_REF(mxattr, 4);
4635 EXPECT_REF(saxattr, 4);
4637 IMXAttributes_Release(mxattr);
4638 ISAXAttributes_Release(saxattr);
4639 IVBSAXAttributes_Release(vbsaxattr);
4640 IVBSAXAttributes_Release(vbsaxattr2);
4643 static struct msxmlsupported_data_t saxattr_support_data[] =
4645 { &CLSID_SAXAttributes, "SAXAttributes" },
4646 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4647 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4648 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4649 { NULL }
4652 static void test_mxattr_localname(void)
4654 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4655 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4656 static const WCHAR uri1W[] = {'u','r','i','1',0};
4657 static const WCHAR uriW[] = {'u','r','i',0};
4659 const struct msxmlsupported_data_t *table = saxattr_support_data;
4661 while (table->clsid)
4663 ISAXAttributes *saxattr;
4664 IMXAttributes *mxattr;
4665 HRESULT hr;
4666 int index;
4668 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4670 table++;
4671 continue;
4674 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4675 &IID_IMXAttributes, (void**)&mxattr);
4676 EXPECT_HR(hr, S_OK);
4678 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4679 EXPECT_HR(hr, S_OK);
4681 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4682 EXPECT_HR(hr, E_INVALIDARG);
4684 /* add some ambiguos attribute names */
4685 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4686 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4687 EXPECT_HR(hr, S_OK);
4688 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4689 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4690 EXPECT_HR(hr, S_OK);
4692 index = -1;
4693 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4694 EXPECT_HR(hr, S_OK);
4695 ok(index == 0, "%s: got index %d\n", table->name, index);
4697 index = -1;
4698 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4699 EXPECT_HR(hr, E_INVALIDARG);
4700 ok(index == -1, "%s: got index %d\n", table->name, index);
4702 index = -1;
4703 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4704 EXPECT_HR(hr, E_INVALIDARG);
4705 ok(index == -1, "%s: got index %d\n", table->name, index);
4707 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4708 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4710 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4711 EXPECT_HR(hr, E_POINTER);
4713 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4714 EXPECT_HR(hr, E_POINTER);
4716 else
4718 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4719 EXPECT_HR(hr, E_INVALIDARG);
4721 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4722 EXPECT_HR(hr, E_INVALIDARG);
4725 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
4726 EXPECT_HR(hr, E_INVALIDARG);
4728 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
4729 EXPECT_HR(hr, E_INVALIDARG);
4731 table++;
4733 ISAXAttributes_Release(saxattr);
4734 IMXAttributes_Release(mxattr);
4738 START_TEST(saxreader)
4740 ISAXXMLReader *reader;
4741 HRESULT hr;
4743 hr = CoInitialize(NULL);
4744 ok(hr == S_OK, "failed to init com\n");
4746 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4747 &IID_ISAXXMLReader, (void**)&reader);
4749 if(FAILED(hr))
4751 skip("Failed to create SAXXMLReader instance\n");
4752 CoUninitialize();
4753 return;
4755 ISAXXMLReader_Release(reader);
4757 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4759 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
4761 test_saxreader();
4762 test_saxreader_properties();
4763 test_saxreader_features();
4764 test_saxreader_encoding();
4765 test_dispex();
4767 /* MXXMLWriter tests */
4768 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
4769 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
4771 test_mxwriter_handlers();
4772 test_mxwriter_startenddocument();
4773 test_mxwriter_startendelement();
4774 test_mxwriter_characters();
4775 test_mxwriter_comment();
4776 test_mxwriter_cdata();
4777 test_mxwriter_pi();
4778 test_mxwriter_ignorablespaces();
4779 test_mxwriter_dtd();
4780 test_mxwriter_properties();
4781 test_mxwriter_flush();
4782 test_mxwriter_stream();
4783 test_mxwriter_encoding();
4784 test_mxwriter_dispex();
4786 else
4787 win_skip("MXXMLWriter not supported\n");
4789 /* SAXAttributes tests */
4790 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
4791 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
4793 test_mxattr_qi();
4794 test_mxattr_addAttribute();
4795 test_mxattr_clear();
4796 test_mxattr_localname();
4797 test_mxattr_dispex();
4799 else
4800 skip("SAXAttributes not supported\n");
4802 CoUninitialize();