msxml3: Set namespace-prefixes on by default.
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blobaa3b2a5df6db45fe3053df417321d6ac3b985c75
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 struct msxmlsupported_data_t
51 const GUID *clsid;
52 const char *name;
53 BOOL supported;
56 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
58 while (table->clsid)
60 if (table->clsid == clsid) return table->supported;
61 table++;
63 return FALSE;
66 static BSTR alloc_str_from_narrow(const char *str)
68 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
69 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
70 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
71 return ret;
74 static BSTR alloced_bstrs[512];
75 static int alloced_bstrs_count;
77 static BSTR _bstr_(const char *str)
79 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
80 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
81 return alloced_bstrs[alloced_bstrs_count++];
84 static void free_bstrs(void)
86 int i;
87 for (i = 0; i < alloced_bstrs_count; i++)
88 SysFreeString(alloced_bstrs[i]);
89 alloced_bstrs_count = 0;
92 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, int todo, int *failcount)
94 int len, lenexp, cmp;
95 WCHAR buf[1024];
97 len = SysStringLen(str);
99 if (!expected) {
100 if (str && todo)
102 (*failcount)++;
103 todo_wine
104 ok_(file, line) (!str, "got %p, expected null str\n", str);
106 else
107 ok_(file, line) (!str, "got %p, expected null str\n", str);
109 if (len && todo)
111 (*failcount)++;
112 todo_wine
113 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
115 else
116 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
117 return;
120 lenexp = strlen(expected);
121 if (lenexp != len && todo)
123 (*failcount)++;
124 todo_wine
125 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
127 else
128 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
130 /* exit earlier on length mismatch */
131 if (lenexp != len) return;
133 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
135 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
136 if (cmp && todo)
138 (*failcount)++;
139 todo_wine
140 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
141 wine_dbgstr_wn(str, len), expected);
143 else
144 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
145 wine_dbgstr_wn(str, len), expected);
148 typedef enum _CH {
149 CH_ENDTEST,
150 CH_PUTDOCUMENTLOCATOR,
151 CH_STARTDOCUMENT,
152 CH_ENDDOCUMENT,
153 CH_STARTPREFIXMAPPING,
154 CH_ENDPREFIXMAPPING,
155 CH_STARTELEMENT,
156 CH_ENDELEMENT,
157 CH_CHARACTERS,
158 CH_IGNORABLEWHITESPACE,
159 CH_PROCESSINGINSTRUCTION,
160 CH_SKIPPEDENTITY,
161 EH_ERROR,
162 EH_FATALERROR,
163 EG_IGNORABLEWARNING,
164 EVENT_LAST
165 } CH;
167 static const char *event_names[EVENT_LAST] = {
168 "endtest",
169 "putDocumentLocator",
170 "startDocument",
171 "endDocument",
172 "startPrefixMapping",
173 "endPrefixMapping",
174 "startElement",
175 "endElement",
176 "characters",
177 "ignorableWhitespace",
178 "processingIntruction",
179 "skippedEntity",
180 "error",
181 "fatalError",
182 "ignorableWarning"
185 struct attribute_entry {
186 const char *uri;
187 const char *local;
188 const char *qname;
189 const char *value;
191 /* used for actual call data only, null for expected call data */
192 BSTR uriW;
193 BSTR localW;
194 BSTR qnameW;
195 BSTR valueW;
198 struct call_entry {
199 CH id;
200 int line;
201 int column;
202 HRESULT ret;
203 const char *arg1;
204 const char *arg2;
205 const char *arg3;
207 /* allocated once at startElement callback */
208 struct attribute_entry *attributes;
209 int attr_count;
211 /* used for actual call data only, null for expected call data */
212 BSTR arg1W;
213 BSTR arg2W;
214 BSTR arg3W;
217 struct call_sequence
219 int count;
220 int size;
221 struct call_entry *sequence;
224 #define CONTENT_HANDLER_INDEX 0
225 #define NUM_CALL_SEQUENCES 1
226 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
228 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
230 memset(call, 0, sizeof(*call));
231 ISAXLocator_getLineNumber(locator, &call->line);
232 ISAXLocator_getColumnNumber(locator, &call->column);
235 static void add_call(struct call_sequence **seq, int sequence_index,
236 const struct call_entry *call)
238 struct call_sequence *call_seq = seq[sequence_index];
240 if (!call_seq->sequence)
242 call_seq->size = 10;
243 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
244 call_seq->size * sizeof (struct call_entry));
247 if (call_seq->count == call_seq->size)
249 call_seq->size *= 2;
250 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
251 call_seq->sequence,
252 call_seq->size * sizeof (struct call_entry));
255 assert(call_seq->sequence);
257 call_seq->sequence[call_seq->count].id = call->id;
258 call_seq->sequence[call_seq->count].line = call->line;
259 call_seq->sequence[call_seq->count].column = call->column;
260 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
261 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
262 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
263 call_seq->sequence[call_seq->count].ret = call->ret;
264 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
265 call_seq->sequence[call_seq->count].attributes = call->attributes;
267 call_seq->count++;
270 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
272 int i;
274 struct call_sequence *call_seq = seg[sequence_index];
276 for (i = 0; i < call_seq->count; i++)
278 int j;
280 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
282 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
283 SysFreeString(call_seq->sequence[i].attributes[j].localW);
284 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
287 SysFreeString(call_seq->sequence[i].arg1W);
288 SysFreeString(call_seq->sequence[i].arg2W);
289 SysFreeString(call_seq->sequence[i].arg3W);
292 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
293 call_seq->sequence = NULL;
294 call_seq->count = call_seq->size = 0;
297 static inline void flush_sequences(struct call_sequence **seq, int n)
299 int i;
300 for (i = 0; i < n; i++)
301 flush_sequence(seq, i);
304 static const char *get_event_name(CH event)
306 return event_names[event];
309 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
310 int todo, const char *file, int line, int *failcount)
312 int i, lenexp = 0;
314 /* attribute count is not stored for expected data */
315 if (expected->attributes)
317 struct attribute_entry *ptr = expected->attributes;
318 while (ptr->uri) { lenexp++; ptr++; };
321 /* check count first and exit earlier */
322 if (actual->attr_count != lenexp && todo)
324 (*failcount)++;
325 todo_wine
326 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
327 context, get_event_name(actual->id), lenexp, actual->attr_count);
329 else
330 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
331 context, get_event_name(actual->id), lenexp, actual->attr_count);
333 if (actual->attr_count != lenexp) return;
335 /* now compare all attributes strings */
336 for (i = 0; i < actual->attr_count; i++)
338 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
339 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
340 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
341 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
345 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
346 const struct call_entry *expected, const char *context, int todo,
347 const char *file, int line)
349 struct call_sequence *call_seq = seq[sequence_index];
350 static const struct call_entry end_of_sequence = { CH_ENDTEST };
351 const struct call_entry *actual, *sequence;
352 int failcount = 0;
354 add_call(seq, sequence_index, &end_of_sequence);
356 sequence = call_seq->sequence;
357 actual = sequence;
359 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
361 if (expected->id == actual->id)
363 /* always test position data */
364 if (expected->line != actual->line && todo)
366 todo_wine
368 failcount++;
369 ok_(file, line) (FALSE,
370 "%s: in event %s expecting line %d got %d\n",
371 context, get_event_name(actual->id), expected->line, actual->line);
374 else
376 ok_(file, line) (expected->line == actual->line,
377 "%s: in event %s expecting line %d got %d\n",
378 context, get_event_name(actual->id), expected->line, actual->line);
381 if (expected->column != actual->column && todo)
383 todo_wine
385 failcount++;
386 ok_(file, line) (FALSE,
387 "%s: in event %s expecting column %d got %d\n",
388 context, get_event_name(actual->id), expected->column, actual->column);
391 else
393 ok_(file, line) (expected->column == actual->column,
394 "%s: in event %s expecting column %d got %d\n",
395 context, get_event_name(actual->id), expected->column, actual->column);
398 switch (actual->id)
400 case CH_PUTDOCUMENTLOCATOR:
401 case CH_STARTDOCUMENT:
402 case CH_ENDDOCUMENT:
403 break;
404 case CH_STARTPREFIXMAPPING:
405 /* prefix, uri */
406 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
407 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
408 break;
409 case CH_ENDPREFIXMAPPING:
410 /* prefix */
411 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
412 break;
413 case CH_STARTELEMENT:
414 /* compare attributes */
415 compare_attributes(actual, expected, context, todo, file, line, &failcount);
416 /* fallthrough */
417 case CH_ENDELEMENT:
418 /* uri, localname, qname */
419 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
420 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
421 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
422 break;
423 case CH_CHARACTERS:
424 case CH_IGNORABLEWHITESPACE:
425 /* char data */
426 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
427 break;
428 case CH_PROCESSINGINSTRUCTION:
429 /* target, data */
430 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
431 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
432 break;
433 case CH_SKIPPEDENTITY:
434 /* name */
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
436 break;
437 case EH_FATALERROR:
438 /* test return value only */
439 if (expected->ret != actual->ret && todo)
441 failcount++;
442 ok_(file, line) (FALSE,
443 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
444 context, get_event_name(actual->id), expected->ret, actual->ret);
446 else
447 ok_(file, line) (expected->ret == actual->ret,
448 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
449 context, get_event_name(actual->id), expected->ret, actual->ret);
450 break;
451 case EH_ERROR:
452 case EG_IGNORABLEWARNING:
453 default:
454 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
456 expected++;
457 actual++;
459 else if (todo)
461 failcount++;
462 todo_wine
464 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
465 context, get_event_name(expected->id), get_event_name(actual->id));
468 flush_sequence(seq, sequence_index);
469 return;
471 else
473 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
474 context, get_event_name(expected->id), get_event_name(actual->id));
475 expected++;
476 actual++;
480 if (todo)
482 todo_wine
484 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
486 failcount++;
487 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
488 context, get_event_name(expected->id), get_event_name(actual->id));
492 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
494 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
495 context, get_event_name(expected->id), get_event_name(actual->id));
498 if (todo && !failcount) /* succeeded yet marked todo */
500 todo_wine
502 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
506 flush_sequence(seq, sequence_index);
509 #define ok_sequence(seq, index, exp, contx, todo) \
510 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
512 static void init_call_sequences(struct call_sequence **seq, int n)
514 int i;
516 for (i = 0; i < n; i++)
517 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
520 static const WCHAR szSimpleXML[] = {
521 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
522 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
523 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
524 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
525 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
528 static const WCHAR carriage_ret_test[] = {
529 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
530 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
531 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
532 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
533 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
536 static const WCHAR szUtf16XML[] = {
537 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
538 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
539 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
542 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
544 static const CHAR szUtf8XML[] =
545 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
547 static const char utf8xml2[] =
548 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
550 static const CHAR testXML[] =
551 "<?xml version=\"1.0\" ?>\n"
552 "<BankAccount>\n"
553 " <Number>1234</Number>\n"
554 " <Name>Captain Ahab</Name>\n"
555 "</BankAccount>\n";
557 static const CHAR szTestAttributes[] =
558 "<?xml version=\"1.0\" ?>\n"
559 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
560 "<node1 xmlns:p=\"test\" />"
561 "</document>\n";
563 static struct call_entry content_handler_test1[] = {
564 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
565 { CH_STARTDOCUMENT, 0, 0, S_OK },
566 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
567 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
568 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
569 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
570 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
571 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
572 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
573 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
574 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
575 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
576 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
577 { CH_ENDDOCUMENT, 0, 0, S_OK},
578 { CH_ENDTEST }
581 /* applies to versions 4 and 6 */
582 static struct call_entry content_handler_test1_alternate[] = {
583 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
584 { CH_STARTDOCUMENT, 1, 22, S_OK },
585 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
586 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
587 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
588 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
589 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
590 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
591 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
592 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
593 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
594 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
595 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_ENDDOCUMENT, 6, 0, S_OK },
597 { CH_ENDTEST }
600 static struct call_entry content_handler_test2[] = {
601 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
602 { CH_STARTDOCUMENT, 0, 0, S_OK },
603 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
604 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
605 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
606 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
607 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
608 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
609 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
610 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
611 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
612 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
613 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
614 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
615 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
616 { CH_ENDDOCUMENT, 0, 0, S_OK },
617 { CH_ENDTEST }
620 static struct call_entry content_handler_test2_alternate[] = {
621 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
622 { CH_STARTDOCUMENT, 1, 21, S_OK },
623 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
624 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
625 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
626 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
627 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
628 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
629 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
630 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
631 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
632 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
633 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
634 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
635 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
636 { CH_ENDDOCUMENT, 6, 0, S_OK },
637 { CH_ENDTEST }
640 static struct call_entry content_handler_testerror[] = {
641 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
642 { EH_FATALERROR, 0, 0, E_FAIL },
643 { CH_ENDTEST }
646 static struct call_entry content_handler_testerror_alternate[] = {
647 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
648 { EH_FATALERROR, 1, 0, E_FAIL },
649 { CH_ENDTEST }
652 static struct call_entry content_handler_test_callback_rets[] = {
653 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
654 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
655 { EH_FATALERROR, 0, 0, S_FALSE },
656 { CH_ENDTEST }
659 static struct call_entry content_handler_test_callback_rets_alt[] = {
660 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
661 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
662 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
663 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
664 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
665 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
666 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
667 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
668 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
669 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
670 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
671 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
672 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
673 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
674 { CH_ENDTEST }
677 static struct attribute_entry ch_attributes1[] = {
678 { "", "", "xmlns:test", "prefix_test" },
679 { "", "", "xmlns", "prefix" },
680 { "prefix_test", "arg1", "test:arg1", "arg1" },
681 { "", "arg2", "arg2", "arg2" },
682 { "prefix_test", "ar3", "test:ar3", "arg3" },
683 { NULL }
686 static struct attribute_entry ch_attributes2[] = {
687 { "", "", "xmlns:p", "test" },
688 { NULL }
691 static struct call_entry content_handler_test_attributes[] = {
692 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
693 { CH_STARTDOCUMENT, 0, 0, S_OK },
694 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
695 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
696 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
697 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
698 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
699 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
700 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
701 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
702 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
703 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
704 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
705 { CH_ENDDOCUMENT, 0, 0 },
706 { CH_ENDTEST }
709 static struct attribute_entry ch_attributes_alt_4[] = {
710 { "prefix_test", "arg1", "test:arg1", "arg1" },
711 { "", "arg2", "arg2", "arg2" },
712 { "prefix_test", "ar3", "test:ar3", "arg3" },
713 { "", "", "xmlns:test", "prefix_test" },
714 { "", "", "xmlns", "prefix" },
715 { NULL }
718 static struct call_entry content_handler_test_attributes_alternate_4[] = {
719 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
720 { CH_STARTDOCUMENT, 1, 22, S_OK },
721 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
722 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
723 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
724 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
725 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
726 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
727 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
728 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
729 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
730 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
731 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
732 { CH_ENDDOCUMENT, 4, 0, S_OK },
733 { CH_ENDTEST }
736 static struct attribute_entry ch_attributes_alt_6[] = {
737 { "prefix_test", "arg1", "test:arg1", "arg1" },
738 { "", "arg2", "arg2", "arg2" },
739 { "prefix_test", "ar3", "test:ar3", "arg3" },
740 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
741 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
742 { NULL }
745 static struct attribute_entry ch_attributes2_6[] = {
746 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
747 { NULL }
750 static struct call_entry content_handler_test_attributes_alternate_6[] = {
751 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
752 { CH_STARTDOCUMENT, 1, 22, S_OK },
753 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
754 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
755 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
756 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
757 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
758 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
759 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
760 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
761 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
762 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
763 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
764 { CH_ENDDOCUMENT, 4, 0, S_OK },
765 { CH_ENDTEST }
768 static struct attribute_entry xmlspace_attrs[] = {
769 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
770 { NULL }
773 static struct call_entry xmlspaceattr_test[] = {
774 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
775 { CH_STARTDOCUMENT, 0, 0, S_OK },
776 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
777 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
778 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
779 { CH_ENDDOCUMENT, 0, 0, S_OK },
780 { CH_ENDTEST }
783 static struct call_entry xmlspaceattr_test_alternate[] = {
784 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
785 { CH_STARTDOCUMENT, 1, 39, S_OK },
786 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
787 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
788 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
789 { CH_ENDDOCUMENT, 1, 83, S_OK },
790 { CH_ENDTEST }
793 static const char xmlspace_attr[] =
794 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
795 "<a xml:space=\"preserve\"> Some text data </a>";
797 static struct call_entry *expectCall;
798 static ISAXLocator *locator;
799 int msxml_version;
801 static void set_expected_seq(struct call_entry *expected)
803 expectCall = expected;
806 /* to be called once on each tested callback return */
807 static HRESULT get_expected_ret(void)
809 HRESULT hr = expectCall->ret;
810 if (expectCall->id != CH_ENDTEST) expectCall++;
811 return hr;
814 static HRESULT WINAPI contentHandler_QueryInterface(
815 ISAXContentHandler* iface,
816 REFIID riid,
817 void **ppvObject)
819 *ppvObject = NULL;
821 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
823 *ppvObject = iface;
825 else
827 return E_NOINTERFACE;
830 return S_OK;
833 static ULONG WINAPI contentHandler_AddRef(
834 ISAXContentHandler* iface)
836 return 2;
839 static ULONG WINAPI contentHandler_Release(
840 ISAXContentHandler* iface)
842 return 1;
845 static HRESULT WINAPI contentHandler_putDocumentLocator(
846 ISAXContentHandler* iface,
847 ISAXLocator *pLocator)
849 struct call_entry call;
850 HRESULT hr;
852 locator = pLocator;
854 memset(&call, 0, sizeof(call));
855 init_call_entry(locator, &call);
856 call.id = CH_PUTDOCUMENTLOCATOR;
857 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
859 if (msxml_version >= 6) {
860 ISAXAttributes *attr, *attr1;
861 IMXAttributes *mxattr;
863 EXPECT_REF(pLocator, 1);
864 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
865 EXPECT_HR(hr, S_OK);
866 EXPECT_REF(pLocator, 2);
867 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
868 EXPECT_HR(hr, S_OK);
869 EXPECT_REF(pLocator, 3);
870 ok(attr == attr1, "got %p, %p\n", attr, attr1);
872 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
873 EXPECT_HR(hr, E_NOINTERFACE);
875 ISAXAttributes_Release(attr);
876 ISAXAttributes_Release(attr1);
879 return get_expected_ret();
882 static ISAXAttributes *test_attr_ptr;
883 static HRESULT WINAPI contentHandler_startDocument(
884 ISAXContentHandler* iface)
886 struct call_entry call;
888 init_call_entry(locator, &call);
889 call.id = CH_STARTDOCUMENT;
890 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
892 test_attr_ptr = NULL;
894 return get_expected_ret();
897 static HRESULT WINAPI contentHandler_endDocument(
898 ISAXContentHandler* iface)
900 struct call_entry call;
902 init_call_entry(locator, &call);
903 call.id = CH_ENDDOCUMENT;
904 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
906 return get_expected_ret();
909 static HRESULT WINAPI contentHandler_startPrefixMapping(
910 ISAXContentHandler* iface,
911 const WCHAR *prefix, int prefix_len,
912 const WCHAR *uri, int uri_len)
914 struct call_entry call;
916 init_call_entry(locator, &call);
917 call.id = CH_STARTPREFIXMAPPING;
918 call.arg1W = SysAllocStringLen(prefix, prefix_len);
919 call.arg2W = SysAllocStringLen(uri, uri_len);
920 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
922 return get_expected_ret();
925 static HRESULT WINAPI contentHandler_endPrefixMapping(
926 ISAXContentHandler* iface,
927 const WCHAR *prefix, int len)
929 struct call_entry call;
931 init_call_entry(locator, &call);
932 call.id = CH_ENDPREFIXMAPPING;
933 call.arg1W = SysAllocStringLen(prefix, len);
934 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
936 return get_expected_ret();
939 static HRESULT WINAPI contentHandler_startElement(
940 ISAXContentHandler* iface,
941 const WCHAR *uri, int uri_len,
942 const WCHAR *localname, int local_len,
943 const WCHAR *qname, int qname_len,
944 ISAXAttributes *saxattr)
946 struct call_entry call;
947 IMXAttributes *mxattr;
948 HRESULT hr;
949 int len;
951 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
952 EXPECT_HR(hr, E_NOINTERFACE);
954 init_call_entry(locator, &call);
955 call.id = CH_STARTELEMENT;
956 call.arg1W = SysAllocStringLen(uri, uri_len);
957 call.arg2W = SysAllocStringLen(localname, local_len);
958 call.arg3W = SysAllocStringLen(qname, qname_len);
960 if(!test_attr_ptr)
961 test_attr_ptr = saxattr;
962 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
964 /* store actual attributes */
965 len = 0;
966 hr = ISAXAttributes_getLength(saxattr, &len);
967 EXPECT_HR(hr, S_OK);
969 if (len)
971 int i;
973 struct attribute_entry *attr;
974 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
976 for (i = 0; i < len; i++)
978 const WCHAR *value;
979 int value_len;
981 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
982 &localname, &local_len, &qname, &qname_len);
983 EXPECT_HR(hr, S_OK);
985 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
986 EXPECT_HR(hr, S_OK);
988 attr[i].uriW = SysAllocStringLen(uri, uri_len);
989 attr[i].localW = SysAllocStringLen(localname, local_len);
990 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
991 attr[i].valueW = SysAllocStringLen(value, value_len);
994 call.attributes = attr;
995 call.attr_count = len;
998 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1000 return get_expected_ret();
1003 static HRESULT WINAPI contentHandler_endElement(
1004 ISAXContentHandler* iface,
1005 const WCHAR *uri, int uri_len,
1006 const WCHAR *localname, int local_len,
1007 const WCHAR *qname, int qname_len)
1009 struct call_entry call;
1011 init_call_entry(locator, &call);
1012 call.id = CH_ENDELEMENT;
1013 call.arg1W = SysAllocStringLen(uri, uri_len);
1014 call.arg2W = SysAllocStringLen(localname, local_len);
1015 call.arg3W = SysAllocStringLen(qname, qname_len);
1016 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1018 return get_expected_ret();
1021 static HRESULT WINAPI contentHandler_characters(
1022 ISAXContentHandler* iface,
1023 const WCHAR *chars,
1024 int len)
1026 struct call_entry call;
1028 init_call_entry(locator, &call);
1029 call.id = CH_CHARACTERS;
1030 call.arg1W = SysAllocStringLen(chars, len);
1031 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1033 return get_expected_ret();
1036 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1037 ISAXContentHandler* iface,
1038 const WCHAR *chars, int len)
1040 struct call_entry call;
1042 init_call_entry(locator, &call);
1043 call.id = CH_IGNORABLEWHITESPACE;
1044 call.arg1W = SysAllocStringLen(chars, len);
1045 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1047 return get_expected_ret();
1050 static HRESULT WINAPI contentHandler_processingInstruction(
1051 ISAXContentHandler* iface,
1052 const WCHAR *target, int target_len,
1053 const WCHAR *data, int data_len)
1055 struct call_entry call;
1057 init_call_entry(locator, &call);
1058 call.id = CH_PROCESSINGINSTRUCTION;
1059 call.arg1W = SysAllocStringLen(target, target_len);
1060 call.arg2W = SysAllocStringLen(data, data_len);
1061 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1063 return get_expected_ret();
1066 static HRESULT WINAPI contentHandler_skippedEntity(
1067 ISAXContentHandler* iface,
1068 const WCHAR *name, int len)
1070 struct call_entry call;
1072 init_call_entry(locator, &call);
1073 call.id = CH_SKIPPEDENTITY;
1074 call.arg1W = SysAllocStringLen(name, len);
1076 return get_expected_ret();
1079 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1081 contentHandler_QueryInterface,
1082 contentHandler_AddRef,
1083 contentHandler_Release,
1084 contentHandler_putDocumentLocator,
1085 contentHandler_startDocument,
1086 contentHandler_endDocument,
1087 contentHandler_startPrefixMapping,
1088 contentHandler_endPrefixMapping,
1089 contentHandler_startElement,
1090 contentHandler_endElement,
1091 contentHandler_characters,
1092 contentHandler_ignorableWhitespace,
1093 contentHandler_processingInstruction,
1094 contentHandler_skippedEntity
1097 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1099 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1100 ISAXErrorHandler* iface,
1101 REFIID riid,
1102 void **ppvObject)
1104 *ppvObject = NULL;
1106 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1108 *ppvObject = iface;
1110 else
1112 return E_NOINTERFACE;
1115 return S_OK;
1118 static ULONG WINAPI isaxerrorHandler_AddRef(
1119 ISAXErrorHandler* iface)
1121 return 2;
1124 static ULONG WINAPI isaxerrorHandler_Release(
1125 ISAXErrorHandler* iface)
1127 return 1;
1130 static HRESULT WINAPI isaxerrorHandler_error(
1131 ISAXErrorHandler* iface,
1132 ISAXLocator *pLocator,
1133 const WCHAR *pErrorMessage,
1134 HRESULT hrErrorCode)
1136 ok(0, "unexpected call\n");
1137 return S_OK;
1140 static HRESULT WINAPI isaxerrorHandler_fatalError(
1141 ISAXErrorHandler* iface,
1142 ISAXLocator *pLocator,
1143 const WCHAR *message,
1144 HRESULT hr)
1146 struct call_entry call;
1148 init_call_entry(locator, &call);
1149 call.id = EH_FATALERROR;
1150 call.ret = hr;
1152 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1154 get_expected_ret();
1155 return S_OK;
1158 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1159 ISAXErrorHandler* iface,
1160 ISAXLocator *pLocator,
1161 const WCHAR *pErrorMessage,
1162 HRESULT hrErrorCode)
1164 ok(0, "unexpected call\n");
1165 return S_OK;
1168 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1170 isaxerrorHandler_QueryInterface,
1171 isaxerrorHandler_AddRef,
1172 isaxerrorHandler_Release,
1173 isaxerrorHandler_error,
1174 isaxerrorHandler_fatalError,
1175 isaxerrorHanddler_ignorableWarning
1178 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1180 static HRESULT WINAPI isaxattributes_QueryInterface(
1181 ISAXAttributes* iface,
1182 REFIID riid,
1183 void **ppvObject)
1185 *ppvObject = NULL;
1187 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1189 *ppvObject = iface;
1191 else
1193 return E_NOINTERFACE;
1196 return S_OK;
1199 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1201 return 2;
1204 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1206 return 1;
1209 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1211 *length = 3;
1212 return S_OK;
1215 static HRESULT WINAPI isaxattributes_getURI(
1216 ISAXAttributes* iface,
1217 int nIndex,
1218 const WCHAR **pUrl,
1219 int *pUriSize)
1221 ok(0, "unexpected call\n");
1222 return E_NOTIMPL;
1225 static HRESULT WINAPI isaxattributes_getLocalName(
1226 ISAXAttributes* iface,
1227 int nIndex,
1228 const WCHAR **pLocalName,
1229 int *pLocalNameLength)
1231 ok(0, "unexpected call\n");
1232 return E_NOTIMPL;
1235 static HRESULT WINAPI isaxattributes_getQName(
1236 ISAXAttributes* iface,
1237 int index,
1238 const WCHAR **QName,
1239 int *QNameLength)
1241 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1242 {'a','t','t','r','2','j','u','n','k',0},
1243 {'a','t','t','r','3',0}};
1244 static const int attrqnamelen[] = {7, 5, 5};
1246 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1248 *QName = attrqnamesW[index];
1249 *QNameLength = attrqnamelen[index];
1251 return S_OK;
1254 static HRESULT WINAPI isaxattributes_getName(
1255 ISAXAttributes* iface,
1256 int nIndex,
1257 const WCHAR **pUri,
1258 int * pUriLength,
1259 const WCHAR ** pLocalName,
1260 int * pLocalNameSize,
1261 const WCHAR ** pQName,
1262 int * pQNameLength)
1264 ok(0, "unexpected call\n");
1265 return E_NOTIMPL;
1268 static HRESULT WINAPI isaxattributes_getIndexFromName(
1269 ISAXAttributes* iface,
1270 const WCHAR * pUri,
1271 int cUriLength,
1272 const WCHAR * pLocalName,
1273 int cocalNameLength,
1274 int * index)
1276 ok(0, "unexpected call\n");
1277 return E_NOTIMPL;
1280 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1281 ISAXAttributes* iface,
1282 const WCHAR * pQName,
1283 int nQNameLength,
1284 int * index)
1286 ok(0, "unexpected call\n");
1287 return E_NOTIMPL;
1290 static HRESULT WINAPI isaxattributes_getType(
1291 ISAXAttributes* iface,
1292 int nIndex,
1293 const WCHAR ** pType,
1294 int * pTypeLength)
1296 ok(0, "unexpected call\n");
1297 return E_NOTIMPL;
1300 static HRESULT WINAPI isaxattributes_getTypeFromName(
1301 ISAXAttributes* iface,
1302 const WCHAR * pUri,
1303 int nUri,
1304 const WCHAR * pLocalName,
1305 int nLocalName,
1306 const WCHAR ** pType,
1307 int * nType)
1309 ok(0, "unexpected call\n");
1310 return E_NOTIMPL;
1313 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1314 ISAXAttributes* iface,
1315 const WCHAR * pQName,
1316 int nQName,
1317 const WCHAR ** pType,
1318 int * nType)
1320 ok(0, "unexpected call\n");
1321 return E_NOTIMPL;
1324 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1325 const WCHAR **value, int *nValue)
1327 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1328 {'a','2','j','u','n','k',0},
1329 {'<','&','"','>',0}};
1330 static const int attrvalueslen[] = {2, 2, 4};
1332 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1334 *value = attrvaluesW[index];
1335 *nValue = attrvalueslen[index];
1337 return S_OK;
1340 static HRESULT WINAPI isaxattributes_getValueFromName(
1341 ISAXAttributes* iface,
1342 const WCHAR * pUri,
1343 int nUri,
1344 const WCHAR * pLocalName,
1345 int nLocalName,
1346 const WCHAR ** pValue,
1347 int * nValue)
1349 ok(0, "unexpected call\n");
1350 return E_NOTIMPL;
1353 static HRESULT WINAPI isaxattributes_getValueFromQName(
1354 ISAXAttributes* iface,
1355 const WCHAR * pQName,
1356 int nQName,
1357 const WCHAR ** pValue,
1358 int * nValue)
1360 ok(0, "unexpected call\n");
1361 return E_NOTIMPL;
1364 static const ISAXAttributesVtbl SAXAttributesVtbl =
1366 isaxattributes_QueryInterface,
1367 isaxattributes_AddRef,
1368 isaxattributes_Release,
1369 isaxattributes_getLength,
1370 isaxattributes_getURI,
1371 isaxattributes_getLocalName,
1372 isaxattributes_getQName,
1373 isaxattributes_getName,
1374 isaxattributes_getIndexFromName,
1375 isaxattributes_getIndexFromQName,
1376 isaxattributes_getType,
1377 isaxattributes_getTypeFromName,
1378 isaxattributes_getTypeFromQName,
1379 isaxattributes_getValue,
1380 isaxattributes_getValueFromName,
1381 isaxattributes_getValueFromQName
1384 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1386 static int handler_addrefcalled;
1388 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **ppvObject)
1390 *ppvObject = NULL;
1392 if(IsEqualGUID(riid, &IID_IUnknown) ||
1393 IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1395 *ppvObject = iface;
1397 else
1399 return E_NOINTERFACE;
1402 return S_OK;
1405 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1407 handler_addrefcalled++;
1408 return 2;
1411 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1413 return 1;
1416 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1417 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1418 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1420 ok(0, "call not expected\n");
1421 return E_NOTIMPL;
1424 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1426 ok(0, "call not expected\n");
1427 return E_NOTIMPL;
1430 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1431 const WCHAR * pName, int nName)
1433 ok(0, "call not expected\n");
1434 return E_NOTIMPL;
1437 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1438 const WCHAR * pName, int nName)
1440 ok(0, "call not expected\n");
1441 return E_NOTIMPL;
1444 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1446 ok(0, "call not expected\n");
1447 return E_NOTIMPL;
1450 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1452 ok(0, "call not expected\n");
1453 return E_NOTIMPL;
1456 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1457 const WCHAR * pChars, int nChars)
1459 ok(0, "call not expected\n");
1460 return E_NOTIMPL;
1463 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1465 isaxlexical_QueryInterface,
1466 isaxlexical_AddRef,
1467 isaxlexical_Release,
1468 isaxlexical_startDTD,
1469 isaxlexical_endDTD,
1470 isaxlexical_startEntity,
1471 isaxlexical_endEntity,
1472 isaxlexical_startCDATA,
1473 isaxlexical_endCDATA,
1474 isaxlexical_comment
1477 static ISAXLexicalHandler saxlexicalhandler = { &SAXLexicalHandlerVtbl };
1479 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **ppvObject)
1481 *ppvObject = NULL;
1483 if(IsEqualGUID(riid, &IID_IUnknown) ||
1484 IsEqualGUID(riid, &IID_ISAXDeclHandler))
1486 *ppvObject = iface;
1488 else
1490 return E_NOINTERFACE;
1493 return S_OK;
1496 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1498 handler_addrefcalled++;
1499 return 2;
1502 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1504 return 1;
1507 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1508 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1510 ok(0, "call not expected\n");
1511 return E_NOTIMPL;
1514 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1515 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1516 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1517 int nValueDefault, const WCHAR * pValue, int nValue)
1519 ok(0, "call not expected\n");
1520 return E_NOTIMPL;
1523 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1524 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1526 ok(0, "call not expected\n");
1527 return E_NOTIMPL;
1530 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1531 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1532 const WCHAR * pSystemId, int nSystemId)
1534 ok(0, "call not expected\n");
1535 return E_NOTIMPL;
1538 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1540 isaxdecl_QueryInterface,
1541 isaxdecl_AddRef,
1542 isaxdecl_Release,
1543 isaxdecl_elementDecl,
1544 isaxdecl_attributeDecl,
1545 isaxdecl_internalEntityDecl,
1546 isaxdecl_externalEntityDecl
1549 static ISAXDeclHandler saxdeclhandler = { &SAXDeclHandlerVtbl };
1551 typedef struct mxwriter_write_test_t {
1552 BOOL last;
1553 const BYTE *data;
1554 DWORD cb;
1555 BOOL null_written;
1556 BOOL fail_write;
1557 } mxwriter_write_test;
1559 typedef struct mxwriter_stream_test_t {
1560 VARIANT_BOOL bom;
1561 const char *encoding;
1562 mxwriter_write_test expected_writes[4];
1563 } mxwriter_stream_test;
1565 static const mxwriter_write_test *current_write_test;
1566 static DWORD current_stream_test_index;
1568 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1570 *ppvObject = NULL;
1572 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1573 *ppvObject = iface;
1574 else
1575 return E_NOINTERFACE;
1577 return S_OK;
1580 static ULONG WINAPI istream_AddRef(IStream *iface)
1582 return 2;
1585 static ULONG WINAPI istream_Release(IStream *iface)
1587 return 1;
1590 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1592 ok(0, "unexpected call\n");
1593 return E_NOTIMPL;
1596 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1598 BOOL fail = FALSE;
1600 ok(pv != NULL, "pv == NULL\n");
1602 if(current_write_test->last) {
1603 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1604 return E_FAIL;
1607 fail = current_write_test->fail_write;
1609 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1610 current_write_test->cb, cb, current_stream_test_index);
1612 if(!pcbWritten)
1613 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1614 else
1615 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1617 ++current_write_test;
1619 if(pcbWritten)
1620 *pcbWritten = cb;
1622 return fail ? E_FAIL : S_OK;
1625 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1626 ULARGE_INTEGER *plibNewPosition)
1628 ok(0, "unexpected call\n");
1629 return E_NOTIMPL;
1632 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1634 ok(0, "unexpected call\n");
1635 return E_NOTIMPL;
1638 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1639 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1641 ok(0, "unexpected call\n");
1642 return E_NOTIMPL;
1645 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1647 ok(0, "unexpected call\n");
1648 return E_NOTIMPL;
1651 static HRESULT WINAPI istream_Revert(IStream *iface)
1653 ok(0, "unexpected call\n");
1654 return E_NOTIMPL;
1657 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1658 ULARGE_INTEGER cb, DWORD dwLockType)
1660 ok(0, "unexpected call\n");
1661 return E_NOTIMPL;
1664 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1665 ULARGE_INTEGER cb, DWORD dwLockType)
1667 ok(0, "unexpected call\n");
1668 return E_NOTIMPL;
1671 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1673 ok(0, "unexpected call\n");
1674 return E_NOTIMPL;
1677 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1679 ok(0, "unexpected call\n");
1680 return E_NOTIMPL;
1683 static const IStreamVtbl StreamVtbl = {
1684 istream_QueryInterface,
1685 istream_AddRef,
1686 istream_Release,
1687 istream_Read,
1688 istream_Write,
1689 istream_Seek,
1690 istream_SetSize,
1691 istream_CopyTo,
1692 istream_Commit,
1693 istream_Revert,
1694 istream_LockRegion,
1695 istream_UnlockRegion,
1696 istream_Stat,
1697 istream_Clone
1700 static IStream mxstream = { &StreamVtbl };
1702 static struct msxmlsupported_data_t reader_support_data[] =
1704 { &CLSID_SAXXMLReader, "SAXReader" },
1705 { &CLSID_SAXXMLReader30, "SAXReader30" },
1706 { &CLSID_SAXXMLReader40, "SAXReader40" },
1707 { &CLSID_SAXXMLReader60, "SAXReader60" },
1708 { NULL }
1711 static void test_saxreader(void)
1713 const struct msxmlsupported_data_t *table = reader_support_data;
1714 HRESULT hr;
1715 ISAXXMLReader *reader = NULL;
1716 VARIANT var;
1717 ISAXContentHandler *content;
1718 ISAXErrorHandler *lpErrorHandler;
1719 SAFEARRAY *sa;
1720 SAFEARRAYBOUND SADim[1];
1721 char *ptr = NULL;
1722 IStream *stream;
1723 ULARGE_INTEGER liSize;
1724 LARGE_INTEGER liPos;
1725 ULONG written;
1726 HANDLE file;
1727 static const CHAR testXmlA[] = "test.xml";
1728 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1729 IXMLDOMDocument *doc;
1730 BSTR str;
1731 VARIANT_BOOL v;
1733 while (table->clsid)
1735 struct call_entry *test_seq;
1737 if (!is_clsid_supported(table->clsid, reader_support_data))
1739 table++;
1740 continue;
1743 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1744 EXPECT_HR(hr, S_OK);
1746 msxml_version = IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ? 6 : 0;
1748 /* crashes on old versions */
1749 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1750 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1752 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1753 EXPECT_HR(hr, E_POINTER);
1755 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1756 EXPECT_HR(hr, E_POINTER);
1759 hr = ISAXXMLReader_getContentHandler(reader, &content);
1760 EXPECT_HR(hr, S_OK);
1761 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1763 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1764 EXPECT_HR(hr, S_OK);
1765 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1767 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1768 EXPECT_HR(hr, S_OK);
1770 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1771 EXPECT_HR(hr, S_OK);
1773 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1774 EXPECT_HR(hr, S_OK);
1776 hr = ISAXXMLReader_getContentHandler(reader, &content);
1777 EXPECT_HR(hr, S_OK);
1778 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1780 V_VT(&var) = VT_BSTR;
1781 V_BSTR(&var) = SysAllocString(szSimpleXML);
1783 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1784 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1785 test_seq = content_handler_test1_alternate;
1786 else
1787 test_seq = content_handler_test1;
1788 set_expected_seq(test_seq);
1789 hr = ISAXXMLReader_parse(reader, var);
1790 EXPECT_HR(hr, S_OK);
1791 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1793 VariantClear(&var);
1795 SADim[0].lLbound = 0;
1796 SADim[0].cElements = sizeof(testXML)-1;
1797 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1798 SafeArrayAccessData(sa, (void**)&ptr);
1799 memcpy(ptr, testXML, sizeof(testXML)-1);
1800 SafeArrayUnaccessData(sa);
1801 V_VT(&var) = VT_ARRAY|VT_UI1;
1802 V_ARRAY(&var) = sa;
1804 set_expected_seq(test_seq);
1805 hr = ISAXXMLReader_parse(reader, var);
1806 EXPECT_HR(hr, S_OK);
1807 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1809 SafeArrayDestroy(sa);
1811 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1812 liSize.QuadPart = strlen(testXML);
1813 IStream_SetSize(stream, liSize);
1814 IStream_Write(stream, testXML, strlen(testXML), &written);
1815 liPos.QuadPart = 0;
1816 IStream_Seek(stream, liPos, STREAM_SEEK_SET, NULL);
1817 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1818 V_UNKNOWN(&var) = (IUnknown*)stream;
1820 set_expected_seq(test_seq);
1821 hr = ISAXXMLReader_parse(reader, var);
1822 EXPECT_HR(hr, S_OK);
1823 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
1825 IStream_Release(stream);
1827 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1828 liSize.QuadPart = strlen(szTestAttributes);
1829 IStream_SetSize(stream, liSize);
1830 IStream_Write(stream, szTestAttributes, strlen(szTestAttributes), &written);
1831 liPos.QuadPart = 0;
1832 IStream_Seek(stream, liPos, STREAM_SEEK_SET, NULL);
1833 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1834 V_UNKNOWN(&var) = (IUnknown*)stream;
1836 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1837 test_seq = content_handler_test_attributes_alternate_4;
1838 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1839 test_seq = content_handler_test_attributes_alternate_6;
1840 else
1841 test_seq = content_handler_test_attributes;
1843 set_expected_seq(test_seq);
1844 hr = ISAXXMLReader_parse(reader, var);
1845 EXPECT_HR(hr, S_OK);
1847 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1848 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1849 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
1850 else
1851 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
1853 IStream_Release(stream);
1855 V_VT(&var) = VT_BSTR;
1856 V_BSTR(&var) = SysAllocString(carriage_ret_test);
1858 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1859 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1860 test_seq = content_handler_test2_alternate;
1861 else
1862 test_seq = content_handler_test2;
1864 set_expected_seq(test_seq);
1865 hr = ISAXXMLReader_parse(reader, var);
1866 EXPECT_HR(hr, S_OK);
1867 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
1869 VariantClear(&var);
1871 /* from file url */
1872 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1873 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
1874 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
1875 CloseHandle(file);
1877 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1878 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1879 test_seq = content_handler_test1_alternate;
1880 else
1881 test_seq = content_handler_test1;
1882 set_expected_seq(test_seq);
1883 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1884 EXPECT_HR(hr, S_OK);
1885 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
1887 /* error handler */
1888 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1889 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1890 test_seq = content_handler_testerror_alternate;
1891 else
1892 test_seq = content_handler_testerror;
1893 set_expected_seq(test_seq);
1894 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1895 EXPECT_HR(hr, E_FAIL);
1896 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
1898 /* callback ret values */
1899 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1900 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1902 test_seq = content_handler_test_callback_rets_alt;
1903 set_expected_seq(test_seq);
1904 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1905 EXPECT_HR(hr, S_OK);
1907 else
1909 test_seq = content_handler_test_callback_rets;
1910 set_expected_seq(test_seq);
1911 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1912 EXPECT_HR(hr, S_FALSE);
1914 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
1916 DeleteFileA(testXmlA);
1918 /* parse from IXMLDOMDocument */
1919 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1920 &IID_IXMLDOMDocument, (void**)&doc);
1921 EXPECT_HR(hr, S_OK);
1923 str = SysAllocString(szSimpleXML);
1924 hr = IXMLDOMDocument_loadXML(doc, str, &v);
1925 EXPECT_HR(hr, S_OK);
1927 V_VT(&var) = VT_UNKNOWN;
1928 V_UNKNOWN(&var) = (IUnknown*)doc;
1930 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1931 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1932 test_seq = content_handler_test2_alternate;
1933 else
1934 test_seq = content_handler_test2;
1936 set_expected_seq(test_seq);
1937 hr = ISAXXMLReader_parse(reader, var);
1938 EXPECT_HR(hr, S_OK);
1939 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
1940 IXMLDOMDocument_Release(doc);
1942 /* xml:space test */
1943 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1944 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1946 test_seq = xmlspaceattr_test_alternate;
1948 else
1949 test_seq = xmlspaceattr_test;
1951 set_expected_seq(test_seq);
1952 V_VT(&var) = VT_BSTR;
1953 V_BSTR(&var) = _bstr_(xmlspace_attr);
1954 hr = ISAXXMLReader_parse(reader, var);
1955 EXPECT_HR(hr, S_OK);
1957 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1958 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1960 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
1962 else
1963 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
1965 ISAXXMLReader_Release(reader);
1966 table++;
1969 return;
1971 ISAXXMLReader_Release(reader);
1972 SysFreeString(str);
1973 free_bstrs();
1976 struct saxreader_props_test_t
1978 const char *prop_name;
1979 IUnknown *iface;
1982 static const struct saxreader_props_test_t props_test_data[] = {
1983 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&saxlexicalhandler },
1984 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&saxdeclhandler },
1985 { 0 }
1988 static void test_saxreader_properties(void)
1990 const struct saxreader_props_test_t *ptr = props_test_data;
1991 ISAXXMLReader *reader;
1992 HRESULT hr;
1994 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
1995 &IID_ISAXXMLReader, (void**)&reader);
1996 EXPECT_HR(hr, S_OK);
1998 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
1999 EXPECT_HR(hr, E_POINTER);
2001 while (ptr->prop_name)
2003 VARIANT v;
2005 V_VT(&v) = VT_EMPTY;
2006 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2007 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2008 EXPECT_HR(hr, S_OK);
2009 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2010 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2012 V_VT(&v) = VT_UNKNOWN;
2013 V_UNKNOWN(&v) = ptr->iface;
2014 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2015 EXPECT_HR(hr, S_OK);
2017 V_VT(&v) = VT_EMPTY;
2018 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2019 handler_addrefcalled = 0;
2020 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2021 EXPECT_HR(hr, S_OK);
2022 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2023 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2024 ok(handler_addrefcalled == 1, "AddRef called %d times\n", handler_addrefcalled);
2025 VariantClear(&v);
2027 V_VT(&v) = VT_EMPTY;
2028 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2029 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2030 EXPECT_HR(hr, S_OK);
2032 V_VT(&v) = VT_EMPTY;
2033 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2034 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2035 EXPECT_HR(hr, S_OK);
2036 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2037 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2039 V_VT(&v) = VT_UNKNOWN;
2040 V_UNKNOWN(&v) = ptr->iface;
2041 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2042 EXPECT_HR(hr, S_OK);
2044 /* only VT_EMPTY seems to be valid to reset property */
2045 V_VT(&v) = VT_I4;
2046 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2047 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2048 EXPECT_HR(hr, E_INVALIDARG);
2050 V_VT(&v) = VT_EMPTY;
2051 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2052 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2053 EXPECT_HR(hr, S_OK);
2054 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2055 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2056 VariantClear(&v);
2058 V_VT(&v) = VT_UNKNOWN;
2059 V_UNKNOWN(&v) = NULL;
2060 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2061 EXPECT_HR(hr, S_OK);
2063 V_VT(&v) = VT_EMPTY;
2064 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2065 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2066 EXPECT_HR(hr, S_OK);
2067 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2068 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2070 ptr++;
2073 ISAXXMLReader_Release(reader);
2074 free_bstrs();
2077 struct feature_ns_entry_t {
2078 const GUID *guid;
2079 const char *clsid;
2080 VARIANT_BOOL value;
2083 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2084 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE },
2085 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE },
2086 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE },
2087 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE },
2088 { 0 }
2091 static void test_saxreader_features(void)
2093 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2094 ISAXXMLReader *reader;
2096 while (entry->guid)
2098 VARIANT_BOOL value;
2099 HRESULT hr;
2101 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2102 if (hr != S_OK)
2104 win_skip("can't create %s instance\n", entry->clsid);
2105 entry++;
2106 continue;
2109 value = 0xc;
2110 hr = ISAXXMLReader_getFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), &value);
2111 EXPECT_HR(hr, S_OK);
2112 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2114 value = 0xc;
2115 hr = ISAXXMLReader_getFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), &value);
2116 EXPECT_HR(hr, S_OK);
2117 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2119 ISAXXMLReader_Release(reader);
2121 entry++;
2125 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2126 static const CHAR UTF8BOMTest[] =
2127 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2128 "<a></a>\n";
2130 struct enc_test_entry_t {
2131 const GUID *guid;
2132 const char *clsid;
2133 const char *data;
2134 HRESULT hr;
2135 int todo;
2138 static const struct enc_test_entry_t encoding_test_data[] = {
2139 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2140 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2141 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2142 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2143 { 0 }
2146 static void test_encoding(void)
2148 const struct enc_test_entry_t *entry = encoding_test_data;
2149 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2150 static const CHAR testXmlA[] = "test.xml";
2151 ISAXXMLReader *reader;
2152 DWORD written;
2153 HANDLE file;
2154 HRESULT hr;
2156 while (entry->guid)
2158 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2159 if (hr != S_OK)
2161 win_skip("can't create %s instance\n", entry->clsid);
2162 entry++;
2163 continue;
2166 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2167 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2168 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2169 CloseHandle(file);
2171 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2172 if (entry->todo)
2173 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2174 else
2175 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2177 DeleteFileA(testXmlA);
2178 ISAXXMLReader_Release(reader);
2180 entry++;
2184 static void test_mxwriter_handlers(void)
2186 ISAXContentHandler *handler;
2187 IMXWriter *writer, *writer2;
2188 ISAXDeclHandler *decl;
2189 ISAXLexicalHandler *lh;
2190 HRESULT hr;
2192 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2193 &IID_IMXWriter, (void**)&writer);
2194 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2196 EXPECT_REF(writer, 1);
2198 /* ISAXContentHandler */
2199 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2200 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2201 EXPECT_REF(writer, 2);
2202 EXPECT_REF(handler, 2);
2204 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2205 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2206 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2207 EXPECT_REF(writer, 3);
2208 EXPECT_REF(writer2, 3);
2209 IMXWriter_Release(writer2);
2210 ISAXContentHandler_Release(handler);
2212 /* ISAXLexicalHandler */
2213 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2214 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2215 EXPECT_REF(writer, 2);
2216 EXPECT_REF(lh, 2);
2218 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2219 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2220 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2221 EXPECT_REF(writer, 3);
2222 EXPECT_REF(writer2, 3);
2223 IMXWriter_Release(writer2);
2224 ISAXLexicalHandler_Release(lh);
2226 /* ISAXDeclHandler */
2227 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2228 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2229 EXPECT_REF(writer, 2);
2230 EXPECT_REF(lh, 2);
2232 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2233 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2234 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2235 EXPECT_REF(writer, 3);
2236 EXPECT_REF(writer2, 3);
2237 IMXWriter_Release(writer2);
2238 ISAXDeclHandler_Release(decl);
2240 IMXWriter_Release(writer);
2244 static struct msxmlsupported_data_t mxwriter_support_data[] =
2246 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2247 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2248 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2249 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2250 { NULL }
2253 static struct msxmlsupported_data_t mxattributes_support_data[] =
2255 { &CLSID_SAXAttributes, "SAXAttributes" },
2256 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2257 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2258 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2259 { NULL }
2262 struct mxwriter_props_t
2264 const GUID *clsid;
2265 VARIANT_BOOL bom;
2266 VARIANT_BOOL disable_escape;
2267 VARIANT_BOOL indent;
2268 VARIANT_BOOL omitdecl;
2269 VARIANT_BOOL standalone;
2270 const char *encoding;
2273 static const struct mxwriter_props_t mxwriter_default_props[] =
2275 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2276 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2277 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2278 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2279 { NULL }
2282 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2284 int i = 0;
2286 while (table->clsid)
2288 IMXWriter *writer;
2289 VARIANT_BOOL b;
2290 BSTR encoding;
2291 HRESULT hr;
2293 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2295 table++;
2296 i++;
2297 continue;
2300 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2301 &IID_IMXWriter, (void**)&writer);
2302 EXPECT_HR(hr, S_OK);
2304 b = !table->bom;
2305 hr = IMXWriter_get_byteOrderMark(writer, &b);
2306 EXPECT_HR(hr, S_OK);
2307 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2309 b = !table->disable_escape;
2310 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2311 EXPECT_HR(hr, S_OK);
2312 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2313 table->disable_escape);
2315 b = !table->indent;
2316 hr = IMXWriter_get_indent(writer, &b);
2317 EXPECT_HR(hr, S_OK);
2318 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2320 b = !table->omitdecl;
2321 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2322 EXPECT_HR(hr, S_OK);
2323 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2325 b = !table->standalone;
2326 hr = IMXWriter_get_standalone(writer, &b);
2327 EXPECT_HR(hr, S_OK);
2328 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2330 hr = IMXWriter_get_encoding(writer, &encoding);
2331 EXPECT_HR(hr, S_OK);
2332 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2333 i, wine_dbgstr_w(encoding), table->encoding);
2334 SysFreeString(encoding);
2336 IMXWriter_Release(writer);
2338 table++;
2339 i++;
2343 static void test_mxwriter_properties(void)
2345 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2346 static const WCHAR emptyW[] = {0};
2347 static const WCHAR testW[] = {'t','e','s','t',0};
2348 ISAXContentHandler *content;
2349 IMXWriter *writer;
2350 VARIANT_BOOL b;
2351 HRESULT hr;
2352 BSTR str, str2;
2353 VARIANT dest;
2355 test_mxwriter_default_properties(mxwriter_default_props);
2357 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2358 &IID_IMXWriter, (void**)&writer);
2359 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2361 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2362 ok(hr == E_POINTER, "got %08x\n", hr);
2364 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2365 ok(hr == E_POINTER, "got %08x\n", hr);
2367 hr = IMXWriter_get_indent(writer, NULL);
2368 ok(hr == E_POINTER, "got %08x\n", hr);
2370 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2371 ok(hr == E_POINTER, "got %08x\n", hr);
2373 hr = IMXWriter_get_standalone(writer, NULL);
2374 ok(hr == E_POINTER, "got %08x\n", hr);
2376 /* set and check */
2377 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2378 ok(hr == S_OK, "got %08x\n", hr);
2380 b = VARIANT_FALSE;
2381 hr = IMXWriter_get_standalone(writer, &b);
2382 ok(hr == S_OK, "got %08x\n", hr);
2383 ok(b == VARIANT_TRUE, "got %d\n", b);
2385 hr = IMXWriter_get_encoding(writer, NULL);
2386 EXPECT_HR(hr, E_POINTER);
2388 /* UTF-16 is a default setting apparently */
2389 str = (void*)0xdeadbeef;
2390 hr = IMXWriter_get_encoding(writer, &str);
2391 EXPECT_HR(hr, S_OK);
2392 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2394 str2 = (void*)0xdeadbeef;
2395 hr = IMXWriter_get_encoding(writer, &str2);
2396 ok(hr == S_OK, "got %08x\n", hr);
2397 ok(str != str2, "expected newly allocated, got same %p\n", str);
2399 SysFreeString(str2);
2400 SysFreeString(str);
2402 /* put empty string */
2403 str = SysAllocString(emptyW);
2404 hr = IMXWriter_put_encoding(writer, str);
2405 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2406 SysFreeString(str);
2408 str = (void*)0xdeadbeef;
2409 hr = IMXWriter_get_encoding(writer, &str);
2410 EXPECT_HR(hr, S_OK);
2411 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2412 SysFreeString(str);
2414 /* invalid encoding name */
2415 str = SysAllocString(testW);
2416 hr = IMXWriter_put_encoding(writer, str);
2417 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2418 SysFreeString(str);
2420 /* test case sensivity */
2421 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2422 EXPECT_HR(hr, S_OK);
2423 str = (void*)0xdeadbeef;
2424 hr = IMXWriter_get_encoding(writer, &str);
2425 EXPECT_HR(hr, S_OK);
2426 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2427 SysFreeString(str);
2429 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2430 EXPECT_HR(hr, S_OK);
2431 str = (void*)0xdeadbeef;
2432 hr = IMXWriter_get_encoding(writer, &str);
2433 EXPECT_HR(hr, S_OK);
2434 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2435 SysFreeString(str);
2437 /* how it affects document creation */
2438 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2439 EXPECT_HR(hr, S_OK);
2441 hr = ISAXContentHandler_startDocument(content);
2442 EXPECT_HR(hr, S_OK);
2443 hr = ISAXContentHandler_endDocument(content);
2444 EXPECT_HR(hr, S_OK);
2446 V_VT(&dest) = VT_EMPTY;
2447 hr = IMXWriter_get_output(writer, &dest);
2448 EXPECT_HR(hr, S_OK);
2449 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2450 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2451 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2452 VariantClear(&dest);
2453 ISAXContentHandler_Release(content);
2455 hr = IMXWriter_get_version(writer, NULL);
2456 ok(hr == E_POINTER, "got %08x\n", hr);
2457 /* default version is 'surprisingly' 1.0 */
2458 hr = IMXWriter_get_version(writer, &str);
2459 ok(hr == S_OK, "got %08x\n", hr);
2460 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2461 SysFreeString(str);
2463 /* store version string as is */
2464 hr = IMXWriter_put_version(writer, NULL);
2465 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2467 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2468 ok(hr == S_OK, "got %08x\n", hr);
2470 hr = IMXWriter_put_version(writer, _bstr_(""));
2471 ok(hr == S_OK, "got %08x\n", hr);
2472 hr = IMXWriter_get_version(writer, &str);
2473 ok(hr == S_OK, "got %08x\n", hr);
2474 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2475 SysFreeString(str);
2477 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2478 ok(hr == S_OK, "got %08x\n", hr);
2479 hr = IMXWriter_get_version(writer, &str);
2480 ok(hr == S_OK, "got %08x\n", hr);
2481 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2482 SysFreeString(str);
2484 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2485 ok(hr == S_OK, "got %08x\n", hr);
2486 hr = IMXWriter_get_version(writer, &str);
2487 ok(hr == S_OK, "got %08x\n", hr);
2488 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2489 SysFreeString(str);
2491 IMXWriter_Release(writer);
2492 free_bstrs();
2495 static void test_mxwriter_flush(void)
2497 ISAXContentHandler *content;
2498 IMXWriter *writer;
2499 LARGE_INTEGER pos;
2500 ULARGE_INTEGER pos2;
2501 IStream *stream;
2502 VARIANT dest;
2503 HRESULT hr;
2505 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2506 &IID_IMXWriter, (void**)&writer);
2507 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2509 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2510 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2511 EXPECT_REF(stream, 1);
2513 /* detach when nothing was attached */
2514 V_VT(&dest) = VT_EMPTY;
2515 hr = IMXWriter_put_output(writer, dest);
2516 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2518 /* attach stream */
2519 V_VT(&dest) = VT_UNKNOWN;
2520 V_UNKNOWN(&dest) = (IUnknown*)stream;
2521 hr = IMXWriter_put_output(writer, dest);
2522 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2523 todo_wine EXPECT_REF(stream, 3);
2525 /* detach setting VT_EMPTY destination */
2526 V_VT(&dest) = VT_EMPTY;
2527 hr = IMXWriter_put_output(writer, dest);
2528 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2529 EXPECT_REF(stream, 1);
2531 V_VT(&dest) = VT_UNKNOWN;
2532 V_UNKNOWN(&dest) = (IUnknown*)stream;
2533 hr = IMXWriter_put_output(writer, dest);
2534 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2536 /* flush() doesn't detach a stream */
2537 hr = IMXWriter_flush(writer);
2538 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2539 todo_wine EXPECT_REF(stream, 3);
2541 pos.QuadPart = 0;
2542 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2543 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2544 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2546 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2547 ok(hr == S_OK, "got %08x\n", hr);
2549 hr = ISAXContentHandler_startDocument(content);
2550 ok(hr == S_OK, "got %08x\n", hr);
2552 pos.QuadPart = 0;
2553 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2554 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2555 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2557 /* already started */
2558 hr = ISAXContentHandler_startDocument(content);
2559 ok(hr == S_OK, "got %08x\n", hr);
2561 hr = ISAXContentHandler_endDocument(content);
2562 ok(hr == S_OK, "got %08x\n", hr);
2564 /* flushed on endDocument() */
2565 pos.QuadPart = 0;
2566 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2567 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2568 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2570 ISAXContentHandler_Release(content);
2571 IStream_Release(stream);
2572 IMXWriter_Release(writer);
2575 static void test_mxwriter_startenddocument(void)
2577 ISAXContentHandler *content;
2578 IMXWriter *writer;
2579 VARIANT dest;
2580 HRESULT hr;
2582 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2583 &IID_IMXWriter, (void**)&writer);
2584 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2586 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2587 ok(hr == S_OK, "got %08x\n", hr);
2589 hr = ISAXContentHandler_startDocument(content);
2590 ok(hr == S_OK, "got %08x\n", hr);
2592 hr = ISAXContentHandler_endDocument(content);
2593 ok(hr == S_OK, "got %08x\n", hr);
2595 V_VT(&dest) = VT_EMPTY;
2596 hr = IMXWriter_get_output(writer, &dest);
2597 ok(hr == S_OK, "got %08x\n", hr);
2598 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2599 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2600 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2601 VariantClear(&dest);
2603 /* now try another startDocument */
2604 hr = ISAXContentHandler_startDocument(content);
2605 ok(hr == S_OK, "got %08x\n", hr);
2606 /* and get duplicated prolog */
2607 V_VT(&dest) = VT_EMPTY;
2608 hr = IMXWriter_get_output(writer, &dest);
2609 ok(hr == S_OK, "got %08x\n", hr);
2610 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2611 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
2612 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2613 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2614 VariantClear(&dest);
2616 ISAXContentHandler_Release(content);
2617 IMXWriter_Release(writer);
2619 /* now with omitted declaration */
2620 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2621 &IID_IMXWriter, (void**)&writer);
2622 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2624 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2625 ok(hr == S_OK, "got %08x\n", hr);
2627 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2628 ok(hr == S_OK, "got %08x\n", hr);
2630 hr = ISAXContentHandler_startDocument(content);
2631 ok(hr == S_OK, "got %08x\n", hr);
2633 hr = ISAXContentHandler_endDocument(content);
2634 ok(hr == S_OK, "got %08x\n", hr);
2636 V_VT(&dest) = VT_EMPTY;
2637 hr = IMXWriter_get_output(writer, &dest);
2638 ok(hr == S_OK, "got %08x\n", hr);
2639 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2640 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2641 VariantClear(&dest);
2643 ISAXContentHandler_Release(content);
2644 IMXWriter_Release(writer);
2646 free_bstrs();
2649 enum startendtype
2651 StartElement,
2652 EndElement,
2653 StartEndElement
2656 struct writer_startendelement_t {
2657 const GUID *clsid;
2658 enum startendtype type;
2659 const char *uri;
2660 const char *local_name;
2661 const char *qname;
2662 const char *output;
2663 HRESULT hr;
2664 ISAXAttributes *attr;
2667 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\">";
2668 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\"/>";
2670 static const struct writer_startendelement_t writer_startendelement[] = {
2671 /* 0 */
2672 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2673 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2674 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2675 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
2676 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2677 /* 5 */
2678 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2679 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2680 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
2681 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2682 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2683 /* 10 */
2684 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2685 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
2686 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2687 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2688 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2689 /* 15 */
2690 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
2691 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2692 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2693 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2694 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2695 /* 20 */
2696 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2697 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2698 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2699 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
2700 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2701 /* 25 */
2702 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2703 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2704 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2705 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2706 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2707 /* 30 */
2708 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2709 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2710 /* endElement tests */
2711 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2712 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2713 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2714 /* 35 */
2715 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
2716 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2717 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2718 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2719 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
2720 /* 40 */
2721 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2722 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2723 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2724 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
2725 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2726 /* 45 */
2727 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2728 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2729 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
2730 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2731 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2732 /* 50 */
2733 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2734 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2735 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2736 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2737 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2738 /* 55 */
2739 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
2740 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2741 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2742 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2743 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2744 /* 60 */
2745 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2746 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2747 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2748 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2750 /* with attributes */
2751 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2752 /* 65 */
2753 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2754 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2755 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2756 /* empty elements */
2757 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2758 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2759 /* 70 */
2760 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2761 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2762 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
2763 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
2764 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
2765 /* 75 */
2766 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
2767 { NULL }
2770 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
2772 while (table->clsid)
2774 IUnknown *unk;
2775 HRESULT hr;
2777 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
2778 if (hr == S_OK) IUnknown_Release(unk);
2780 table->supported = hr == S_OK;
2781 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
2783 table++;
2787 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
2789 int i = 0;
2791 while (table->clsid)
2793 ISAXContentHandler *content;
2794 IMXWriter *writer;
2795 HRESULT hr;
2797 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2799 table++;
2800 i++;
2801 continue;
2804 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2805 &IID_IMXWriter, (void**)&writer);
2806 EXPECT_HR(hr, S_OK);
2808 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2809 EXPECT_HR(hr, S_OK);
2811 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2812 EXPECT_HR(hr, S_OK);
2814 hr = ISAXContentHandler_startDocument(content);
2815 EXPECT_HR(hr, S_OK);
2817 if (table->type == StartElement)
2819 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
2820 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
2821 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2823 else if (table->type == EndElement)
2825 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
2826 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
2827 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2829 else
2831 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
2832 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
2833 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2834 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
2835 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
2836 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2839 /* test output */
2840 if (hr == S_OK)
2842 VARIANT dest;
2844 V_VT(&dest) = VT_EMPTY;
2845 hr = IMXWriter_get_output(writer, &dest);
2846 EXPECT_HR(hr, S_OK);
2847 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2848 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
2849 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
2850 VariantClear(&dest);
2853 ISAXContentHandler_Release(content);
2854 IMXWriter_Release(writer);
2856 table++;
2857 i++;
2860 free_bstrs();
2863 static void test_mxwriter_startendelement(void)
2865 ISAXContentHandler *content;
2866 IMXWriter *writer;
2867 VARIANT dest;
2868 HRESULT hr;
2870 test_mxwriter_startendelement_batch(writer_startendelement);
2872 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2873 &IID_IMXWriter, (void**)&writer);
2874 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2876 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2877 ok(hr == S_OK, "got %08x\n", hr);
2879 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2880 ok(hr == S_OK, "got %08x\n", hr);
2882 hr = ISAXContentHandler_startDocument(content);
2883 ok(hr == S_OK, "got %08x\n", hr);
2885 /* all string pointers should be not null */
2886 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
2887 ok(hr == S_OK, "got %08x\n", hr);
2889 V_VT(&dest) = VT_EMPTY;
2890 hr = IMXWriter_get_output(writer, &dest);
2891 ok(hr == S_OK, "got %08x\n", hr);
2892 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2893 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2894 VariantClear(&dest);
2896 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
2897 ok(hr == S_OK, "got %08x\n", hr);
2899 V_VT(&dest) = VT_EMPTY;
2900 hr = IMXWriter_get_output(writer, &dest);
2901 ok(hr == S_OK, "got %08x\n", hr);
2902 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2903 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2904 VariantClear(&dest);
2906 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
2907 EXPECT_HR(hr, E_INVALIDARG);
2909 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
2910 EXPECT_HR(hr, E_INVALIDARG);
2912 /* only local name is an error too */
2913 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
2914 EXPECT_HR(hr, E_INVALIDARG);
2916 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
2917 EXPECT_HR(hr, S_OK);
2919 V_VT(&dest) = VT_EMPTY;
2920 hr = IMXWriter_get_output(writer, &dest);
2921 EXPECT_HR(hr, S_OK);
2922 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2923 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2924 VariantClear(&dest);
2926 hr = ISAXContentHandler_endDocument(content);
2927 EXPECT_HR(hr, S_OK);
2929 V_VT(&dest) = VT_EMPTY;
2930 hr = IMXWriter_put_output(writer, dest);
2931 EXPECT_HR(hr, S_OK);
2933 V_VT(&dest) = VT_EMPTY;
2934 hr = IMXWriter_get_output(writer, &dest);
2935 EXPECT_HR(hr, S_OK);
2936 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2937 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2938 VariantClear(&dest);
2940 hr = ISAXContentHandler_startDocument(content);
2941 EXPECT_HR(hr, S_OK);
2943 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
2944 EXPECT_HR(hr, S_OK);
2946 V_VT(&dest) = VT_EMPTY;
2947 hr = IMXWriter_get_output(writer, &dest);
2948 EXPECT_HR(hr, S_OK);
2949 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2950 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2951 VariantClear(&dest);
2953 ISAXContentHandler_endDocument(content);
2954 IMXWriter_flush(writer);
2956 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
2957 EXPECT_HR(hr, S_OK);
2958 V_VT(&dest) = VT_EMPTY;
2959 hr = IMXWriter_get_output(writer, &dest);
2960 EXPECT_HR(hr, S_OK);
2961 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2962 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2963 VariantClear(&dest);
2965 ISAXContentHandler_Release(content);
2966 IMXWriter_Release(writer);
2967 free_bstrs();
2970 struct writer_characters_t {
2971 const GUID *clsid;
2972 const char *data;
2973 const char *output;
2976 static const struct writer_characters_t writer_characters[] = {
2977 { &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
2978 { &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
2979 { &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
2980 { &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
2981 { NULL }
2984 static void test_mxwriter_characters(void)
2986 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
2987 const struct writer_characters_t *table = writer_characters;
2988 ISAXContentHandler *content;
2989 IMXWriter *writer;
2990 VARIANT dest;
2991 HRESULT hr;
2992 int i = 0;
2994 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2995 &IID_IMXWriter, (void**)&writer);
2996 EXPECT_HR(hr, S_OK);
2998 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2999 EXPECT_HR(hr, S_OK);
3001 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3002 EXPECT_HR(hr, S_OK);
3004 hr = ISAXContentHandler_startDocument(content);
3005 EXPECT_HR(hr, S_OK);
3007 hr = ISAXContentHandler_characters(content, NULL, 0);
3008 EXPECT_HR(hr, E_INVALIDARG);
3010 hr = ISAXContentHandler_characters(content, chardataW, 0);
3011 EXPECT_HR(hr, S_OK);
3013 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3014 EXPECT_HR(hr, S_OK);
3016 V_VT(&dest) = VT_EMPTY;
3017 hr = IMXWriter_get_output(writer, &dest);
3018 EXPECT_HR(hr, S_OK);
3019 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3020 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3021 VariantClear(&dest);
3023 hr = ISAXContentHandler_endDocument(content);
3024 EXPECT_HR(hr, S_OK);
3026 ISAXContentHandler_Release(content);
3027 IMXWriter_Release(writer);
3029 /* try empty characters data to see if element is closed */
3030 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3031 &IID_IMXWriter, (void**)&writer);
3032 EXPECT_HR(hr, S_OK);
3034 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3035 EXPECT_HR(hr, S_OK);
3037 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3038 EXPECT_HR(hr, S_OK);
3040 hr = ISAXContentHandler_startDocument(content);
3041 EXPECT_HR(hr, S_OK);
3043 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3044 EXPECT_HR(hr, S_OK);
3046 hr = ISAXContentHandler_characters(content, chardataW, 0);
3047 EXPECT_HR(hr, S_OK);
3049 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3050 EXPECT_HR(hr, S_OK);
3052 V_VT(&dest) = VT_EMPTY;
3053 hr = IMXWriter_get_output(writer, &dest);
3054 EXPECT_HR(hr, S_OK);
3055 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3056 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3057 VariantClear(&dest);
3059 ISAXContentHandler_Release(content);
3060 IMXWriter_Release(writer);
3062 /* batch tests */
3063 while (table->clsid)
3065 ISAXContentHandler *content;
3066 IMXWriter *writer;
3067 HRESULT hr;
3069 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3071 table++;
3072 i++;
3073 continue;
3076 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3077 &IID_IMXWriter, (void**)&writer);
3078 EXPECT_HR(hr, S_OK);
3080 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3081 EXPECT_HR(hr, S_OK);
3083 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3084 EXPECT_HR(hr, S_OK);
3086 hr = ISAXContentHandler_startDocument(content);
3087 EXPECT_HR(hr, S_OK);
3089 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3090 EXPECT_HR(hr, S_OK);
3092 /* test output */
3093 if (hr == S_OK)
3095 VARIANT dest;
3097 V_VT(&dest) = VT_EMPTY;
3098 hr = IMXWriter_get_output(writer, &dest);
3099 EXPECT_HR(hr, S_OK);
3100 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3101 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3102 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3103 VariantClear(&dest);
3106 table++;
3107 i++;
3110 free_bstrs();
3113 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3115 VARIANT_TRUE,"UTF-16",
3117 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3118 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3119 {TRUE}
3123 VARIANT_FALSE,"UTF-16",
3125 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3126 {TRUE}
3130 VARIANT_TRUE,"UTF-8",
3132 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3133 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3134 * and the writer is released.
3136 {FALSE,NULL,0},
3137 {TRUE}
3141 VARIANT_TRUE,"utf-8",
3143 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3144 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3145 * and the writer is released.
3147 {FALSE,NULL,0},
3148 {TRUE}
3152 VARIANT_TRUE,"UTF-16",
3154 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3155 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3156 {TRUE}
3160 VARIANT_TRUE,"UTF-16",
3162 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3163 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3164 {TRUE}
3169 static void test_mxwriter_stream(void)
3171 IMXWriter *writer;
3172 ISAXContentHandler *content;
3173 HRESULT hr;
3174 VARIANT dest;
3175 IStream *stream;
3176 LARGE_INTEGER pos;
3177 ULARGE_INTEGER pos2;
3178 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3180 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3181 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3183 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3184 &IID_IMXWriter, (void**)&writer);
3185 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3187 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3188 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3190 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3191 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3193 V_VT(&dest) = VT_UNKNOWN;
3194 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3195 hr = IMXWriter_put_output(writer, dest);
3196 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3197 VariantClear(&dest);
3199 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3200 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3202 current_write_test = test->expected_writes;
3204 hr = ISAXContentHandler_startDocument(content);
3205 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3207 hr = ISAXContentHandler_endDocument(content);
3208 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3210 ISAXContentHandler_Release(content);
3211 IMXWriter_Release(writer);
3213 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3214 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3217 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3218 &IID_IMXWriter, (void**)&writer);
3219 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3221 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3222 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3224 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3225 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3227 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3228 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3230 V_VT(&dest) = VT_UNKNOWN;
3231 V_UNKNOWN(&dest) = (IUnknown*)stream;
3232 hr = IMXWriter_put_output(writer, dest);
3233 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3235 hr = ISAXContentHandler_startDocument(content);
3236 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3238 /* Setting output of the mxwriter causes the current output to be flushed,
3239 * and the writer to start over.
3241 V_VT(&dest) = VT_EMPTY;
3242 hr = IMXWriter_put_output(writer, dest);
3243 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3245 pos.QuadPart = 0;
3246 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3247 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3248 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3250 hr = ISAXContentHandler_startDocument(content);
3251 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3253 hr = ISAXContentHandler_endDocument(content);
3254 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3256 V_VT(&dest) = VT_EMPTY;
3257 hr = IMXWriter_get_output(writer, &dest);
3258 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3259 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3260 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3261 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3262 VariantClear(&dest);
3264 /* test when BOM is written to output stream */
3265 V_VT(&dest) = VT_EMPTY;
3266 hr = IMXWriter_put_output(writer, dest);
3267 EXPECT_HR(hr, S_OK);
3269 pos.QuadPart = 0;
3270 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3271 EXPECT_HR(hr, S_OK);
3273 V_VT(&dest) = VT_UNKNOWN;
3274 V_UNKNOWN(&dest) = (IUnknown*)stream;
3275 hr = IMXWriter_put_output(writer, dest);
3276 EXPECT_HR(hr, S_OK);
3278 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3279 EXPECT_HR(hr, S_OK);
3281 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3282 EXPECT_HR(hr, S_OK);
3284 hr = ISAXContentHandler_startDocument(content);
3285 EXPECT_HR(hr, S_OK);
3287 pos.QuadPart = 0;
3288 pos2.QuadPart = 0;
3289 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3290 EXPECT_HR(hr, S_OK);
3291 ok(pos2.QuadPart == 2, "got wrong position\n");
3293 ISAXContentHandler_Release(content);
3294 IMXWriter_Release(writer);
3296 free_bstrs();
3299 static void test_mxwriter_encoding(void)
3301 ISAXContentHandler *content;
3302 IMXWriter *writer;
3303 IStream *stream;
3304 VARIANT dest;
3305 HRESULT hr;
3306 HGLOBAL g;
3307 char *ptr;
3308 BSTR s;
3310 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3311 &IID_IMXWriter, (void**)&writer);
3312 EXPECT_HR(hr, S_OK);
3314 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3315 EXPECT_HR(hr, S_OK);
3317 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3318 EXPECT_HR(hr, S_OK);
3320 hr = ISAXContentHandler_startDocument(content);
3321 EXPECT_HR(hr, S_OK);
3323 hr = ISAXContentHandler_endDocument(content);
3324 EXPECT_HR(hr, S_OK);
3326 /* The content is always re-encoded to UTF-16 when the output is
3327 * retrieved as a BSTR.
3329 V_VT(&dest) = VT_EMPTY;
3330 hr = IMXWriter_get_output(writer, &dest);
3331 EXPECT_HR(hr, S_OK);
3332 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3333 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3334 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3335 VariantClear(&dest);
3337 /* switch encoding when something is written already */
3338 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3339 EXPECT_HR(hr, S_OK);
3341 V_VT(&dest) = VT_UNKNOWN;
3342 V_UNKNOWN(&dest) = (IUnknown*)stream;
3343 hr = IMXWriter_put_output(writer, dest);
3344 EXPECT_HR(hr, S_OK);
3346 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3347 EXPECT_HR(hr, S_OK);
3349 /* write empty element */
3350 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3351 EXPECT_HR(hr, S_OK);
3353 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3354 EXPECT_HR(hr, S_OK);
3356 /* switch */
3357 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3358 EXPECT_HR(hr, S_OK);
3360 hr = IMXWriter_flush(writer);
3361 EXPECT_HR(hr, S_OK);
3363 hr = GetHGlobalFromStream(stream, &g);
3364 EXPECT_HR(hr, S_OK);
3366 ptr = GlobalLock(g);
3367 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3368 GlobalUnlock(g);
3370 /* so output is unaffected, encoding name is stored however */
3371 hr = IMXWriter_get_encoding(writer, &s);
3372 EXPECT_HR(hr, S_OK);
3373 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3374 SysFreeString(s);
3376 IStream_Release(stream);
3378 ISAXContentHandler_Release(content);
3379 IMXWriter_Release(writer);
3381 free_bstrs();
3384 static void test_obj_dispex(IUnknown *obj)
3386 static const WCHAR starW[] = {'*',0};
3387 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
3388 IDispatchEx *dispex;
3389 IUnknown *unk;
3390 DWORD props;
3391 UINT ticnt;
3392 HRESULT hr;
3393 BSTR name;
3395 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
3396 EXPECT_HR(hr, S_OK);
3397 if (FAILED(hr)) return;
3399 ticnt = 0;
3400 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
3401 EXPECT_HR(hr, S_OK);
3402 ok(ticnt == 1, "ticnt=%u\n", ticnt);
3404 name = SysAllocString(starW);
3405 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
3406 EXPECT_HR(hr, E_NOTIMPL);
3407 SysFreeString(name);
3409 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
3410 EXPECT_HR(hr, E_NOTIMPL);
3412 props = 0;
3413 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
3414 EXPECT_HR(hr, E_NOTIMPL);
3415 ok(props == 0, "expected 0 got %d\n", props);
3417 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
3418 EXPECT_HR(hr, E_NOTIMPL);
3419 if (SUCCEEDED(hr)) SysFreeString(name);
3421 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
3422 EXPECT_HR(hr, E_NOTIMPL);
3424 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
3425 EXPECT_HR(hr, E_NOTIMPL);
3426 if (hr == S_OK && unk) IUnknown_Release(unk);
3428 IDispatchEx_Release(dispex);
3431 static void test_dispex(void)
3433 IVBSAXXMLReader *vbreader;
3434 ISAXXMLReader *reader;
3435 IUnknown *unk;
3436 HRESULT hr;
3438 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
3439 &IID_ISAXXMLReader, (void**)&reader);
3440 EXPECT_HR(hr, S_OK);
3442 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
3443 EXPECT_HR(hr, S_OK);
3444 test_obj_dispex(unk);
3445 IUnknown_Release(unk);
3447 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
3448 EXPECT_HR(hr, S_OK);
3449 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
3450 EXPECT_HR(hr, S_OK);
3451 test_obj_dispex(unk);
3452 IUnknown_Release(unk);
3453 IVBSAXXMLReader_Release(vbreader);
3455 ISAXXMLReader_Release(reader);
3458 static void test_mxwriter_dispex(void)
3460 IDispatchEx *dispex;
3461 IMXWriter *writer;
3462 IUnknown *unk;
3463 HRESULT hr;
3465 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3466 &IID_IMXWriter, (void**)&writer);
3467 EXPECT_HR(hr, S_OK);
3469 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
3470 EXPECT_HR(hr, S_OK);
3471 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
3472 test_obj_dispex(unk);
3473 IUnknown_Release(unk);
3474 IDispatchEx_Release(dispex);
3476 IMXWriter_Release(writer);
3479 static void test_mxwriter_comment(void)
3481 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
3482 ISAXContentHandler *content;
3483 ISAXLexicalHandler *lexical;
3484 IMXWriter *writer;
3485 VARIANT dest;
3486 HRESULT hr;
3488 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3489 &IID_IMXWriter, (void**)&writer);
3490 EXPECT_HR(hr, S_OK);
3492 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3493 EXPECT_HR(hr, S_OK);
3495 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3496 EXPECT_HR(hr, S_OK);
3498 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3499 EXPECT_HR(hr, S_OK);
3501 hr = ISAXContentHandler_startDocument(content);
3502 EXPECT_HR(hr, S_OK);
3504 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
3505 EXPECT_HR(hr, E_INVALIDARG);
3507 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
3508 EXPECT_HR(hr, S_OK);
3510 V_VT(&dest) = VT_EMPTY;
3511 hr = IMXWriter_get_output(writer, &dest);
3512 EXPECT_HR(hr, S_OK);
3513 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3514 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3515 VariantClear(&dest);
3517 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
3518 EXPECT_HR(hr, S_OK);
3520 V_VT(&dest) = VT_EMPTY;
3521 hr = IMXWriter_get_output(writer, &dest);
3522 EXPECT_HR(hr, S_OK);
3523 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3524 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3525 VariantClear(&dest);
3527 ISAXContentHandler_Release(content);
3528 ISAXLexicalHandler_Release(lexical);
3529 IMXWriter_Release(writer);
3530 free_bstrs();
3533 static void test_mxwriter_cdata(void)
3535 ISAXContentHandler *content;
3536 ISAXLexicalHandler *lexical;
3537 IMXWriter *writer;
3538 VARIANT dest;
3539 HRESULT hr;
3541 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3542 &IID_IMXWriter, (void**)&writer);
3543 EXPECT_HR(hr, S_OK);
3545 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3546 EXPECT_HR(hr, S_OK);
3548 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3549 EXPECT_HR(hr, S_OK);
3551 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3552 EXPECT_HR(hr, S_OK);
3554 hr = ISAXContentHandler_startDocument(content);
3555 EXPECT_HR(hr, S_OK);
3557 hr = ISAXLexicalHandler_startCDATA(lexical);
3558 EXPECT_HR(hr, S_OK);
3560 V_VT(&dest) = VT_EMPTY;
3561 hr = IMXWriter_get_output(writer, &dest);
3562 EXPECT_HR(hr, S_OK);
3563 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3564 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3565 VariantClear(&dest);
3567 hr = ISAXLexicalHandler_startCDATA(lexical);
3568 EXPECT_HR(hr, S_OK);
3570 /* all these are escaped for text nodes */
3571 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
3572 EXPECT_HR(hr, S_OK);
3574 hr = ISAXLexicalHandler_endCDATA(lexical);
3575 EXPECT_HR(hr, S_OK);
3577 V_VT(&dest) = VT_EMPTY;
3578 hr = IMXWriter_get_output(writer, &dest);
3579 EXPECT_HR(hr, S_OK);
3580 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3581 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3582 VariantClear(&dest);
3584 ISAXContentHandler_Release(content);
3585 ISAXLexicalHandler_Release(lexical);
3586 IMXWriter_Release(writer);
3587 free_bstrs();
3590 static void test_mxwriter_pi(void)
3592 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
3593 static const WCHAR dataW[] = {'d','a','t','a',0};
3594 ISAXContentHandler *content;
3595 IMXWriter *writer;
3596 VARIANT dest;
3597 HRESULT hr;
3599 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3600 &IID_IMXWriter, (void**)&writer);
3601 EXPECT_HR(hr, S_OK);
3603 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3604 EXPECT_HR(hr, S_OK);
3606 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
3607 EXPECT_HR(hr, E_INVALIDARG);
3609 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
3610 EXPECT_HR(hr, S_OK);
3612 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
3613 EXPECT_HR(hr, S_OK);
3615 V_VT(&dest) = VT_EMPTY;
3616 hr = IMXWriter_get_output(writer, &dest);
3617 EXPECT_HR(hr, S_OK);
3618 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3619 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3620 VariantClear(&dest);
3622 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
3623 EXPECT_HR(hr, S_OK);
3625 V_VT(&dest) = VT_EMPTY;
3626 hr = IMXWriter_get_output(writer, &dest);
3627 EXPECT_HR(hr, S_OK);
3628 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3629 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)));
3630 VariantClear(&dest);
3632 V_VT(&dest) = VT_EMPTY;
3633 hr = IMXWriter_put_output(writer, dest);
3634 EXPECT_HR(hr, S_OK);
3636 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
3637 EXPECT_HR(hr, S_OK);
3639 V_VT(&dest) = VT_EMPTY;
3640 hr = IMXWriter_get_output(writer, &dest);
3641 EXPECT_HR(hr, S_OK);
3642 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3643 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3644 VariantClear(&dest);
3647 ISAXContentHandler_Release(content);
3648 IMXWriter_Release(writer);
3651 static void test_mxwriter_ignorablespaces(void)
3653 static const WCHAR dataW[] = {'d','a','t','a',0};
3654 ISAXContentHandler *content;
3655 IMXWriter *writer;
3656 VARIANT dest;
3657 HRESULT hr;
3659 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3660 &IID_IMXWriter, (void**)&writer);
3661 EXPECT_HR(hr, S_OK);
3663 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3664 EXPECT_HR(hr, S_OK);
3666 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
3667 EXPECT_HR(hr, E_INVALIDARG);
3669 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
3670 EXPECT_HR(hr, S_OK);
3672 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
3673 EXPECT_HR(hr, S_OK);
3675 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
3676 EXPECT_HR(hr, S_OK);
3678 V_VT(&dest) = VT_EMPTY;
3679 hr = IMXWriter_get_output(writer, &dest);
3680 EXPECT_HR(hr, S_OK);
3681 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3682 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3683 VariantClear(&dest);
3685 ISAXContentHandler_Release(content);
3686 IMXWriter_Release(writer);
3689 static void test_mxwriter_dtd(void)
3691 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
3692 static const WCHAR nameW[] = {'n','a','m','e'};
3693 static const WCHAR pubW[] = {'p','u','b'};
3694 static const WCHAR sysW[] = {'s','y','s'};
3695 ISAXContentHandler *content;
3696 ISAXLexicalHandler *lexical;
3697 ISAXDeclHandler *decl;
3698 IMXWriter *writer;
3699 VARIANT dest;
3700 HRESULT hr;
3702 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3703 &IID_IMXWriter, (void**)&writer);
3704 EXPECT_HR(hr, S_OK);
3706 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3707 EXPECT_HR(hr, S_OK);
3709 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3710 EXPECT_HR(hr, S_OK);
3712 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
3713 EXPECT_HR(hr, S_OK);
3715 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3716 EXPECT_HR(hr, S_OK);
3718 hr = ISAXContentHandler_startDocument(content);
3719 EXPECT_HR(hr, S_OK);
3721 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
3722 EXPECT_HR(hr, E_INVALIDARG);
3724 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3725 EXPECT_HR(hr, E_INVALIDARG);
3727 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
3728 EXPECT_HR(hr, E_INVALIDARG);
3730 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3731 EXPECT_HR(hr, E_INVALIDARG);
3733 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
3734 EXPECT_HR(hr, S_OK);
3736 V_VT(&dest) = VT_EMPTY;
3737 hr = IMXWriter_get_output(writer, &dest);
3738 EXPECT_HR(hr, S_OK);
3739 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3740 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3741 VariantClear(&dest);
3743 /* system id is required if public is present */
3744 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3745 EXPECT_HR(hr, E_INVALIDARG);
3747 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
3748 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3749 EXPECT_HR(hr, S_OK);
3751 V_VT(&dest) = VT_EMPTY;
3752 hr = IMXWriter_get_output(writer, &dest);
3753 EXPECT_HR(hr, S_OK);
3754 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3755 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3756 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3757 VariantClear(&dest);
3759 hr = ISAXLexicalHandler_endDTD(lexical);
3760 EXPECT_HR(hr, S_OK);
3762 hr = ISAXLexicalHandler_endDTD(lexical);
3763 EXPECT_HR(hr, S_OK);
3765 V_VT(&dest) = VT_EMPTY;
3766 hr = IMXWriter_get_output(writer, &dest);
3767 EXPECT_HR(hr, S_OK);
3768 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3769 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3770 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
3771 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3772 VariantClear(&dest);
3774 /* element declaration */
3775 V_VT(&dest) = VT_EMPTY;
3776 hr = IMXWriter_put_output(writer, dest);
3777 EXPECT_HR(hr, S_OK);
3779 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
3780 EXPECT_HR(hr, E_INVALIDARG);
3782 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
3783 EXPECT_HR(hr, E_INVALIDARG);
3785 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
3786 EXPECT_HR(hr, S_OK);
3788 V_VT(&dest) = VT_EMPTY;
3789 hr = IMXWriter_get_output(writer, &dest);
3790 EXPECT_HR(hr, S_OK);
3791 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3792 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
3793 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3794 VariantClear(&dest);
3796 V_VT(&dest) = VT_EMPTY;
3797 hr = IMXWriter_put_output(writer, dest);
3798 EXPECT_HR(hr, S_OK);
3800 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
3801 EXPECT_HR(hr, S_OK);
3803 V_VT(&dest) = VT_EMPTY;
3804 hr = IMXWriter_get_output(writer, &dest);
3805 EXPECT_HR(hr, S_OK);
3806 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3807 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
3808 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3809 VariantClear(&dest);
3811 ISAXContentHandler_Release(content);
3812 ISAXLexicalHandler_Release(lexical);
3813 ISAXDeclHandler_Release(decl);
3814 IMXWriter_Release(writer);
3815 free_bstrs();
3818 typedef struct {
3819 const CLSID *clsid;
3820 const char *uri;
3821 const char *local;
3822 const char *qname;
3823 const char *type;
3824 const char *value;
3825 HRESULT hr;
3826 } addattribute_test_t;
3828 static const addattribute_test_t addattribute_data[] = {
3829 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
3830 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
3831 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
3832 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
3834 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
3835 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
3836 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
3837 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
3839 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
3840 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
3841 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
3842 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
3844 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
3845 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
3846 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
3847 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
3849 { NULL }
3852 static void test_mxattr_addAttribute(void)
3854 const addattribute_test_t *table = addattribute_data;
3855 int i = 0;
3857 while (table->clsid)
3859 ISAXAttributes *saxattr;
3860 IMXAttributes *mxattr;
3861 const WCHAR *value;
3862 int len, index;
3863 HRESULT hr;
3865 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
3867 table++;
3868 i++;
3869 continue;
3872 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3873 &IID_IMXAttributes, (void**)&mxattr);
3874 EXPECT_HR(hr, S_OK);
3876 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
3877 EXPECT_HR(hr, S_OK);
3879 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
3880 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
3881 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
3883 hr = ISAXAttributes_getLength(saxattr, NULL);
3884 EXPECT_HR(hr, E_POINTER);
3887 len = -1;
3888 hr = ISAXAttributes_getLength(saxattr, &len);
3889 EXPECT_HR(hr, S_OK);
3890 ok(len == 0, "got %d\n", len);
3892 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
3893 EXPECT_HR(hr, E_INVALIDARG);
3895 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
3896 EXPECT_HR(hr, E_INVALIDARG);
3898 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
3899 EXPECT_HR(hr, E_INVALIDARG);
3901 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
3902 EXPECT_HR(hr, E_INVALIDARG);
3904 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
3905 EXPECT_HR(hr, E_INVALIDARG);
3907 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
3908 EXPECT_HR(hr, E_INVALIDARG);
3910 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
3911 EXPECT_HR(hr, E_INVALIDARG);
3913 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
3914 EXPECT_HR(hr, E_INVALIDARG);
3916 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
3917 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
3918 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3920 if (hr == S_OK)
3922 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
3923 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
3924 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
3926 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
3927 EXPECT_HR(hr, E_POINTER);
3929 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
3930 EXPECT_HR(hr, E_POINTER);
3932 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
3933 EXPECT_HR(hr, E_POINTER);
3935 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
3936 EXPECT_HR(hr, E_POINTER);
3938 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
3939 EXPECT_HR(hr, E_POINTER);
3941 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
3942 EXPECT_HR(hr, E_POINTER);
3945 len = -1;
3946 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
3947 EXPECT_HR(hr, S_OK);
3948 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
3949 table->value);
3950 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
3952 len = -1;
3953 value = (void*)0xdeadbeef;
3954 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
3955 EXPECT_HR(hr, S_OK);
3957 if (table->type)
3959 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
3960 table->type);
3961 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
3963 else
3965 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
3966 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
3969 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
3970 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
3971 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
3973 EXPECT_HR(hr, E_POINTER);
3975 else
3976 EXPECT_HR(hr, E_INVALIDARG);
3978 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
3979 EXPECT_HR(hr, E_INVALIDARG);
3981 index = -1;
3982 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
3983 EXPECT_HR(hr, E_INVALIDARG);
3984 ok(index == -1, "%d: got wrong index %d\n", i, index);
3986 index = -1;
3987 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
3988 EXPECT_HR(hr, E_INVALIDARG);
3989 ok(index == -1, "%d: got wrong index %d\n", i, index);
3991 index = -1;
3992 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
3993 EXPECT_HR(hr, S_OK);
3994 ok(index == 0, "%d: got wrong index %d\n", i, index);
3996 index = -1;
3997 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
3998 EXPECT_HR(hr, E_INVALIDARG);
3999 ok(index == -1, "%d: got wrong index %d\n", i, index);
4001 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4002 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4004 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4005 EXPECT_HR(hr, E_INVALIDARG);
4007 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4008 EXPECT_HR(hr, E_INVALIDARG);
4010 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4011 EXPECT_HR(hr, E_INVALIDARG);
4013 else
4015 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4016 EXPECT_HR(hr, E_POINTER);
4018 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4019 EXPECT_HR(hr, E_POINTER);
4021 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4022 EXPECT_HR(hr, E_POINTER);
4024 /* versions 4 and 6 crash */
4025 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4026 EXPECT_HR(hr, E_POINTER);
4028 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4029 EXPECT_HR(hr, E_POINTER);
4032 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4033 EXPECT_HR(hr, S_OK);
4036 len = -1;
4037 hr = ISAXAttributes_getLength(saxattr, &len);
4038 EXPECT_HR(hr, S_OK);
4039 if (table->hr == S_OK)
4040 ok(len == 1, "%d: got %d length, expected 0\n", i, len);
4041 else
4042 ok(len == 0, "%d: got %d length, expected 1\n", i, len);
4044 ISAXAttributes_Release(saxattr);
4045 IMXAttributes_Release(mxattr);
4047 table++;
4048 i++;
4051 free_bstrs();
4054 static void test_mxattr_clear(void)
4056 ISAXAttributes *saxattr;
4057 IMXAttributes *mxattr;
4058 const WCHAR *ptr;
4059 HRESULT hr;
4060 int len;
4062 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4063 &IID_IMXAttributes, (void**)&mxattr);
4064 EXPECT_HR(hr, S_OK);
4066 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4067 EXPECT_HR(hr, S_OK);
4069 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4070 EXPECT_HR(hr, E_INVALIDARG);
4072 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4073 EXPECT_HR(hr, E_INVALIDARG);
4075 hr = IMXAttributes_clear(mxattr);
4076 EXPECT_HR(hr, S_OK);
4078 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4079 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4080 EXPECT_HR(hr, S_OK);
4082 len = -1;
4083 hr = ISAXAttributes_getLength(saxattr, &len);
4084 EXPECT_HR(hr, S_OK);
4085 ok(len == 1, "got %d\n", len);
4087 len = -1;
4088 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4089 EXPECT_HR(hr, E_POINTER);
4090 ok(len == -1, "got %d\n", len);
4092 ptr = (void*)0xdeadbeef;
4093 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4094 EXPECT_HR(hr, E_POINTER);
4095 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4097 len = 0;
4098 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4099 EXPECT_HR(hr, S_OK);
4100 ok(len == 5, "got %d\n", len);
4101 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4103 hr = IMXAttributes_clear(mxattr);
4104 EXPECT_HR(hr, S_OK);
4106 len = -1;
4107 hr = ISAXAttributes_getLength(saxattr, &len);
4108 EXPECT_HR(hr, S_OK);
4109 ok(len == 0, "got %d\n", len);
4111 len = -1;
4112 ptr = (void*)0xdeadbeef;
4113 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4114 EXPECT_HR(hr, E_INVALIDARG);
4115 ok(len == -1, "got %d\n", len);
4116 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4118 IMXAttributes_Release(mxattr);
4119 ISAXAttributes_Release(saxattr);
4120 free_bstrs();
4123 static void test_mxattr_dispex(void)
4125 IMXAttributes *mxattr;
4126 IDispatchEx *dispex;
4127 IUnknown *unk;
4128 HRESULT hr;
4130 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4131 &IID_IMXAttributes, (void**)&mxattr);
4132 EXPECT_HR(hr, S_OK);
4134 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4135 EXPECT_HR(hr, S_OK);
4136 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4137 test_obj_dispex(unk);
4138 IUnknown_Release(unk);
4139 IDispatchEx_Release(dispex);
4141 IMXAttributes_Release(mxattr);
4144 static void test_mxattr_qi(void)
4146 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4147 ISAXAttributes *saxattr;
4148 IMXAttributes *mxattr;
4149 HRESULT hr;
4151 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4152 &IID_IMXAttributes, (void**)&mxattr);
4153 EXPECT_HR(hr, S_OK);
4155 EXPECT_REF(mxattr, 1);
4156 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4157 EXPECT_HR(hr, S_OK);
4159 EXPECT_REF(mxattr, 2);
4160 EXPECT_REF(saxattr, 2);
4162 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4163 EXPECT_HR(hr, S_OK);
4165 EXPECT_REF(vbsaxattr, 3);
4166 EXPECT_REF(mxattr, 3);
4167 EXPECT_REF(saxattr, 3);
4169 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4170 EXPECT_HR(hr, S_OK);
4172 EXPECT_REF(vbsaxattr, 4);
4173 EXPECT_REF(mxattr, 4);
4174 EXPECT_REF(saxattr, 4);
4176 IMXAttributes_Release(mxattr);
4177 ISAXAttributes_Release(saxattr);
4178 IVBSAXAttributes_Release(vbsaxattr);
4179 IVBSAXAttributes_Release(vbsaxattr2);
4182 static struct msxmlsupported_data_t saxattr_support_data[] =
4184 { &CLSID_SAXAttributes, "SAXAttributes" },
4185 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4186 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4187 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4188 { NULL }
4191 static void test_mxattr_localname(void)
4193 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4194 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4195 static const WCHAR uri1W[] = {'u','r','i','1',0};
4196 static const WCHAR uriW[] = {'u','r','i',0};
4198 const struct msxmlsupported_data_t *table = saxattr_support_data;
4200 while (table->clsid)
4202 ISAXAttributes *saxattr;
4203 IMXAttributes *mxattr;
4204 HRESULT hr;
4205 int index;
4207 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4209 table++;
4210 continue;
4213 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4214 &IID_IMXAttributes, (void**)&mxattr);
4215 EXPECT_HR(hr, S_OK);
4217 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4218 EXPECT_HR(hr, S_OK);
4220 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4221 EXPECT_HR(hr, E_INVALIDARG);
4223 /* add some ambiguos attribute names */
4224 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4225 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4226 EXPECT_HR(hr, S_OK);
4227 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4228 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4229 EXPECT_HR(hr, S_OK);
4231 index = -1;
4232 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4233 EXPECT_HR(hr, S_OK);
4234 ok(index == 0, "%s: got index %d\n", table->name, index);
4236 index = -1;
4237 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4238 EXPECT_HR(hr, E_INVALIDARG);
4239 ok(index == -1, "%s: got index %d\n", table->name, index);
4241 index = -1;
4242 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4243 EXPECT_HR(hr, E_INVALIDARG);
4244 ok(index == -1, "%s: got index %d\n", table->name, index);
4246 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4247 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4249 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4250 EXPECT_HR(hr, E_POINTER);
4252 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4253 EXPECT_HR(hr, E_POINTER);
4255 else
4257 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4258 EXPECT_HR(hr, E_INVALIDARG);
4260 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4261 EXPECT_HR(hr, E_INVALIDARG);
4264 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
4265 EXPECT_HR(hr, E_INVALIDARG);
4267 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
4268 EXPECT_HR(hr, E_INVALIDARG);
4270 table++;
4272 ISAXAttributes_Release(saxattr);
4273 IMXAttributes_Release(mxattr);
4277 START_TEST(saxreader)
4279 ISAXXMLReader *reader;
4280 HRESULT hr;
4282 hr = CoInitialize(NULL);
4283 ok(hr == S_OK, "failed to init com\n");
4285 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4286 &IID_ISAXXMLReader, (void**)&reader);
4288 if(FAILED(hr))
4290 skip("Failed to create SAXXMLReader instance\n");
4291 CoUninitialize();
4292 return;
4294 ISAXXMLReader_Release(reader);
4296 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4298 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
4300 test_saxreader();
4301 test_saxreader_properties();
4302 test_saxreader_features();
4303 test_encoding();
4304 test_dispex();
4306 /* MXXMLWriter tests */
4307 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
4308 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
4310 test_mxwriter_handlers();
4311 test_mxwriter_startenddocument();
4312 test_mxwriter_startendelement();
4313 test_mxwriter_characters();
4314 test_mxwriter_comment();
4315 test_mxwriter_cdata();
4316 test_mxwriter_pi();
4317 test_mxwriter_ignorablespaces();
4318 test_mxwriter_dtd();
4319 test_mxwriter_properties();
4320 test_mxwriter_flush();
4321 test_mxwriter_stream();
4322 test_mxwriter_encoding();
4323 test_mxwriter_dispex();
4325 else
4326 win_skip("MXXMLWriter not supported\n");
4328 /* SAXAttributes tests */
4329 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
4330 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
4332 test_mxattr_qi();
4333 test_mxattr_addAttribute();
4334 test_mxattr_clear();
4335 test_mxattr_localname();
4336 test_mxattr_dispex();
4338 else
4339 skip("SAXAttributes not supported\n");
4341 CoUninitialize();