Add AppDefaults app selection to control panel
[wine/gsoc-2012-control.git] / dlls / msxml3 / tests / saxreader.c
blob9216f3a2f49480ed0ed2eccd6f915cbf256d5bcf
1 /*
2 * SAXReader/MXWriter tests
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
6 * Copyright 2012 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define CONST_VTABLE
26 #include <stdio.h>
27 #include <assert.h>
29 #include "windows.h"
30 #include "ole2.h"
31 #include "msxml2.h"
32 #include "msxml2did.h"
33 #include "ocidl.h"
34 #include "dispex.h"
36 #include "wine/test.h"
38 #define EXPECT_HR(hr,hr_exp) \
39 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
41 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
42 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
44 ULONG rc = IUnknown_AddRef(obj);
45 IUnknown_Release(obj);
46 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
49 static LONG get_refcount(void *iface)
51 IUnknown *unk = iface;
52 LONG ref;
54 ref = IUnknown_AddRef(unk);
55 IUnknown_Release(unk);
56 return ref-1;
59 struct msxmlsupported_data_t
61 const GUID *clsid;
62 const char *name;
63 BOOL supported;
66 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
68 while (table->clsid)
70 if (table->clsid == clsid) return table->supported;
71 table++;
73 return FALSE;
76 static BSTR alloc_str_from_narrow(const char *str)
78 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
79 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
80 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
81 return ret;
84 static BSTR alloced_bstrs[512];
85 static int alloced_bstrs_count;
87 static BSTR _bstr_(const char *str)
89 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
90 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
91 return alloced_bstrs[alloced_bstrs_count++];
94 static void free_bstrs(void)
96 int i;
97 for (i = 0; i < alloced_bstrs_count; i++)
98 SysFreeString(alloced_bstrs[i]);
99 alloced_bstrs_count = 0;
102 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, int todo, int *failcount)
104 int len, lenexp, cmp;
105 WCHAR buf[1024];
107 len = SysStringLen(str);
109 if (!expected) {
110 if (str && todo)
112 (*failcount)++;
113 todo_wine
114 ok_(file, line) (!str, "got %p, expected null str\n", str);
116 else
117 ok_(file, line) (!str, "got %p, expected null str\n", str);
119 if (len && todo)
121 (*failcount)++;
122 todo_wine
123 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
125 else
126 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
127 return;
130 lenexp = strlen(expected);
131 if (lenexp != len && todo)
133 (*failcount)++;
134 todo_wine
135 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
137 else
138 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
140 /* exit earlier on length mismatch */
141 if (lenexp != len) return;
143 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
145 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
146 if (cmp && todo)
148 (*failcount)++;
149 todo_wine
150 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
151 wine_dbgstr_wn(str, len), expected);
153 else
154 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
155 wine_dbgstr_wn(str, len), expected);
158 typedef enum _CH {
159 CH_ENDTEST,
160 CH_PUTDOCUMENTLOCATOR,
161 CH_STARTDOCUMENT,
162 CH_ENDDOCUMENT,
163 CH_STARTPREFIXMAPPING,
164 CH_ENDPREFIXMAPPING,
165 CH_STARTELEMENT,
166 CH_ENDELEMENT,
167 CH_CHARACTERS,
168 CH_IGNORABLEWHITESPACE,
169 CH_PROCESSINGINSTRUCTION,
170 CH_SKIPPEDENTITY,
171 EH_ERROR,
172 EH_FATALERROR,
173 EG_IGNORABLEWARNING,
174 EVENT_LAST
175 } CH;
177 static const char *event_names[EVENT_LAST] = {
178 "endtest",
179 "putDocumentLocator",
180 "startDocument",
181 "endDocument",
182 "startPrefixMapping",
183 "endPrefixMapping",
184 "startElement",
185 "endElement",
186 "characters",
187 "ignorableWhitespace",
188 "processingInstruction",
189 "skippedEntity",
190 "error",
191 "fatalError",
192 "ignorableWarning"
195 struct attribute_entry {
196 const char *uri;
197 const char *local;
198 const char *qname;
199 const char *value;
201 /* used for actual call data only, null for expected call data */
202 BSTR uriW;
203 BSTR localW;
204 BSTR qnameW;
205 BSTR valueW;
208 struct call_entry {
209 CH id;
210 int line;
211 int column;
212 HRESULT ret;
213 const char *arg1;
214 const char *arg2;
215 const char *arg3;
217 /* allocated once at startElement callback */
218 struct attribute_entry *attributes;
219 int attr_count;
221 /* used for actual call data only, null for expected call data */
222 BSTR arg1W;
223 BSTR arg2W;
224 BSTR arg3W;
227 struct call_sequence
229 int count;
230 int size;
231 struct call_entry *sequence;
234 #define CONTENT_HANDLER_INDEX 0
235 #define NUM_CALL_SEQUENCES 1
236 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
238 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
240 memset(call, 0, sizeof(*call));
241 ISAXLocator_getLineNumber(locator, &call->line);
242 ISAXLocator_getColumnNumber(locator, &call->column);
245 static void add_call(struct call_sequence **seq, int sequence_index,
246 const struct call_entry *call)
248 struct call_sequence *call_seq = seq[sequence_index];
250 if (!call_seq->sequence)
252 call_seq->size = 10;
253 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
254 call_seq->size * sizeof (struct call_entry));
257 if (call_seq->count == call_seq->size)
259 call_seq->size *= 2;
260 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
261 call_seq->sequence,
262 call_seq->size * sizeof (struct call_entry));
265 assert(call_seq->sequence);
267 call_seq->sequence[call_seq->count].id = call->id;
268 call_seq->sequence[call_seq->count].line = call->line;
269 call_seq->sequence[call_seq->count].column = call->column;
270 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
271 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
272 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
273 call_seq->sequence[call_seq->count].ret = call->ret;
274 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
275 call_seq->sequence[call_seq->count].attributes = call->attributes;
277 call_seq->count++;
280 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
282 int i;
284 struct call_sequence *call_seq = seg[sequence_index];
286 for (i = 0; i < call_seq->count; i++)
288 int j;
290 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
292 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
293 SysFreeString(call_seq->sequence[i].attributes[j].localW);
294 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
297 SysFreeString(call_seq->sequence[i].arg1W);
298 SysFreeString(call_seq->sequence[i].arg2W);
299 SysFreeString(call_seq->sequence[i].arg3W);
302 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
303 call_seq->sequence = NULL;
304 call_seq->count = call_seq->size = 0;
307 static inline void flush_sequences(struct call_sequence **seq, int n)
309 int i;
310 for (i = 0; i < n; i++)
311 flush_sequence(seq, i);
314 static const char *get_event_name(CH event)
316 return event_names[event];
319 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
320 int todo, const char *file, int line, int *failcount)
322 int i, lenexp = 0;
324 /* attribute count is not stored for expected data */
325 if (expected->attributes)
327 struct attribute_entry *ptr = expected->attributes;
328 while (ptr->uri) { lenexp++; ptr++; };
331 /* check count first and exit earlier */
332 if (actual->attr_count != lenexp && todo)
334 (*failcount)++;
335 todo_wine
336 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
337 context, get_event_name(actual->id), lenexp, actual->attr_count);
339 else
340 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
341 context, get_event_name(actual->id), lenexp, actual->attr_count);
343 if (actual->attr_count != lenexp) return;
345 /* now compare all attributes strings */
346 for (i = 0; i < actual->attr_count; i++)
348 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
349 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
350 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
351 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
355 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
356 const struct call_entry *expected, const char *context, int todo,
357 const char *file, int line)
359 struct call_sequence *call_seq = seq[sequence_index];
360 static const struct call_entry end_of_sequence = { CH_ENDTEST };
361 const struct call_entry *actual, *sequence;
362 int failcount = 0;
364 add_call(seq, sequence_index, &end_of_sequence);
366 sequence = call_seq->sequence;
367 actual = sequence;
369 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
371 if (expected->id == actual->id)
373 /* always test position data */
374 if (expected->line != actual->line && todo)
376 todo_wine
378 failcount++;
379 ok_(file, line) (FALSE,
380 "%s: in event %s expecting line %d got %d\n",
381 context, get_event_name(actual->id), expected->line, actual->line);
384 else
386 ok_(file, line) (expected->line == actual->line,
387 "%s: in event %s expecting line %d got %d\n",
388 context, get_event_name(actual->id), expected->line, actual->line);
391 if (expected->column != actual->column && todo)
393 todo_wine
395 failcount++;
396 ok_(file, line) (FALSE,
397 "%s: in event %s expecting column %d got %d\n",
398 context, get_event_name(actual->id), expected->column, actual->column);
401 else
403 ok_(file, line) (expected->column == actual->column,
404 "%s: in event %s expecting column %d got %d\n",
405 context, get_event_name(actual->id), expected->column, actual->column);
408 switch (actual->id)
410 case CH_PUTDOCUMENTLOCATOR:
411 case CH_STARTDOCUMENT:
412 case CH_ENDDOCUMENT:
413 break;
414 case CH_STARTPREFIXMAPPING:
415 /* prefix, uri */
416 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
417 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
418 break;
419 case CH_ENDPREFIXMAPPING:
420 /* prefix */
421 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
422 break;
423 case CH_STARTELEMENT:
424 /* compare attributes */
425 compare_attributes(actual, expected, context, todo, file, line, &failcount);
426 /* fallthrough */
427 case CH_ENDELEMENT:
428 /* uri, localname, qname */
429 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
430 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
431 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
432 break;
433 case CH_CHARACTERS:
434 case CH_IGNORABLEWHITESPACE:
435 /* char data */
436 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
437 break;
438 case CH_PROCESSINGINSTRUCTION:
439 /* target, data */
440 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
441 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
442 break;
443 case CH_SKIPPEDENTITY:
444 /* name */
445 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
446 break;
447 case EH_FATALERROR:
448 /* test return value only */
449 if (expected->ret != actual->ret && todo)
451 failcount++;
452 ok_(file, line) (FALSE,
453 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
454 context, get_event_name(actual->id), expected->ret, actual->ret);
456 else
457 ok_(file, line) (expected->ret == actual->ret,
458 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
459 context, get_event_name(actual->id), expected->ret, actual->ret);
460 break;
461 case EH_ERROR:
462 case EG_IGNORABLEWARNING:
463 default:
464 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
466 expected++;
467 actual++;
469 else if (todo)
471 failcount++;
472 todo_wine
474 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
475 context, get_event_name(expected->id), get_event_name(actual->id));
478 flush_sequence(seq, sequence_index);
479 return;
481 else
483 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
484 context, get_event_name(expected->id), get_event_name(actual->id));
485 expected++;
486 actual++;
490 if (todo)
492 todo_wine
494 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
496 failcount++;
497 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
498 context, get_event_name(expected->id), get_event_name(actual->id));
502 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
504 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
505 context, get_event_name(expected->id), get_event_name(actual->id));
508 if (todo && !failcount) /* succeeded yet marked todo */
510 todo_wine
512 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
516 flush_sequence(seq, sequence_index);
519 #define ok_sequence(seq, index, exp, contx, todo) \
520 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
522 static void init_call_sequences(struct call_sequence **seq, int n)
524 int i;
526 for (i = 0; i < n; i++)
527 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
530 static const WCHAR szSimpleXML[] = {
531 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
532 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
533 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
534 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
535 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
538 static const WCHAR carriage_ret_test[] = {
539 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
540 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
541 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
542 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
543 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
546 static const WCHAR szUtf16XML[] = {
547 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
548 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
549 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
552 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
554 static const CHAR szUtf8XML[] =
555 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
557 static const char utf8xml2[] =
558 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
560 static const CHAR testXML[] =
561 "<?xml version=\"1.0\" ?>\n"
562 "<BankAccount>\n"
563 " <Number>1234</Number>\n"
564 " <Name>Captain Ahab</Name>\n"
565 "</BankAccount>\n";
567 static const char test_attributes[] =
568 "<?xml version=\"1.0\" ?>\n"
569 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
570 "<node1 xmlns:p=\"test\" />"
571 "</document>\n";
573 static struct call_entry content_handler_test1[] = {
574 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
575 { CH_STARTDOCUMENT, 0, 0, S_OK },
576 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
577 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
578 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
579 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
580 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
581 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
582 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
583 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
584 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
585 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
586 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
587 { CH_ENDDOCUMENT, 0, 0, S_OK},
588 { CH_ENDTEST }
591 /* applies to versions 4 and 6 */
592 static struct call_entry content_handler_test1_alternate[] = {
593 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
594 { CH_STARTDOCUMENT, 1, 22, S_OK },
595 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
597 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
598 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
599 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
600 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
601 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
602 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
603 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
604 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
605 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
606 { CH_ENDDOCUMENT, 6, 0, S_OK },
607 { CH_ENDTEST }
610 static struct call_entry content_handler_test2[] = {
611 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
612 { CH_STARTDOCUMENT, 0, 0, S_OK },
613 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
614 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
615 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
616 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
617 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
618 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
619 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
620 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
621 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
622 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
623 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
624 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
625 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
626 { CH_ENDDOCUMENT, 0, 0, S_OK },
627 { CH_ENDTEST }
630 static struct call_entry content_handler_test2_alternate[] = {
631 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
632 { CH_STARTDOCUMENT, 1, 21, S_OK },
633 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
634 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
635 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
636 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
637 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
638 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
639 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
640 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
641 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
642 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
643 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
644 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
645 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
646 { CH_ENDDOCUMENT, 6, 0, S_OK },
647 { CH_ENDTEST }
650 static struct call_entry content_handler_testerror[] = {
651 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
652 { EH_FATALERROR, 0, 0, E_FAIL },
653 { CH_ENDTEST }
656 static struct call_entry content_handler_testerror_alternate[] = {
657 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
658 { EH_FATALERROR, 1, 0, E_FAIL },
659 { CH_ENDTEST }
662 static struct call_entry content_handler_test_callback_rets[] = {
663 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
664 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
665 { EH_FATALERROR, 0, 0, S_FALSE },
666 { CH_ENDTEST }
669 static struct call_entry content_handler_test_callback_rets_alt[] = {
670 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
671 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
672 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
673 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
674 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
675 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
676 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
677 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
678 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
679 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
680 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
681 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
682 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
683 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
684 { CH_ENDTEST }
687 static struct attribute_entry ch_attributes1[] = {
688 { "", "", "xmlns:test", "prefix_test" },
689 { "", "", "xmlns", "prefix" },
690 { "prefix_test", "arg1", "test:arg1", "arg1" },
691 { "", "arg2", "arg2", "arg2" },
692 { "prefix_test", "ar3", "test:ar3", "arg3" },
693 { NULL }
696 static struct attribute_entry ch_attributes2[] = {
697 { "", "", "xmlns:p", "test" },
698 { NULL }
701 static struct call_entry content_handler_test_attributes[] = {
702 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
703 { CH_STARTDOCUMENT, 0, 0, S_OK },
704 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
705 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
706 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
707 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
708 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
709 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
710 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
711 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
712 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
713 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
714 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
715 { CH_ENDDOCUMENT, 0, 0 },
716 { CH_ENDTEST }
719 static struct attribute_entry ch_attributes_alt_4[] = {
720 { "prefix_test", "arg1", "test:arg1", "arg1" },
721 { "", "arg2", "arg2", "arg2" },
722 { "prefix_test", "ar3", "test:ar3", "arg3" },
723 { "", "", "xmlns:test", "prefix_test" },
724 { "", "", "xmlns", "prefix" },
725 { NULL }
728 static struct call_entry content_handler_test_attributes_alternate_4[] = {
729 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
730 { CH_STARTDOCUMENT, 1, 22, S_OK },
731 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
732 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
733 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
734 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
735 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
736 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
737 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
738 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
739 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
740 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
741 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
742 { CH_ENDDOCUMENT, 4, 0, S_OK },
743 { CH_ENDTEST }
746 /* 'namespace' feature switched off */
747 static struct attribute_entry ch_attributes_alt_no_ns[] = {
748 { "", "", "xmlns:test", "prefix_test" },
749 { "", "", "xmlns", "prefix" },
750 { "", "", "test:arg1", "arg1" },
751 { "", "", "arg2", "arg2" },
752 { "", "", "test:ar3", "arg3" },
753 { NULL }
756 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
757 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
758 { CH_STARTDOCUMENT, 1, 22, S_OK },
759 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
760 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
761 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
762 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
763 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
764 { CH_ENDDOCUMENT, 4, 0, S_OK },
765 { CH_ENDTEST }
768 static struct attribute_entry ch_attributes_alt_6[] = {
769 { "prefix_test", "arg1", "test:arg1", "arg1" },
770 { "", "arg2", "arg2", "arg2" },
771 { "prefix_test", "ar3", "test:ar3", "arg3" },
772 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
773 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
774 { NULL }
777 static struct attribute_entry ch_attributes2_6[] = {
778 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
779 { NULL }
782 static struct call_entry content_handler_test_attributes_alternate_6[] = {
783 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
784 { CH_STARTDOCUMENT, 1, 22, S_OK },
785 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
786 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
787 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
788 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
789 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
790 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
791 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
792 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
793 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
794 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
795 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
796 { CH_ENDDOCUMENT, 4, 0, S_OK },
797 { CH_ENDTEST }
800 /* 'namespaces' is on, 'namespace-prefixes' if off */
801 static struct attribute_entry ch_attributes_no_prefix[] = {
802 { "prefix_test", "arg1", "test:arg1", "arg1" },
803 { "", "arg2", "arg2", "arg2" },
804 { "prefix_test", "ar3", "test:ar3", "arg3" },
805 { NULL }
808 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
809 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
810 { CH_STARTDOCUMENT, 1, 22, S_OK },
811 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
812 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
813 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
814 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
815 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
816 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
817 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
818 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
819 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
820 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
821 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
822 { CH_ENDDOCUMENT, 4, 0, S_OK },
823 { CH_ENDTEST }
826 static struct call_entry content_handler_test_attributes_no_prefix[] = {
827 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
828 { CH_STARTDOCUMENT, 0, 0, S_OK },
829 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
830 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
831 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
832 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
833 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
834 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
835 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
836 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
837 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
838 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
839 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
840 { CH_ENDDOCUMENT, 0, 0 },
841 { CH_ENDTEST }
844 static struct attribute_entry xmlspace_attrs[] = {
845 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
846 { NULL }
849 static struct call_entry xmlspaceattr_test[] = {
850 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
851 { CH_STARTDOCUMENT, 0, 0, S_OK },
852 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
853 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
854 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
855 { CH_ENDDOCUMENT, 0, 0, S_OK },
856 { CH_ENDTEST }
859 static struct call_entry xmlspaceattr_test_alternate[] = {
860 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
861 { CH_STARTDOCUMENT, 1, 39, S_OK },
862 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
863 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
864 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
865 { CH_ENDDOCUMENT, 1, 83, S_OK },
866 { CH_ENDTEST }
869 /* attribute value normalization test */
870 static const char attribute_normalize[] =
871 "<?xml version=\"1.0\" ?>\n"
872 "<a attr1=\" \r \n \tattr_value &#65; \t \r \n\r\n \n\"/>\n";
874 static struct attribute_entry attribute_norm_attrs[] = {
875 { "", "attr1", "attr1", " attr_value A " },
876 { NULL }
879 static struct call_entry attribute_norm[] = {
880 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
881 { CH_STARTDOCUMENT, 0, 0, S_OK },
882 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
883 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
884 { CH_ENDDOCUMENT, 0, 0, S_OK },
885 { CH_ENDTEST }
888 static struct call_entry attribute_norm_alt[] = {
889 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
890 { CH_STARTDOCUMENT, 1, 22, S_OK },
891 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
892 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
893 { CH_ENDDOCUMENT, 9, 0, S_OK },
894 { CH_ENDTEST }
897 static const char xmlspace_attr[] =
898 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
899 "<a xml:space=\"preserve\"> Some text data </a>";
901 static struct call_entry *expectCall;
902 static ISAXLocator *locator;
903 static ISAXXMLReader *g_reader;
904 int msxml_version;
906 static void set_expected_seq(struct call_entry *expected)
908 expectCall = expected;
911 /* to be called once on each tested callback return */
912 static HRESULT get_expected_ret(void)
914 HRESULT hr = expectCall->ret;
915 if (expectCall->id != CH_ENDTEST) expectCall++;
916 return hr;
919 static HRESULT WINAPI contentHandler_QueryInterface(
920 ISAXContentHandler* iface,
921 REFIID riid,
922 void **ppvObject)
924 *ppvObject = NULL;
926 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
928 *ppvObject = iface;
930 else
932 return E_NOINTERFACE;
935 return S_OK;
938 static ULONG WINAPI contentHandler_AddRef(
939 ISAXContentHandler* iface)
941 return 2;
944 static ULONG WINAPI contentHandler_Release(
945 ISAXContentHandler* iface)
947 return 1;
950 static HRESULT WINAPI contentHandler_putDocumentLocator(
951 ISAXContentHandler* iface,
952 ISAXLocator *pLocator)
954 struct call_entry call;
955 HRESULT hr;
957 locator = pLocator;
959 init_call_entry(locator, &call);
960 call.id = CH_PUTDOCUMENTLOCATOR;
961 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
963 if (msxml_version >= 6) {
964 ISAXAttributes *attr, *attr1;
965 IMXAttributes *mxattr;
967 EXPECT_REF(pLocator, 1);
968 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
969 EXPECT_HR(hr, S_OK);
970 EXPECT_REF(pLocator, 2);
971 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
972 EXPECT_HR(hr, S_OK);
973 EXPECT_REF(pLocator, 3);
974 ok(attr == attr1, "got %p, %p\n", attr, attr1);
976 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
977 EXPECT_HR(hr, E_NOINTERFACE);
979 ISAXAttributes_Release(attr);
980 ISAXAttributes_Release(attr1);
983 return get_expected_ret();
986 static ISAXAttributes *test_attr_ptr;
987 static HRESULT WINAPI contentHandler_startDocument(
988 ISAXContentHandler* iface)
990 struct call_entry call;
992 init_call_entry(locator, &call);
993 call.id = CH_STARTDOCUMENT;
994 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
996 test_attr_ptr = NULL;
998 return get_expected_ret();
1001 static HRESULT WINAPI contentHandler_endDocument(
1002 ISAXContentHandler* iface)
1004 struct call_entry call;
1006 init_call_entry(locator, &call);
1007 call.id = CH_ENDDOCUMENT;
1008 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1010 return get_expected_ret();
1013 static HRESULT WINAPI contentHandler_startPrefixMapping(
1014 ISAXContentHandler* iface,
1015 const WCHAR *prefix, int prefix_len,
1016 const WCHAR *uri, int uri_len)
1018 struct call_entry call;
1020 init_call_entry(locator, &call);
1021 call.id = CH_STARTPREFIXMAPPING;
1022 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1023 call.arg2W = SysAllocStringLen(uri, uri_len);
1024 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1026 return get_expected_ret();
1029 static HRESULT WINAPI contentHandler_endPrefixMapping(
1030 ISAXContentHandler* iface,
1031 const WCHAR *prefix, int len)
1033 struct call_entry call;
1035 init_call_entry(locator, &call);
1036 call.id = CH_ENDPREFIXMAPPING;
1037 call.arg1W = SysAllocStringLen(prefix, len);
1038 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1040 return get_expected_ret();
1043 static HRESULT WINAPI contentHandler_startElement(
1044 ISAXContentHandler* iface,
1045 const WCHAR *uri, int uri_len,
1046 const WCHAR *localname, int local_len,
1047 const WCHAR *qname, int qname_len,
1048 ISAXAttributes *saxattr)
1050 struct call_entry call;
1051 IMXAttributes *mxattr;
1052 HRESULT hr;
1053 int len;
1055 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1056 EXPECT_HR(hr, E_NOINTERFACE);
1058 init_call_entry(locator, &call);
1059 call.id = CH_STARTELEMENT;
1060 call.arg1W = SysAllocStringLen(uri, uri_len);
1061 call.arg2W = SysAllocStringLen(localname, local_len);
1062 call.arg3W = SysAllocStringLen(qname, qname_len);
1064 if(!test_attr_ptr)
1065 test_attr_ptr = saxattr;
1066 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1068 /* store actual attributes */
1069 len = 0;
1070 hr = ISAXAttributes_getLength(saxattr, &len);
1071 EXPECT_HR(hr, S_OK);
1073 if (len)
1075 VARIANT_BOOL v;
1076 int i;
1078 struct attribute_entry *attr;
1079 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1081 v = VARIANT_TRUE;
1082 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1083 EXPECT_HR(hr, S_OK);
1085 for (i = 0; i < len; i++)
1087 const WCHAR *value;
1088 int value_len;
1090 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1091 &localname, &local_len, &qname, &qname_len);
1092 EXPECT_HR(hr, S_OK);
1094 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1095 EXPECT_HR(hr, S_OK);
1097 /* if 'namespaces' switched off uri and local name contains garbage */
1098 if (v == VARIANT_FALSE && msxml_version > 0)
1100 attr[i].uriW = SysAllocStringLen(NULL, 0);
1101 attr[i].localW = SysAllocStringLen(NULL, 0);
1103 else
1105 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1106 attr[i].localW = SysAllocStringLen(localname, local_len);
1109 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1110 attr[i].valueW = SysAllocStringLen(value, value_len);
1113 call.attributes = attr;
1114 call.attr_count = len;
1117 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1119 return get_expected_ret();
1122 static HRESULT WINAPI contentHandler_endElement(
1123 ISAXContentHandler* iface,
1124 const WCHAR *uri, int uri_len,
1125 const WCHAR *localname, int local_len,
1126 const WCHAR *qname, int qname_len)
1128 struct call_entry call;
1130 init_call_entry(locator, &call);
1131 call.id = CH_ENDELEMENT;
1132 call.arg1W = SysAllocStringLen(uri, uri_len);
1133 call.arg2W = SysAllocStringLen(localname, local_len);
1134 call.arg3W = SysAllocStringLen(qname, qname_len);
1135 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1137 return get_expected_ret();
1140 static HRESULT WINAPI contentHandler_characters(
1141 ISAXContentHandler* iface,
1142 const WCHAR *chars,
1143 int len)
1145 struct call_entry call;
1147 init_call_entry(locator, &call);
1148 call.id = CH_CHARACTERS;
1149 call.arg1W = SysAllocStringLen(chars, len);
1150 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1152 return get_expected_ret();
1155 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1156 ISAXContentHandler* iface,
1157 const WCHAR *chars, int len)
1159 struct call_entry call;
1161 init_call_entry(locator, &call);
1162 call.id = CH_IGNORABLEWHITESPACE;
1163 call.arg1W = SysAllocStringLen(chars, len);
1164 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1166 return get_expected_ret();
1169 static HRESULT WINAPI contentHandler_processingInstruction(
1170 ISAXContentHandler* iface,
1171 const WCHAR *target, int target_len,
1172 const WCHAR *data, int data_len)
1174 struct call_entry call;
1176 init_call_entry(locator, &call);
1177 call.id = CH_PROCESSINGINSTRUCTION;
1178 call.arg1W = SysAllocStringLen(target, target_len);
1179 call.arg2W = SysAllocStringLen(data, data_len);
1180 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1182 return get_expected_ret();
1185 static HRESULT WINAPI contentHandler_skippedEntity(
1186 ISAXContentHandler* iface,
1187 const WCHAR *name, int len)
1189 struct call_entry call;
1191 init_call_entry(locator, &call);
1192 call.id = CH_SKIPPEDENTITY;
1193 call.arg1W = SysAllocStringLen(name, len);
1195 return get_expected_ret();
1198 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1200 contentHandler_QueryInterface,
1201 contentHandler_AddRef,
1202 contentHandler_Release,
1203 contentHandler_putDocumentLocator,
1204 contentHandler_startDocument,
1205 contentHandler_endDocument,
1206 contentHandler_startPrefixMapping,
1207 contentHandler_endPrefixMapping,
1208 contentHandler_startElement,
1209 contentHandler_endElement,
1210 contentHandler_characters,
1211 contentHandler_ignorableWhitespace,
1212 contentHandler_processingInstruction,
1213 contentHandler_skippedEntity
1216 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1218 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1219 ISAXErrorHandler* iface,
1220 REFIID riid,
1221 void **ppvObject)
1223 *ppvObject = NULL;
1225 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1227 *ppvObject = iface;
1229 else
1231 return E_NOINTERFACE;
1234 return S_OK;
1237 static ULONG WINAPI isaxerrorHandler_AddRef(
1238 ISAXErrorHandler* iface)
1240 return 2;
1243 static ULONG WINAPI isaxerrorHandler_Release(
1244 ISAXErrorHandler* iface)
1246 return 1;
1249 static HRESULT WINAPI isaxerrorHandler_error(
1250 ISAXErrorHandler* iface,
1251 ISAXLocator *pLocator,
1252 const WCHAR *pErrorMessage,
1253 HRESULT hrErrorCode)
1255 ok(0, "unexpected call\n");
1256 return S_OK;
1259 static HRESULT WINAPI isaxerrorHandler_fatalError(
1260 ISAXErrorHandler* iface,
1261 ISAXLocator *pLocator,
1262 const WCHAR *message,
1263 HRESULT hr)
1265 struct call_entry call;
1267 init_call_entry(locator, &call);
1268 call.id = EH_FATALERROR;
1269 call.ret = hr;
1271 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1273 get_expected_ret();
1274 return S_OK;
1277 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1278 ISAXErrorHandler* iface,
1279 ISAXLocator *pLocator,
1280 const WCHAR *pErrorMessage,
1281 HRESULT hrErrorCode)
1283 ok(0, "unexpected call\n");
1284 return S_OK;
1287 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1289 isaxerrorHandler_QueryInterface,
1290 isaxerrorHandler_AddRef,
1291 isaxerrorHandler_Release,
1292 isaxerrorHandler_error,
1293 isaxerrorHandler_fatalError,
1294 isaxerrorHanddler_ignorableWarning
1297 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1299 static HRESULT WINAPI isaxattributes_QueryInterface(
1300 ISAXAttributes* iface,
1301 REFIID riid,
1302 void **ppvObject)
1304 *ppvObject = NULL;
1306 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1308 *ppvObject = iface;
1310 else
1312 return E_NOINTERFACE;
1315 return S_OK;
1318 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1320 return 2;
1323 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1325 return 1;
1328 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1330 *length = 3;
1331 return S_OK;
1334 static HRESULT WINAPI isaxattributes_getURI(
1335 ISAXAttributes* iface,
1336 int nIndex,
1337 const WCHAR **pUrl,
1338 int *pUriSize)
1340 ok(0, "unexpected call\n");
1341 return E_NOTIMPL;
1344 static HRESULT WINAPI isaxattributes_getLocalName(
1345 ISAXAttributes* iface,
1346 int nIndex,
1347 const WCHAR **pLocalName,
1348 int *pLocalNameLength)
1350 ok(0, "unexpected call\n");
1351 return E_NOTIMPL;
1354 static HRESULT WINAPI isaxattributes_getQName(
1355 ISAXAttributes* iface,
1356 int index,
1357 const WCHAR **QName,
1358 int *QNameLength)
1360 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1361 {'a','t','t','r','2','j','u','n','k',0},
1362 {'a','t','t','r','3',0}};
1363 static const int attrqnamelen[] = {7, 5, 5};
1365 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1367 *QName = attrqnamesW[index];
1368 *QNameLength = attrqnamelen[index];
1370 return S_OK;
1373 static HRESULT WINAPI isaxattributes_getName(
1374 ISAXAttributes* iface,
1375 int nIndex,
1376 const WCHAR **pUri,
1377 int * pUriLength,
1378 const WCHAR ** pLocalName,
1379 int * pLocalNameSize,
1380 const WCHAR ** pQName,
1381 int * pQNameLength)
1383 ok(0, "unexpected call\n");
1384 return E_NOTIMPL;
1387 static HRESULT WINAPI isaxattributes_getIndexFromName(
1388 ISAXAttributes* iface,
1389 const WCHAR * pUri,
1390 int cUriLength,
1391 const WCHAR * pLocalName,
1392 int cocalNameLength,
1393 int * index)
1395 ok(0, "unexpected call\n");
1396 return E_NOTIMPL;
1399 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1400 ISAXAttributes* iface,
1401 const WCHAR * pQName,
1402 int nQNameLength,
1403 int * index)
1405 ok(0, "unexpected call\n");
1406 return E_NOTIMPL;
1409 static HRESULT WINAPI isaxattributes_getType(
1410 ISAXAttributes* iface,
1411 int nIndex,
1412 const WCHAR ** pType,
1413 int * pTypeLength)
1415 ok(0, "unexpected call\n");
1416 return E_NOTIMPL;
1419 static HRESULT WINAPI isaxattributes_getTypeFromName(
1420 ISAXAttributes* iface,
1421 const WCHAR * pUri,
1422 int nUri,
1423 const WCHAR * pLocalName,
1424 int nLocalName,
1425 const WCHAR ** pType,
1426 int * nType)
1428 ok(0, "unexpected call\n");
1429 return E_NOTIMPL;
1432 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1433 ISAXAttributes* iface,
1434 const WCHAR * pQName,
1435 int nQName,
1436 const WCHAR ** pType,
1437 int * nType)
1439 ok(0, "unexpected call\n");
1440 return E_NOTIMPL;
1443 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1444 const WCHAR **value, int *nValue)
1446 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1447 {'a','2','j','u','n','k',0},
1448 {'<','&','"','>',0}};
1449 static const int attrvalueslen[] = {2, 2, 4};
1451 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1453 *value = attrvaluesW[index];
1454 *nValue = attrvalueslen[index];
1456 return S_OK;
1459 static HRESULT WINAPI isaxattributes_getValueFromName(
1460 ISAXAttributes* iface,
1461 const WCHAR * pUri,
1462 int nUri,
1463 const WCHAR * pLocalName,
1464 int nLocalName,
1465 const WCHAR ** pValue,
1466 int * nValue)
1468 ok(0, "unexpected call\n");
1469 return E_NOTIMPL;
1472 static HRESULT WINAPI isaxattributes_getValueFromQName(
1473 ISAXAttributes* iface,
1474 const WCHAR * pQName,
1475 int nQName,
1476 const WCHAR ** pValue,
1477 int * nValue)
1479 ok(0, "unexpected call\n");
1480 return E_NOTIMPL;
1483 static const ISAXAttributesVtbl SAXAttributesVtbl =
1485 isaxattributes_QueryInterface,
1486 isaxattributes_AddRef,
1487 isaxattributes_Release,
1488 isaxattributes_getLength,
1489 isaxattributes_getURI,
1490 isaxattributes_getLocalName,
1491 isaxattributes_getQName,
1492 isaxattributes_getName,
1493 isaxattributes_getIndexFromName,
1494 isaxattributes_getIndexFromQName,
1495 isaxattributes_getType,
1496 isaxattributes_getTypeFromName,
1497 isaxattributes_getTypeFromQName,
1498 isaxattributes_getValue,
1499 isaxattributes_getValueFromName,
1500 isaxattributes_getValueFromQName
1503 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1505 struct saxlexicalhandler
1507 ISAXLexicalHandler ISAXLexicalHandler_iface;
1508 LONG ref;
1510 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1513 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1515 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1518 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1520 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1522 *out = NULL;
1524 if (IsEqualGUID(riid, &IID_IUnknown))
1526 *out = iface;
1527 ok(0, "got unexpected IID_IUnknown query\n");
1529 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1531 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1532 *out = iface;
1535 if (*out)
1536 ISAXLexicalHandler_AddRef(iface);
1537 else
1538 return E_NOINTERFACE;
1540 return S_OK;
1543 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1545 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1546 return InterlockedIncrement(&handler->ref);
1549 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1551 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1552 return InterlockedDecrement(&handler->ref);
1555 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1556 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1557 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1559 ok(0, "call not expected\n");
1560 return E_NOTIMPL;
1563 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1565 ok(0, "call not expected\n");
1566 return E_NOTIMPL;
1569 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1570 const WCHAR * pName, int nName)
1572 ok(0, "call not expected\n");
1573 return E_NOTIMPL;
1576 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1577 const WCHAR * pName, int nName)
1579 ok(0, "call not expected\n");
1580 return E_NOTIMPL;
1583 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1585 ok(0, "call not expected\n");
1586 return E_NOTIMPL;
1589 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1591 ok(0, "call not expected\n");
1592 return E_NOTIMPL;
1595 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1596 const WCHAR * pChars, int nChars)
1598 ok(0, "call not expected\n");
1599 return E_NOTIMPL;
1602 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1604 isaxlexical_QueryInterface,
1605 isaxlexical_AddRef,
1606 isaxlexical_Release,
1607 isaxlexical_startDTD,
1608 isaxlexical_endDTD,
1609 isaxlexical_startEntity,
1610 isaxlexical_endEntity,
1611 isaxlexical_startCDATA,
1612 isaxlexical_endCDATA,
1613 isaxlexical_comment
1616 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1618 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1619 handler->ref = 1;
1620 handler->qi_hr = hr;
1623 struct saxdeclhandler
1625 ISAXDeclHandler ISAXDeclHandler_iface;
1626 LONG ref;
1628 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1631 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1633 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1636 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1638 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1640 *out = NULL;
1642 if (IsEqualGUID(riid, &IID_IUnknown))
1644 *out = iface;
1645 ok(0, "got unexpected IID_IUnknown query\n");
1647 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1649 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1650 *out = iface;
1653 if (*out)
1654 ISAXDeclHandler_AddRef(iface);
1655 else
1656 return E_NOINTERFACE;
1658 return S_OK;
1661 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1663 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1664 return InterlockedIncrement(&handler->ref);
1667 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1669 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1670 return InterlockedDecrement(&handler->ref);
1673 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1674 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1676 ok(0, "call not expected\n");
1677 return E_NOTIMPL;
1680 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1681 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1682 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1683 int nValueDefault, const WCHAR * pValue, int nValue)
1685 ok(0, "call not expected\n");
1686 return E_NOTIMPL;
1689 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1690 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1692 ok(0, "call not expected\n");
1693 return E_NOTIMPL;
1696 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1697 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1698 const WCHAR * pSystemId, int nSystemId)
1700 ok(0, "call not expected\n");
1701 return E_NOTIMPL;
1704 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1706 isaxdecl_QueryInterface,
1707 isaxdecl_AddRef,
1708 isaxdecl_Release,
1709 isaxdecl_elementDecl,
1710 isaxdecl_attributeDecl,
1711 isaxdecl_internalEntityDecl,
1712 isaxdecl_externalEntityDecl
1715 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1717 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1718 handler->ref = 1;
1719 handler->qi_hr = hr;
1722 typedef struct mxwriter_write_test_t {
1723 BOOL last;
1724 const BYTE *data;
1725 DWORD cb;
1726 BOOL null_written;
1727 BOOL fail_write;
1728 } mxwriter_write_test;
1730 typedef struct mxwriter_stream_test_t {
1731 VARIANT_BOOL bom;
1732 const char *encoding;
1733 mxwriter_write_test expected_writes[4];
1734 } mxwriter_stream_test;
1736 static const mxwriter_write_test *current_write_test;
1737 static DWORD current_stream_test_index;
1739 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1741 *ppvObject = NULL;
1743 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1744 *ppvObject = iface;
1745 else
1746 return E_NOINTERFACE;
1748 return S_OK;
1751 static ULONG WINAPI istream_AddRef(IStream *iface)
1753 return 2;
1756 static ULONG WINAPI istream_Release(IStream *iface)
1758 return 1;
1761 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1763 ok(0, "unexpected call\n");
1764 return E_NOTIMPL;
1767 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1769 BOOL fail = FALSE;
1771 ok(pv != NULL, "pv == NULL\n");
1773 if(current_write_test->last) {
1774 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1775 return E_FAIL;
1778 fail = current_write_test->fail_write;
1780 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1781 current_write_test->cb, cb, current_stream_test_index);
1783 if(!pcbWritten)
1784 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1785 else
1786 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1788 ++current_write_test;
1790 if(pcbWritten)
1791 *pcbWritten = cb;
1793 return fail ? E_FAIL : S_OK;
1796 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1797 ULARGE_INTEGER *plibNewPosition)
1799 ok(0, "unexpected call\n");
1800 return E_NOTIMPL;
1803 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1805 ok(0, "unexpected call\n");
1806 return E_NOTIMPL;
1809 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1810 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1812 ok(0, "unexpected call\n");
1813 return E_NOTIMPL;
1816 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1818 ok(0, "unexpected call\n");
1819 return E_NOTIMPL;
1822 static HRESULT WINAPI istream_Revert(IStream *iface)
1824 ok(0, "unexpected call\n");
1825 return E_NOTIMPL;
1828 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1829 ULARGE_INTEGER cb, DWORD dwLockType)
1831 ok(0, "unexpected call\n");
1832 return E_NOTIMPL;
1835 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1836 ULARGE_INTEGER cb, DWORD dwLockType)
1838 ok(0, "unexpected call\n");
1839 return E_NOTIMPL;
1842 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1844 ok(0, "unexpected call\n");
1845 return E_NOTIMPL;
1848 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1850 ok(0, "unexpected call\n");
1851 return E_NOTIMPL;
1854 static const IStreamVtbl StreamVtbl = {
1855 istream_QueryInterface,
1856 istream_AddRef,
1857 istream_Release,
1858 istream_Read,
1859 istream_Write,
1860 istream_Seek,
1861 istream_SetSize,
1862 istream_CopyTo,
1863 istream_Commit,
1864 istream_Revert,
1865 istream_LockRegion,
1866 istream_UnlockRegion,
1867 istream_Stat,
1868 istream_Clone
1871 static IStream mxstream = { &StreamVtbl };
1873 static struct msxmlsupported_data_t reader_support_data[] =
1875 { &CLSID_SAXXMLReader, "SAXReader" },
1876 { &CLSID_SAXXMLReader30, "SAXReader30" },
1877 { &CLSID_SAXXMLReader40, "SAXReader40" },
1878 { &CLSID_SAXXMLReader60, "SAXReader60" },
1879 { NULL }
1882 static void test_saxreader(void)
1884 const struct msxmlsupported_data_t *table = reader_support_data;
1885 HRESULT hr;
1886 ISAXXMLReader *reader = NULL;
1887 VARIANT var;
1888 ISAXContentHandler *content;
1889 ISAXErrorHandler *lpErrorHandler;
1890 SAFEARRAY *sa;
1891 SAFEARRAYBOUND SADim[1];
1892 char *ptr = NULL;
1893 IStream *stream;
1894 ULARGE_INTEGER size;
1895 LARGE_INTEGER pos;
1896 ULONG written;
1897 HANDLE file;
1898 static const CHAR testXmlA[] = "test.xml";
1899 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1900 IXMLDOMDocument *doc;
1901 VARIANT_BOOL v;
1903 while (table->clsid)
1905 struct call_entry *test_seq;
1906 BSTR str;
1908 if (!is_clsid_supported(table->clsid, reader_support_data))
1910 table++;
1911 continue;
1914 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1915 EXPECT_HR(hr, S_OK);
1916 g_reader = reader;
1918 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1919 msxml_version = 4;
1920 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1921 msxml_version = 6;
1922 else
1923 msxml_version = 0;
1925 /* crashes on old versions */
1926 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1927 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1929 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1930 EXPECT_HR(hr, E_POINTER);
1932 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1933 EXPECT_HR(hr, E_POINTER);
1936 hr = ISAXXMLReader_getContentHandler(reader, &content);
1937 EXPECT_HR(hr, S_OK);
1938 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1940 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1941 EXPECT_HR(hr, S_OK);
1942 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1944 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1945 EXPECT_HR(hr, S_OK);
1947 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1948 EXPECT_HR(hr, S_OK);
1950 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1951 EXPECT_HR(hr, S_OK);
1953 hr = ISAXXMLReader_getContentHandler(reader, &content);
1954 EXPECT_HR(hr, S_OK);
1955 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1957 V_VT(&var) = VT_BSTR;
1958 V_BSTR(&var) = SysAllocString(szSimpleXML);
1960 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1961 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1962 test_seq = content_handler_test1_alternate;
1963 else
1964 test_seq = content_handler_test1;
1965 set_expected_seq(test_seq);
1966 hr = ISAXXMLReader_parse(reader, var);
1967 EXPECT_HR(hr, S_OK);
1968 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1970 VariantClear(&var);
1972 SADim[0].lLbound = 0;
1973 SADim[0].cElements = sizeof(testXML)-1;
1974 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1975 SafeArrayAccessData(sa, (void**)&ptr);
1976 memcpy(ptr, testXML, sizeof(testXML)-1);
1977 SafeArrayUnaccessData(sa);
1978 V_VT(&var) = VT_ARRAY|VT_UI1;
1979 V_ARRAY(&var) = sa;
1981 set_expected_seq(test_seq);
1982 hr = ISAXXMLReader_parse(reader, var);
1983 EXPECT_HR(hr, S_OK);
1984 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1986 SafeArrayDestroy(sa);
1988 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1989 size.QuadPart = strlen(testXML);
1990 IStream_SetSize(stream, size);
1991 IStream_Write(stream, testXML, strlen(testXML), &written);
1992 pos.QuadPart = 0;
1993 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1994 V_VT(&var) = VT_UNKNOWN;
1995 V_UNKNOWN(&var) = (IUnknown*)stream;
1997 set_expected_seq(test_seq);
1998 hr = ISAXXMLReader_parse(reader, var);
1999 EXPECT_HR(hr, S_OK);
2000 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2002 IStream_Release(stream);
2004 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2005 size.QuadPart = strlen(test_attributes);
2006 IStream_SetSize(stream, size);
2007 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2008 pos.QuadPart = 0;
2009 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2010 V_VT(&var) = VT_UNKNOWN;
2011 V_UNKNOWN(&var) = (IUnknown*)stream;
2013 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2014 test_seq = content_handler_test_attributes_alternate_4;
2015 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2016 test_seq = content_handler_test_attributes_alternate_6;
2017 else
2018 test_seq = content_handler_test_attributes;
2020 set_expected_seq(test_seq);
2021 hr = ISAXXMLReader_parse(reader, var);
2022 EXPECT_HR(hr, S_OK);
2024 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2025 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2026 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2027 else
2028 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2030 IStream_Release(stream);
2032 V_VT(&var) = VT_BSTR;
2033 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2035 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2036 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2037 test_seq = content_handler_test2_alternate;
2038 else
2039 test_seq = content_handler_test2;
2041 set_expected_seq(test_seq);
2042 hr = ISAXXMLReader_parse(reader, var);
2043 EXPECT_HR(hr, S_OK);
2044 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2046 VariantClear(&var);
2048 /* from file url */
2049 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2050 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2051 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2052 CloseHandle(file);
2054 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2055 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2056 test_seq = content_handler_test1_alternate;
2057 else
2058 test_seq = content_handler_test1;
2059 set_expected_seq(test_seq);
2060 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2061 EXPECT_HR(hr, S_OK);
2062 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2064 /* error handler */
2065 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2066 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2067 test_seq = content_handler_testerror_alternate;
2068 else
2069 test_seq = content_handler_testerror;
2070 set_expected_seq(test_seq);
2071 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2072 EXPECT_HR(hr, E_FAIL);
2073 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2075 /* callback ret values */
2076 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2077 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2079 test_seq = content_handler_test_callback_rets_alt;
2080 set_expected_seq(test_seq);
2081 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2082 EXPECT_HR(hr, S_OK);
2084 else
2086 test_seq = content_handler_test_callback_rets;
2087 set_expected_seq(test_seq);
2088 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2089 EXPECT_HR(hr, S_FALSE);
2091 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2093 DeleteFileA(testXmlA);
2095 /* parse from IXMLDOMDocument */
2096 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2097 &IID_IXMLDOMDocument, (void**)&doc);
2098 EXPECT_HR(hr, S_OK);
2100 str = SysAllocString(szSimpleXML);
2101 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2102 EXPECT_HR(hr, S_OK);
2103 SysFreeString(str);
2105 V_VT(&var) = VT_UNKNOWN;
2106 V_UNKNOWN(&var) = (IUnknown*)doc;
2108 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2109 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2110 test_seq = content_handler_test2_alternate;
2111 else
2112 test_seq = content_handler_test2;
2114 set_expected_seq(test_seq);
2115 hr = ISAXXMLReader_parse(reader, var);
2116 EXPECT_HR(hr, S_OK);
2117 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2118 IXMLDOMDocument_Release(doc);
2120 /* xml:space test */
2121 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2122 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2124 test_seq = xmlspaceattr_test_alternate;
2126 else
2127 test_seq = xmlspaceattr_test;
2129 set_expected_seq(test_seq);
2130 V_VT(&var) = VT_BSTR;
2131 V_BSTR(&var) = _bstr_(xmlspace_attr);
2132 hr = ISAXXMLReader_parse(reader, var);
2133 EXPECT_HR(hr, S_OK);
2135 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2136 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2138 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2140 else
2141 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2143 /* switch off 'namespaces' feature */
2144 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2145 EXPECT_HR(hr, S_OK);
2147 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2148 size.QuadPart = strlen(test_attributes);
2149 IStream_SetSize(stream, size);
2150 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2151 pos.QuadPart = 0;
2152 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2153 V_VT(&var) = VT_UNKNOWN;
2154 V_UNKNOWN(&var) = (IUnknown*)stream;
2156 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2157 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2159 test_seq = content_handler_test_attributes_alt_no_ns;
2161 else
2162 test_seq = content_handler_test_attributes;
2164 set_expected_seq(test_seq);
2165 hr = ISAXXMLReader_parse(reader, var);
2166 EXPECT_HR(hr, S_OK);
2167 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2168 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2169 EXPECT_HR(hr, S_OK);
2171 /* switch off 'namespace-prefixes' feature */
2172 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2173 EXPECT_HR(hr, S_OK);
2175 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2176 size.QuadPart = strlen(test_attributes);
2177 IStream_SetSize(stream, size);
2178 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2179 pos.QuadPart = 0;
2180 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2181 V_VT(&var) = VT_UNKNOWN;
2182 V_UNKNOWN(&var) = (IUnknown*)stream;
2184 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2185 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2187 test_seq = content_handler_test_attributes_alt_no_prefix;
2189 else
2190 test_seq = content_handler_test_attributes_no_prefix;
2192 set_expected_seq(test_seq);
2193 hr = ISAXXMLReader_parse(reader, var);
2194 EXPECT_HR(hr, S_OK);
2195 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2197 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2198 EXPECT_HR(hr, S_OK);
2200 /* attribute normalization */
2201 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2202 size.QuadPart = strlen(attribute_normalize);
2203 IStream_SetSize(stream, size);
2204 IStream_Write(stream, attribute_normalize, strlen(attribute_normalize), &written);
2205 pos.QuadPart = 0;
2206 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2207 V_VT(&var) = VT_UNKNOWN;
2208 V_UNKNOWN(&var) = (IUnknown*)stream;
2210 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2211 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2213 test_seq = attribute_norm_alt;
2215 else
2216 test_seq = attribute_norm;
2218 set_expected_seq(test_seq);
2219 hr = ISAXXMLReader_parse(reader, var);
2220 EXPECT_HR(hr, S_OK);
2221 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2223 ISAXXMLReader_Release(reader);
2224 table++;
2227 free_bstrs();
2230 struct saxreader_props_test_t
2232 const char *prop_name;
2233 IUnknown *iface;
2236 static struct saxlexicalhandler lexicalhandler;
2237 static struct saxdeclhandler declhandler;
2239 static const struct saxreader_props_test_t props_test_data[] = {
2240 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2241 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2242 { 0 }
2245 static void test_saxreader_properties(void)
2247 const struct saxreader_props_test_t *ptr = props_test_data;
2248 ISAXXMLReader *reader;
2249 HRESULT hr;
2251 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2252 &IID_ISAXXMLReader, (void**)&reader);
2253 EXPECT_HR(hr, S_OK);
2255 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2256 EXPECT_HR(hr, E_POINTER);
2258 while (ptr->prop_name)
2260 VARIANT v;
2261 LONG ref;
2263 init_saxlexicalhandler(&lexicalhandler, S_OK);
2264 init_saxdeclhandler(&declhandler, S_OK);
2266 V_VT(&v) = VT_EMPTY;
2267 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2268 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2269 EXPECT_HR(hr, S_OK);
2270 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2271 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2273 V_VT(&v) = VT_UNKNOWN;
2274 V_UNKNOWN(&v) = ptr->iface;
2275 ref = get_refcount(ptr->iface);
2276 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2277 EXPECT_HR(hr, S_OK);
2278 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2280 V_VT(&v) = VT_EMPTY;
2281 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2283 ref = get_refcount(ptr->iface);
2284 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2285 EXPECT_HR(hr, S_OK);
2286 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2287 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2288 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2289 VariantClear(&v);
2291 V_VT(&v) = VT_EMPTY;
2292 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2293 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2294 EXPECT_HR(hr, S_OK);
2296 V_VT(&v) = VT_EMPTY;
2297 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2298 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2299 EXPECT_HR(hr, S_OK);
2300 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2301 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2303 V_VT(&v) = VT_UNKNOWN;
2304 V_UNKNOWN(&v) = ptr->iface;
2305 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2306 EXPECT_HR(hr, S_OK);
2308 /* only VT_EMPTY seems to be valid to reset property */
2309 V_VT(&v) = VT_I4;
2310 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2311 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2312 EXPECT_HR(hr, E_INVALIDARG);
2314 V_VT(&v) = VT_EMPTY;
2315 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2316 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2317 EXPECT_HR(hr, S_OK);
2318 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2319 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2320 VariantClear(&v);
2322 V_VT(&v) = VT_UNKNOWN;
2323 V_UNKNOWN(&v) = NULL;
2324 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2325 EXPECT_HR(hr, S_OK);
2327 V_VT(&v) = VT_EMPTY;
2328 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2329 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2330 EXPECT_HR(hr, S_OK);
2331 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2332 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2334 /* block QueryInterface on handler riid */
2335 V_VT(&v) = VT_UNKNOWN;
2336 V_UNKNOWN(&v) = ptr->iface;
2337 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2338 EXPECT_HR(hr, S_OK);
2340 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2341 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2343 V_VT(&v) = VT_UNKNOWN;
2344 V_UNKNOWN(&v) = ptr->iface;
2345 EXPECT_REF(ptr->iface, 1);
2346 ref = get_refcount(ptr->iface);
2347 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2348 EXPECT_HR(hr, E_NOINTERFACE);
2349 EXPECT_REF(ptr->iface, 1);
2351 V_VT(&v) = VT_EMPTY;
2352 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2353 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2354 EXPECT_HR(hr, S_OK);
2355 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2356 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2358 ptr++;
2361 ISAXXMLReader_Release(reader);
2362 free_bstrs();
2365 struct feature_ns_entry_t {
2366 const GUID *guid;
2367 const char *clsid;
2368 VARIANT_BOOL value;
2369 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2372 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2373 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2374 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2375 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2376 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2377 { 0 }
2380 static const char *feature_names[] = {
2381 "http://xml.org/sax/features/namespaces",
2382 "http://xml.org/sax/features/namespace-prefixes",
2386 static void test_saxreader_features(void)
2388 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2389 ISAXXMLReader *reader;
2391 while (entry->guid)
2393 VARIANT_BOOL value;
2394 const char **name;
2395 HRESULT hr;
2397 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2398 if (hr != S_OK)
2400 win_skip("can't create %s instance\n", entry->clsid);
2401 entry++;
2402 continue;
2405 name = feature_names;
2406 while (*name)
2408 value = 0xc;
2409 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2410 EXPECT_HR(hr, S_OK);
2411 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2413 value = 0xc;
2414 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2415 EXPECT_HR(hr, S_OK);
2417 value = 0xd;
2418 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2419 EXPECT_HR(hr, S_OK);
2420 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2422 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2423 EXPECT_HR(hr, S_OK);
2424 value = 0xd;
2425 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2426 EXPECT_HR(hr, S_OK);
2427 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2429 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2430 EXPECT_HR(hr, S_OK);
2431 value = 0xd;
2432 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2433 EXPECT_HR(hr, S_OK);
2434 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2436 name++;
2439 ISAXXMLReader_Release(reader);
2441 entry++;
2445 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2446 static const CHAR UTF8BOMTest[] =
2447 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2448 "<a></a>\n";
2450 struct enc_test_entry_t {
2451 const GUID *guid;
2452 const char *clsid;
2453 const char *data;
2454 HRESULT hr;
2455 int todo;
2458 static const struct enc_test_entry_t encoding_test_data[] = {
2459 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2460 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2461 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2462 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2463 { 0 }
2466 static void test_saxreader_encoding(void)
2468 const struct enc_test_entry_t *entry = encoding_test_data;
2469 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2470 static const CHAR testXmlA[] = "test.xml";
2472 while (entry->guid)
2474 ISAXXMLReader *reader;
2475 VARIANT input;
2476 DWORD written;
2477 HANDLE file;
2478 HRESULT hr;
2480 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2481 if (hr != S_OK)
2483 win_skip("can't create %s instance\n", entry->clsid);
2484 entry++;
2485 continue;
2488 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2489 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2490 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2491 CloseHandle(file);
2493 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2494 if (entry->todo)
2495 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2496 else
2497 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2499 DeleteFileA(testXmlA);
2501 /* try BSTR input with no BOM or '<?xml' instruction */
2502 V_VT(&input) = VT_BSTR;
2503 V_BSTR(&input) = _bstr_("<element></element>");
2504 hr = ISAXXMLReader_parse(reader, input);
2505 EXPECT_HR(hr, S_OK);
2507 ISAXXMLReader_Release(reader);
2509 free_bstrs();
2510 entry++;
2514 static void test_mxwriter_handlers(void)
2516 ISAXContentHandler *handler;
2517 IMXWriter *writer, *writer2;
2518 ISAXDeclHandler *decl;
2519 ISAXLexicalHandler *lh;
2520 HRESULT hr;
2522 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2523 &IID_IMXWriter, (void**)&writer);
2524 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2526 EXPECT_REF(writer, 1);
2528 /* ISAXContentHandler */
2529 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2530 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2531 EXPECT_REF(writer, 2);
2532 EXPECT_REF(handler, 2);
2534 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2535 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2536 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2537 EXPECT_REF(writer, 3);
2538 EXPECT_REF(writer2, 3);
2539 IMXWriter_Release(writer2);
2540 ISAXContentHandler_Release(handler);
2542 /* ISAXLexicalHandler */
2543 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2544 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2545 EXPECT_REF(writer, 2);
2546 EXPECT_REF(lh, 2);
2548 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2549 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2550 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2551 EXPECT_REF(writer, 3);
2552 EXPECT_REF(writer2, 3);
2553 IMXWriter_Release(writer2);
2554 ISAXLexicalHandler_Release(lh);
2556 /* ISAXDeclHandler */
2557 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2558 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2559 EXPECT_REF(writer, 2);
2560 EXPECT_REF(lh, 2);
2562 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2563 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2564 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2565 EXPECT_REF(writer, 3);
2566 EXPECT_REF(writer2, 3);
2567 IMXWriter_Release(writer2);
2568 ISAXDeclHandler_Release(decl);
2570 IMXWriter_Release(writer);
2574 static struct msxmlsupported_data_t mxwriter_support_data[] =
2576 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2577 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2578 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2579 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2580 { NULL }
2583 static struct msxmlsupported_data_t mxattributes_support_data[] =
2585 { &CLSID_SAXAttributes, "SAXAttributes" },
2586 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2587 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2588 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2589 { NULL }
2592 struct mxwriter_props_t
2594 const GUID *clsid;
2595 VARIANT_BOOL bom;
2596 VARIANT_BOOL disable_escape;
2597 VARIANT_BOOL indent;
2598 VARIANT_BOOL omitdecl;
2599 VARIANT_BOOL standalone;
2600 const char *encoding;
2603 static const struct mxwriter_props_t mxwriter_default_props[] =
2605 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2606 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2607 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2608 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2609 { NULL }
2612 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2614 int i = 0;
2616 while (table->clsid)
2618 IMXWriter *writer;
2619 VARIANT_BOOL b;
2620 BSTR encoding;
2621 HRESULT hr;
2623 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2625 table++;
2626 i++;
2627 continue;
2630 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2631 &IID_IMXWriter, (void**)&writer);
2632 EXPECT_HR(hr, S_OK);
2634 b = !table->bom;
2635 hr = IMXWriter_get_byteOrderMark(writer, &b);
2636 EXPECT_HR(hr, S_OK);
2637 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2639 b = !table->disable_escape;
2640 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2641 EXPECT_HR(hr, S_OK);
2642 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2643 table->disable_escape);
2645 b = !table->indent;
2646 hr = IMXWriter_get_indent(writer, &b);
2647 EXPECT_HR(hr, S_OK);
2648 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2650 b = !table->omitdecl;
2651 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2652 EXPECT_HR(hr, S_OK);
2653 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2655 b = !table->standalone;
2656 hr = IMXWriter_get_standalone(writer, &b);
2657 EXPECT_HR(hr, S_OK);
2658 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2660 hr = IMXWriter_get_encoding(writer, &encoding);
2661 EXPECT_HR(hr, S_OK);
2662 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2663 i, wine_dbgstr_w(encoding), table->encoding);
2664 SysFreeString(encoding);
2666 IMXWriter_Release(writer);
2668 table++;
2669 i++;
2673 static void test_mxwriter_properties(void)
2675 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2676 static const WCHAR emptyW[] = {0};
2677 static const WCHAR testW[] = {'t','e','s','t',0};
2678 ISAXContentHandler *content;
2679 IMXWriter *writer;
2680 VARIANT_BOOL b;
2681 HRESULT hr;
2682 BSTR str, str2;
2683 VARIANT dest;
2685 test_mxwriter_default_properties(mxwriter_default_props);
2687 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2688 &IID_IMXWriter, (void**)&writer);
2689 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2691 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2692 ok(hr == E_POINTER, "got %08x\n", hr);
2694 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2695 ok(hr == E_POINTER, "got %08x\n", hr);
2697 hr = IMXWriter_get_indent(writer, NULL);
2698 ok(hr == E_POINTER, "got %08x\n", hr);
2700 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2701 ok(hr == E_POINTER, "got %08x\n", hr);
2703 hr = IMXWriter_get_standalone(writer, NULL);
2704 ok(hr == E_POINTER, "got %08x\n", hr);
2706 /* set and check */
2707 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2708 ok(hr == S_OK, "got %08x\n", hr);
2710 b = VARIANT_FALSE;
2711 hr = IMXWriter_get_standalone(writer, &b);
2712 ok(hr == S_OK, "got %08x\n", hr);
2713 ok(b == VARIANT_TRUE, "got %d\n", b);
2715 hr = IMXWriter_get_encoding(writer, NULL);
2716 EXPECT_HR(hr, E_POINTER);
2718 /* UTF-16 is a default setting apparently */
2719 str = (void*)0xdeadbeef;
2720 hr = IMXWriter_get_encoding(writer, &str);
2721 EXPECT_HR(hr, S_OK);
2722 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2724 str2 = (void*)0xdeadbeef;
2725 hr = IMXWriter_get_encoding(writer, &str2);
2726 ok(hr == S_OK, "got %08x\n", hr);
2727 ok(str != str2, "expected newly allocated, got same %p\n", str);
2729 SysFreeString(str2);
2730 SysFreeString(str);
2732 /* put empty string */
2733 str = SysAllocString(emptyW);
2734 hr = IMXWriter_put_encoding(writer, str);
2735 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2736 SysFreeString(str);
2738 str = (void*)0xdeadbeef;
2739 hr = IMXWriter_get_encoding(writer, &str);
2740 EXPECT_HR(hr, S_OK);
2741 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2742 SysFreeString(str);
2744 /* invalid encoding name */
2745 str = SysAllocString(testW);
2746 hr = IMXWriter_put_encoding(writer, str);
2747 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2748 SysFreeString(str);
2750 /* test case sensivity */
2751 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2752 EXPECT_HR(hr, S_OK);
2753 str = (void*)0xdeadbeef;
2754 hr = IMXWriter_get_encoding(writer, &str);
2755 EXPECT_HR(hr, S_OK);
2756 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2757 SysFreeString(str);
2759 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2760 EXPECT_HR(hr, S_OK);
2761 str = (void*)0xdeadbeef;
2762 hr = IMXWriter_get_encoding(writer, &str);
2763 EXPECT_HR(hr, S_OK);
2764 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2765 SysFreeString(str);
2767 /* how it affects document creation */
2768 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2769 EXPECT_HR(hr, S_OK);
2771 hr = ISAXContentHandler_startDocument(content);
2772 EXPECT_HR(hr, S_OK);
2773 hr = ISAXContentHandler_endDocument(content);
2774 EXPECT_HR(hr, S_OK);
2776 V_VT(&dest) = VT_EMPTY;
2777 hr = IMXWriter_get_output(writer, &dest);
2778 EXPECT_HR(hr, S_OK);
2779 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2780 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2781 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2782 VariantClear(&dest);
2783 ISAXContentHandler_Release(content);
2785 hr = IMXWriter_get_version(writer, NULL);
2786 ok(hr == E_POINTER, "got %08x\n", hr);
2787 /* default version is 'surprisingly' 1.0 */
2788 hr = IMXWriter_get_version(writer, &str);
2789 ok(hr == S_OK, "got %08x\n", hr);
2790 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2791 SysFreeString(str);
2793 /* store version string as is */
2794 hr = IMXWriter_put_version(writer, NULL);
2795 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2797 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2798 ok(hr == S_OK, "got %08x\n", hr);
2800 hr = IMXWriter_put_version(writer, _bstr_(""));
2801 ok(hr == S_OK, "got %08x\n", hr);
2802 hr = IMXWriter_get_version(writer, &str);
2803 ok(hr == S_OK, "got %08x\n", hr);
2804 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2805 SysFreeString(str);
2807 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2808 ok(hr == S_OK, "got %08x\n", hr);
2809 hr = IMXWriter_get_version(writer, &str);
2810 ok(hr == S_OK, "got %08x\n", hr);
2811 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2812 SysFreeString(str);
2814 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2815 ok(hr == S_OK, "got %08x\n", hr);
2816 hr = IMXWriter_get_version(writer, &str);
2817 ok(hr == S_OK, "got %08x\n", hr);
2818 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2819 SysFreeString(str);
2821 IMXWriter_Release(writer);
2822 free_bstrs();
2825 static void test_mxwriter_flush(void)
2827 static const WCHAR emptyW[] = {0};
2828 ISAXContentHandler *content;
2829 IMXWriter *writer;
2830 LARGE_INTEGER pos;
2831 ULARGE_INTEGER pos2;
2832 IStream *stream;
2833 VARIANT dest;
2834 HRESULT hr;
2835 char *buff;
2836 LONG ref;
2837 int len;
2839 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2840 &IID_IMXWriter, (void**)&writer);
2841 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2843 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2844 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2845 EXPECT_REF(stream, 1);
2847 /* detach when nothing was attached */
2848 V_VT(&dest) = VT_EMPTY;
2849 hr = IMXWriter_put_output(writer, dest);
2850 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2852 /* attach stream */
2853 V_VT(&dest) = VT_UNKNOWN;
2854 V_UNKNOWN(&dest) = (IUnknown*)stream;
2855 hr = IMXWriter_put_output(writer, dest);
2856 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2857 todo_wine EXPECT_REF(stream, 3);
2859 /* detach setting VT_EMPTY destination */
2860 V_VT(&dest) = VT_EMPTY;
2861 hr = IMXWriter_put_output(writer, dest);
2862 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2863 EXPECT_REF(stream, 1);
2865 V_VT(&dest) = VT_UNKNOWN;
2866 V_UNKNOWN(&dest) = (IUnknown*)stream;
2867 hr = IMXWriter_put_output(writer, dest);
2868 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2870 /* flush() doesn't detach a stream */
2871 hr = IMXWriter_flush(writer);
2872 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2873 todo_wine EXPECT_REF(stream, 3);
2875 pos.QuadPart = 0;
2876 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2877 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2878 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2880 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2881 ok(hr == S_OK, "got %08x\n", hr);
2883 hr = ISAXContentHandler_startDocument(content);
2884 ok(hr == S_OK, "got %08x\n", hr);
2886 pos.QuadPart = 0;
2887 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2888 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2889 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2891 /* already started */
2892 hr = ISAXContentHandler_startDocument(content);
2893 ok(hr == S_OK, "got %08x\n", hr);
2895 hr = ISAXContentHandler_endDocument(content);
2896 ok(hr == S_OK, "got %08x\n", hr);
2898 /* flushed on endDocument() */
2899 pos.QuadPart = 0;
2900 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2901 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2902 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2904 IStream_Release(stream);
2906 /* auto-flush feature */
2907 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2908 EXPECT_HR(hr, S_OK);
2909 EXPECT_REF(stream, 1);
2911 V_VT(&dest) = VT_UNKNOWN;
2912 V_UNKNOWN(&dest) = (IUnknown*)stream;
2913 hr = IMXWriter_put_output(writer, dest);
2914 EXPECT_HR(hr, S_OK);
2916 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
2917 EXPECT_HR(hr, S_OK);
2919 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2920 EXPECT_HR(hr, S_OK);
2922 hr = ISAXContentHandler_startDocument(content);
2923 EXPECT_HR(hr, S_OK);
2925 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
2926 EXPECT_HR(hr, S_OK);
2928 /* internal buffer is flushed automatically on certain threshold */
2929 pos.QuadPart = 0;
2930 pos2.QuadPart = 1;
2931 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2932 EXPECT_HR(hr, S_OK);
2933 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2935 len = 2048;
2936 buff = HeapAlloc(GetProcessHeap(), 0, len);
2937 memset(buff, 'A', len);
2938 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
2939 EXPECT_HR(hr, S_OK);
2941 pos.QuadPart = 0;
2942 pos2.QuadPart = 0;
2943 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2944 EXPECT_HR(hr, S_OK);
2945 todo_wine
2946 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
2948 hr = IMXWriter_get_output(writer, NULL);
2949 EXPECT_HR(hr, E_POINTER);
2951 ref = get_refcount(stream);
2952 V_VT(&dest) = VT_EMPTY;
2953 hr = IMXWriter_get_output(writer, &dest);
2954 EXPECT_HR(hr, S_OK);
2955 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
2956 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
2957 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
2958 VariantClear(&dest);
2960 hr = ISAXContentHandler_endDocument(content);
2961 EXPECT_HR(hr, S_OK);
2963 IStream_Release(stream);
2965 /* test char count lower than threshold */
2966 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2967 EXPECT_HR(hr, S_OK);
2968 EXPECT_REF(stream, 1);
2970 hr = ISAXContentHandler_startDocument(content);
2971 EXPECT_HR(hr, S_OK);
2973 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
2974 EXPECT_HR(hr, S_OK);
2976 pos.QuadPart = 0;
2977 pos2.QuadPart = 1;
2978 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2979 EXPECT_HR(hr, S_OK);
2980 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2982 memset(buff, 'A', len);
2983 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
2984 EXPECT_HR(hr, S_OK);
2986 pos.QuadPart = 0;
2987 pos2.QuadPart = 1;
2988 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2989 EXPECT_HR(hr, S_OK);
2990 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2992 hr = ISAXContentHandler_endDocument(content);
2993 EXPECT_HR(hr, S_OK);
2995 /* test auto-flush function when stream is not set */
2996 V_VT(&dest) = VT_EMPTY;
2997 hr = IMXWriter_put_output(writer, dest);
2998 EXPECT_HR(hr, S_OK);
3000 hr = ISAXContentHandler_startDocument(content);
3001 EXPECT_HR(hr, S_OK);
3003 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3004 EXPECT_HR(hr, S_OK);
3006 memset(buff, 'A', len);
3007 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3008 EXPECT_HR(hr, S_OK);
3010 V_VT(&dest) = VT_EMPTY;
3011 hr = IMXWriter_get_output(writer, &dest);
3012 EXPECT_HR(hr, S_OK);
3013 len += strlen("<a>");
3014 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3015 VariantClear(&dest);
3017 HeapFree(GetProcessHeap(), 0, buff);
3018 ISAXContentHandler_Release(content);
3019 IStream_Release(stream);
3020 IMXWriter_Release(writer);
3021 free_bstrs();
3024 static void test_mxwriter_startenddocument(void)
3026 ISAXContentHandler *content;
3027 IMXWriter *writer;
3028 VARIANT dest;
3029 HRESULT hr;
3031 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3032 &IID_IMXWriter, (void**)&writer);
3033 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3035 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3036 ok(hr == S_OK, "got %08x\n", hr);
3038 hr = ISAXContentHandler_startDocument(content);
3039 ok(hr == S_OK, "got %08x\n", hr);
3041 hr = ISAXContentHandler_endDocument(content);
3042 ok(hr == S_OK, "got %08x\n", hr);
3044 V_VT(&dest) = VT_EMPTY;
3045 hr = IMXWriter_get_output(writer, &dest);
3046 ok(hr == S_OK, "got %08x\n", hr);
3047 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3048 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3049 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3050 VariantClear(&dest);
3052 /* now try another startDocument */
3053 hr = ISAXContentHandler_startDocument(content);
3054 ok(hr == S_OK, "got %08x\n", hr);
3055 /* and get duplicated prolog */
3056 V_VT(&dest) = VT_EMPTY;
3057 hr = IMXWriter_get_output(writer, &dest);
3058 ok(hr == S_OK, "got %08x\n", hr);
3059 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3060 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3061 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3062 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3063 VariantClear(&dest);
3065 ISAXContentHandler_Release(content);
3066 IMXWriter_Release(writer);
3068 /* now with omitted declaration */
3069 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3070 &IID_IMXWriter, (void**)&writer);
3071 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3073 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3074 ok(hr == S_OK, "got %08x\n", hr);
3076 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3077 ok(hr == S_OK, "got %08x\n", hr);
3079 hr = ISAXContentHandler_startDocument(content);
3080 ok(hr == S_OK, "got %08x\n", hr);
3082 hr = ISAXContentHandler_endDocument(content);
3083 ok(hr == S_OK, "got %08x\n", hr);
3085 V_VT(&dest) = VT_EMPTY;
3086 hr = IMXWriter_get_output(writer, &dest);
3087 ok(hr == S_OK, "got %08x\n", hr);
3088 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3089 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3090 VariantClear(&dest);
3092 ISAXContentHandler_Release(content);
3093 IMXWriter_Release(writer);
3095 free_bstrs();
3098 enum startendtype
3100 StartElement = 0x001,
3101 EndElement = 0x010,
3102 StartEndElement = 0x011,
3103 DisableEscaping = 0x100
3106 struct writer_startendelement_t {
3107 const GUID *clsid;
3108 enum startendtype type;
3109 const char *uri;
3110 const char *local_name;
3111 const char *qname;
3112 const char *output;
3113 HRESULT hr;
3114 ISAXAttributes *attr;
3117 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\">";
3118 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\"/>";
3119 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
3121 static const struct writer_startendelement_t writer_startendelement[] = {
3122 /* 0 */
3123 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3124 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3125 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3126 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3127 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3128 /* 5 */
3129 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3130 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3131 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3132 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3133 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3134 /* 10 */
3135 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3136 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3137 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3138 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3139 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3140 /* 15 */
3141 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3142 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3143 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3144 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3145 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3146 /* 20 */
3147 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3148 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3149 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3150 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3151 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3152 /* 25 */
3153 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3154 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3155 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3156 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3157 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3158 /* 30 */
3159 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3160 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3161 /* endElement tests */
3162 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3163 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3164 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3165 /* 35 */
3166 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3167 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3168 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3169 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3170 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3171 /* 40 */
3172 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3173 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3174 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3175 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3176 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3177 /* 45 */
3178 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3179 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3180 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3181 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3182 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3183 /* 50 */
3184 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3185 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3186 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3187 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3188 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3189 /* 55 */
3190 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3191 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3192 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3193 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3194 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3195 /* 60 */
3196 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3197 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3198 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3199 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3201 /* with attributes */
3202 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3203 /* 65 */
3204 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3205 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3206 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3207 /* empty elements */
3208 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3209 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3210 /* 70 */
3211 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3212 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3213 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3214 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3215 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3216 /* 75 */
3217 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3219 /* with disabled output escaping */
3220 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3221 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3222 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3223 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3225 { NULL }
3228 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3230 while (table->clsid)
3232 IUnknown *unk;
3233 HRESULT hr;
3235 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3236 if (hr == S_OK) IUnknown_Release(unk);
3238 table->supported = hr == S_OK;
3239 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3241 table++;
3245 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3247 int i = 0;
3249 while (table->clsid)
3251 ISAXContentHandler *content;
3252 IMXWriter *writer;
3253 HRESULT hr;
3255 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3257 table++;
3258 i++;
3259 continue;
3262 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3263 &IID_IMXWriter, (void**)&writer);
3264 EXPECT_HR(hr, S_OK);
3266 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3267 EXPECT_HR(hr, S_OK);
3269 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3270 EXPECT_HR(hr, S_OK);
3272 hr = ISAXContentHandler_startDocument(content);
3273 EXPECT_HR(hr, S_OK);
3275 if (table->type & DisableEscaping)
3277 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3278 EXPECT_HR(hr, S_OK);
3281 if (table->type & StartElement)
3283 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3284 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3285 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3288 if (table->type & EndElement)
3290 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3291 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3292 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3295 /* test output */
3296 if (hr == S_OK)
3298 VARIANT dest;
3300 V_VT(&dest) = VT_EMPTY;
3301 hr = IMXWriter_get_output(writer, &dest);
3302 EXPECT_HR(hr, S_OK);
3303 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3304 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3305 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3306 VariantClear(&dest);
3309 ISAXContentHandler_Release(content);
3310 IMXWriter_Release(writer);
3312 table++;
3313 i++;
3316 free_bstrs();
3319 /* point of these test is to start/end element with different names and name lengths */
3320 struct writer_startendelement2_t {
3321 const GUID *clsid;
3322 const char *qnamestart;
3323 int qnamestart_len;
3324 const char *qnameend;
3325 int qnameend_len;
3326 const char *output;
3327 HRESULT hr;
3330 static const struct writer_startendelement2_t writer_startendelement2[] = {
3331 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3332 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3333 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3334 /* -1 length is not allowed for version 6 */
3335 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3337 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3338 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3339 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3340 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3341 { NULL }
3344 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3346 int i = 0;
3348 while (table->clsid)
3350 ISAXContentHandler *content;
3351 IMXWriter *writer;
3352 HRESULT hr;
3354 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3356 table++;
3357 i++;
3358 continue;
3361 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3362 &IID_IMXWriter, (void**)&writer);
3363 EXPECT_HR(hr, S_OK);
3365 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3366 EXPECT_HR(hr, S_OK);
3368 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3369 EXPECT_HR(hr, S_OK);
3371 hr = ISAXContentHandler_startDocument(content);
3372 EXPECT_HR(hr, S_OK);
3374 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3375 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3376 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3378 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3379 _bstr_(table->qnameend), table->qnameend_len);
3380 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3382 /* test output */
3383 if (hr == S_OK)
3385 VARIANT dest;
3387 V_VT(&dest) = VT_EMPTY;
3388 hr = IMXWriter_get_output(writer, &dest);
3389 EXPECT_HR(hr, S_OK);
3390 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3391 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3392 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3393 VariantClear(&dest);
3396 ISAXContentHandler_Release(content);
3397 IMXWriter_Release(writer);
3399 table++;
3400 i++;
3402 free_bstrs();
3407 static void test_mxwriter_startendelement(void)
3409 ISAXContentHandler *content;
3410 IMXWriter *writer;
3411 VARIANT dest;
3412 HRESULT hr;
3414 test_mxwriter_startendelement_batch(writer_startendelement);
3415 test_mxwriter_startendelement_batch2(writer_startendelement2);
3417 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3418 &IID_IMXWriter, (void**)&writer);
3419 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3421 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3422 ok(hr == S_OK, "got %08x\n", hr);
3424 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3425 ok(hr == S_OK, "got %08x\n", hr);
3427 hr = ISAXContentHandler_startDocument(content);
3428 ok(hr == S_OK, "got %08x\n", hr);
3430 /* all string pointers should be not null */
3431 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3432 ok(hr == S_OK, "got %08x\n", hr);
3434 V_VT(&dest) = VT_EMPTY;
3435 hr = IMXWriter_get_output(writer, &dest);
3436 ok(hr == S_OK, "got %08x\n", hr);
3437 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3438 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3439 VariantClear(&dest);
3441 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3442 ok(hr == S_OK, "got %08x\n", hr);
3444 V_VT(&dest) = VT_EMPTY;
3445 hr = IMXWriter_get_output(writer, &dest);
3446 ok(hr == S_OK, "got %08x\n", hr);
3447 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3448 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3449 VariantClear(&dest);
3451 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3452 EXPECT_HR(hr, E_INVALIDARG);
3454 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3455 EXPECT_HR(hr, E_INVALIDARG);
3457 /* only local name is an error too */
3458 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3459 EXPECT_HR(hr, E_INVALIDARG);
3461 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3462 EXPECT_HR(hr, S_OK);
3464 V_VT(&dest) = VT_EMPTY;
3465 hr = IMXWriter_get_output(writer, &dest);
3466 EXPECT_HR(hr, S_OK);
3467 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3468 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3469 VariantClear(&dest);
3471 hr = ISAXContentHandler_endDocument(content);
3472 EXPECT_HR(hr, S_OK);
3474 V_VT(&dest) = VT_EMPTY;
3475 hr = IMXWriter_put_output(writer, dest);
3476 EXPECT_HR(hr, S_OK);
3478 V_VT(&dest) = VT_EMPTY;
3479 hr = IMXWriter_get_output(writer, &dest);
3480 EXPECT_HR(hr, S_OK);
3481 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3482 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3483 VariantClear(&dest);
3485 hr = ISAXContentHandler_startDocument(content);
3486 EXPECT_HR(hr, S_OK);
3488 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3489 EXPECT_HR(hr, S_OK);
3491 V_VT(&dest) = VT_EMPTY;
3492 hr = IMXWriter_get_output(writer, &dest);
3493 EXPECT_HR(hr, S_OK);
3494 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3495 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3496 VariantClear(&dest);
3498 ISAXContentHandler_endDocument(content);
3499 IMXWriter_flush(writer);
3501 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3502 EXPECT_HR(hr, S_OK);
3503 V_VT(&dest) = VT_EMPTY;
3504 hr = IMXWriter_get_output(writer, &dest);
3505 EXPECT_HR(hr, S_OK);
3506 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3507 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3508 VariantClear(&dest);
3510 V_VT(&dest) = VT_EMPTY;
3511 hr = IMXWriter_put_output(writer, dest);
3512 EXPECT_HR(hr, S_OK);
3514 /* length -1 */
3515 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3516 EXPECT_HR(hr, S_OK);
3517 V_VT(&dest) = VT_EMPTY;
3518 hr = IMXWriter_get_output(writer, &dest);
3519 EXPECT_HR(hr, S_OK);
3520 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3521 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3522 VariantClear(&dest);
3524 ISAXContentHandler_Release(content);
3525 IMXWriter_Release(writer);
3526 free_bstrs();
3529 struct writer_characters_t {
3530 const GUID *clsid;
3531 const char *data;
3532 const char *output;
3535 static const struct writer_characters_t writer_characters[] = {
3536 { &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
3537 { &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
3538 { &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
3539 { &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
3540 { NULL }
3543 static void test_mxwriter_characters(void)
3545 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3546 const struct writer_characters_t *table = writer_characters;
3547 ISAXContentHandler *content;
3548 IMXWriter *writer;
3549 VARIANT dest;
3550 HRESULT hr;
3551 int i = 0;
3553 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3554 &IID_IMXWriter, (void**)&writer);
3555 EXPECT_HR(hr, S_OK);
3557 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3558 EXPECT_HR(hr, S_OK);
3560 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3561 EXPECT_HR(hr, S_OK);
3563 hr = ISAXContentHandler_startDocument(content);
3564 EXPECT_HR(hr, S_OK);
3566 hr = ISAXContentHandler_characters(content, NULL, 0);
3567 EXPECT_HR(hr, E_INVALIDARG);
3569 hr = ISAXContentHandler_characters(content, chardataW, 0);
3570 EXPECT_HR(hr, S_OK);
3572 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3573 EXPECT_HR(hr, S_OK);
3575 V_VT(&dest) = VT_EMPTY;
3576 hr = IMXWriter_get_output(writer, &dest);
3577 EXPECT_HR(hr, S_OK);
3578 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3579 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3580 VariantClear(&dest);
3582 hr = ISAXContentHandler_endDocument(content);
3583 EXPECT_HR(hr, S_OK);
3585 ISAXContentHandler_Release(content);
3586 IMXWriter_Release(writer);
3588 /* try empty characters data to see if element is closed */
3589 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3590 &IID_IMXWriter, (void**)&writer);
3591 EXPECT_HR(hr, S_OK);
3593 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3594 EXPECT_HR(hr, S_OK);
3596 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3597 EXPECT_HR(hr, S_OK);
3599 hr = ISAXContentHandler_startDocument(content);
3600 EXPECT_HR(hr, S_OK);
3602 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3603 EXPECT_HR(hr, S_OK);
3605 hr = ISAXContentHandler_characters(content, chardataW, 0);
3606 EXPECT_HR(hr, S_OK);
3608 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3609 EXPECT_HR(hr, S_OK);
3611 V_VT(&dest) = VT_EMPTY;
3612 hr = IMXWriter_get_output(writer, &dest);
3613 EXPECT_HR(hr, S_OK);
3614 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3615 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3616 VariantClear(&dest);
3618 ISAXContentHandler_Release(content);
3619 IMXWriter_Release(writer);
3621 /* batch tests */
3622 while (table->clsid)
3624 ISAXContentHandler *content;
3625 IMXWriter *writer;
3626 VARIANT dest;
3627 HRESULT hr;
3629 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3631 table++;
3632 i++;
3633 continue;
3636 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3637 &IID_IMXWriter, (void**)&writer);
3638 EXPECT_HR(hr, S_OK);
3640 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3641 EXPECT_HR(hr, S_OK);
3643 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3644 EXPECT_HR(hr, S_OK);
3646 hr = ISAXContentHandler_startDocument(content);
3647 EXPECT_HR(hr, S_OK);
3649 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3650 EXPECT_HR(hr, S_OK);
3652 /* test output */
3653 if (hr == S_OK)
3655 V_VT(&dest) = VT_EMPTY;
3656 hr = IMXWriter_get_output(writer, &dest);
3657 EXPECT_HR(hr, S_OK);
3658 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3659 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3660 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3661 VariantClear(&dest);
3664 /* with disabled escaping */
3665 V_VT(&dest) = VT_EMPTY;
3666 hr = IMXWriter_put_output(writer, dest);
3667 EXPECT_HR(hr, S_OK);
3669 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3670 EXPECT_HR(hr, S_OK);
3672 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3673 EXPECT_HR(hr, S_OK);
3675 /* test output */
3676 if (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_(table->data), V_BSTR(&dest)),
3683 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3684 VariantClear(&dest);
3687 ISAXContentHandler_Release(content);
3688 IMXWriter_Release(writer);
3690 table++;
3691 i++;
3694 free_bstrs();
3697 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3699 VARIANT_TRUE,"UTF-16",
3701 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3702 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3703 {TRUE}
3707 VARIANT_FALSE,"UTF-16",
3709 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3710 {TRUE}
3714 VARIANT_TRUE,"UTF-8",
3716 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3717 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3718 * and the writer is released.
3720 {FALSE,NULL,0},
3721 {TRUE}
3725 VARIANT_TRUE,"utf-8",
3727 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3728 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3729 * and the writer is released.
3731 {FALSE,NULL,0},
3732 {TRUE}
3736 VARIANT_TRUE,"UTF-16",
3738 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3739 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3740 {TRUE}
3744 VARIANT_TRUE,"UTF-16",
3746 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3747 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3748 {TRUE}
3753 static void test_mxwriter_stream(void)
3755 IMXWriter *writer;
3756 ISAXContentHandler *content;
3757 HRESULT hr;
3758 VARIANT dest;
3759 IStream *stream;
3760 LARGE_INTEGER pos;
3761 ULARGE_INTEGER pos2;
3762 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3764 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3765 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3767 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3768 &IID_IMXWriter, (void**)&writer);
3769 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3771 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3772 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3774 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3775 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3777 V_VT(&dest) = VT_UNKNOWN;
3778 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3779 hr = IMXWriter_put_output(writer, dest);
3780 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3781 VariantClear(&dest);
3783 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3784 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3786 current_write_test = test->expected_writes;
3788 hr = ISAXContentHandler_startDocument(content);
3789 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3791 hr = ISAXContentHandler_endDocument(content);
3792 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3794 ISAXContentHandler_Release(content);
3795 IMXWriter_Release(writer);
3797 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3798 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3801 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3802 &IID_IMXWriter, (void**)&writer);
3803 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3805 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3806 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3808 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3809 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3811 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3812 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3814 V_VT(&dest) = VT_UNKNOWN;
3815 V_UNKNOWN(&dest) = (IUnknown*)stream;
3816 hr = IMXWriter_put_output(writer, dest);
3817 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3819 hr = ISAXContentHandler_startDocument(content);
3820 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3822 /* Setting output of the mxwriter causes the current output to be flushed,
3823 * and the writer to start over.
3825 V_VT(&dest) = VT_EMPTY;
3826 hr = IMXWriter_put_output(writer, dest);
3827 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3829 pos.QuadPart = 0;
3830 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3831 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3832 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3834 hr = ISAXContentHandler_startDocument(content);
3835 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3837 hr = ISAXContentHandler_endDocument(content);
3838 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3840 V_VT(&dest) = VT_EMPTY;
3841 hr = IMXWriter_get_output(writer, &dest);
3842 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3843 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3844 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3845 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3846 VariantClear(&dest);
3848 /* test when BOM is written to output stream */
3849 V_VT(&dest) = VT_EMPTY;
3850 hr = IMXWriter_put_output(writer, dest);
3851 EXPECT_HR(hr, S_OK);
3853 pos.QuadPart = 0;
3854 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3855 EXPECT_HR(hr, S_OK);
3857 V_VT(&dest) = VT_UNKNOWN;
3858 V_UNKNOWN(&dest) = (IUnknown*)stream;
3859 hr = IMXWriter_put_output(writer, dest);
3860 EXPECT_HR(hr, S_OK);
3862 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3863 EXPECT_HR(hr, S_OK);
3865 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3866 EXPECT_HR(hr, S_OK);
3868 hr = ISAXContentHandler_startDocument(content);
3869 EXPECT_HR(hr, S_OK);
3871 pos.QuadPart = 0;
3872 pos2.QuadPart = 0;
3873 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3874 EXPECT_HR(hr, S_OK);
3875 ok(pos2.QuadPart == 2, "got wrong position\n");
3877 ISAXContentHandler_Release(content);
3878 IMXWriter_Release(writer);
3880 free_bstrs();
3883 static const char *encoding_names[] = {
3884 "iso-8859-1",
3885 "iso-8859-2",
3886 "iso-8859-3",
3887 "iso-8859-4",
3888 "iso-8859-5",
3889 "iso-8859-7",
3890 "iso-8859-9",
3891 "iso-8859-13",
3892 "iso-8859-15",
3893 NULL
3896 static void test_mxwriter_encoding(void)
3898 ISAXContentHandler *content;
3899 IMXWriter *writer;
3900 IStream *stream;
3901 const char *enc;
3902 VARIANT dest;
3903 HRESULT hr;
3904 HGLOBAL g;
3905 char *ptr;
3906 BSTR s;
3907 int i;
3909 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3910 &IID_IMXWriter, (void**)&writer);
3911 EXPECT_HR(hr, S_OK);
3913 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3914 EXPECT_HR(hr, S_OK);
3916 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3917 EXPECT_HR(hr, S_OK);
3919 hr = ISAXContentHandler_startDocument(content);
3920 EXPECT_HR(hr, S_OK);
3922 hr = ISAXContentHandler_endDocument(content);
3923 EXPECT_HR(hr, S_OK);
3925 /* The content is always re-encoded to UTF-16 when the output is
3926 * retrieved as a BSTR.
3928 V_VT(&dest) = VT_EMPTY;
3929 hr = IMXWriter_get_output(writer, &dest);
3930 EXPECT_HR(hr, S_OK);
3931 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3932 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3933 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3934 VariantClear(&dest);
3936 /* switch encoding when something is written already */
3937 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3938 EXPECT_HR(hr, S_OK);
3940 V_VT(&dest) = VT_UNKNOWN;
3941 V_UNKNOWN(&dest) = (IUnknown*)stream;
3942 hr = IMXWriter_put_output(writer, dest);
3943 EXPECT_HR(hr, S_OK);
3945 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3946 EXPECT_HR(hr, S_OK);
3948 /* write empty element */
3949 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3950 EXPECT_HR(hr, S_OK);
3952 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3953 EXPECT_HR(hr, S_OK);
3955 /* switch */
3956 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3957 EXPECT_HR(hr, S_OK);
3959 hr = IMXWriter_flush(writer);
3960 EXPECT_HR(hr, S_OK);
3962 hr = GetHGlobalFromStream(stream, &g);
3963 EXPECT_HR(hr, S_OK);
3965 ptr = GlobalLock(g);
3966 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3967 GlobalUnlock(g);
3969 /* so output is unaffected, encoding name is stored however */
3970 hr = IMXWriter_get_encoding(writer, &s);
3971 EXPECT_HR(hr, S_OK);
3972 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3973 SysFreeString(s);
3975 IStream_Release(stream);
3977 i = 0;
3978 enc = encoding_names[i];
3979 while (enc)
3981 char expectedA[200];
3983 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3984 EXPECT_HR(hr, S_OK);
3986 V_VT(&dest) = VT_UNKNOWN;
3987 V_UNKNOWN(&dest) = (IUnknown*)stream;
3988 hr = IMXWriter_put_output(writer, dest);
3989 EXPECT_HR(hr, S_OK);
3991 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
3992 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
3993 "%s: encoding not accepted\n", enc);
3994 if (hr != S_OK)
3996 enc = encoding_names[++i];
3997 IStream_Release(stream);
3998 continue;
4001 hr = ISAXContentHandler_startDocument(content);
4002 EXPECT_HR(hr, S_OK);
4004 hr = ISAXContentHandler_endDocument(content);
4005 EXPECT_HR(hr, S_OK);
4007 hr = IMXWriter_flush(writer);
4008 EXPECT_HR(hr, S_OK);
4010 /* prepare expected string */
4011 *expectedA = 0;
4012 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4013 strcat(expectedA, enc);
4014 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4016 hr = GetHGlobalFromStream(stream, &g);
4017 EXPECT_HR(hr, S_OK);
4019 ptr = GlobalLock(g);
4020 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4021 GlobalUnlock(g);
4023 V_VT(&dest) = VT_EMPTY;
4024 hr = IMXWriter_put_output(writer, dest);
4025 EXPECT_HR(hr, S_OK);
4027 IStream_Release(stream);
4029 enc = encoding_names[++i];
4032 ISAXContentHandler_Release(content);
4033 IMXWriter_Release(writer);
4035 free_bstrs();
4038 static void test_obj_dispex(IUnknown *obj)
4040 static const WCHAR starW[] = {'*',0};
4041 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4042 IDispatchEx *dispex;
4043 IUnknown *unk;
4044 DWORD props;
4045 UINT ticnt;
4046 HRESULT hr;
4047 BSTR name;
4049 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4050 EXPECT_HR(hr, S_OK);
4051 if (FAILED(hr)) return;
4053 ticnt = 0;
4054 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4055 EXPECT_HR(hr, S_OK);
4056 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4058 name = SysAllocString(starW);
4059 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4060 EXPECT_HR(hr, E_NOTIMPL);
4061 SysFreeString(name);
4063 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4064 EXPECT_HR(hr, E_NOTIMPL);
4066 props = 0;
4067 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4068 EXPECT_HR(hr, E_NOTIMPL);
4069 ok(props == 0, "expected 0 got %d\n", props);
4071 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4072 EXPECT_HR(hr, E_NOTIMPL);
4073 if (SUCCEEDED(hr)) SysFreeString(name);
4075 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4076 EXPECT_HR(hr, E_NOTIMPL);
4078 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4079 EXPECT_HR(hr, E_NOTIMPL);
4080 if (hr == S_OK && unk) IUnknown_Release(unk);
4082 IDispatchEx_Release(dispex);
4085 static void test_dispex(void)
4087 IVBSAXXMLReader *vbreader;
4088 ISAXXMLReader *reader;
4089 IUnknown *unk;
4090 HRESULT hr;
4092 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4093 &IID_ISAXXMLReader, (void**)&reader);
4094 EXPECT_HR(hr, S_OK);
4096 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4097 EXPECT_HR(hr, S_OK);
4098 test_obj_dispex(unk);
4099 IUnknown_Release(unk);
4101 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4102 EXPECT_HR(hr, S_OK);
4103 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4104 EXPECT_HR(hr, S_OK);
4105 test_obj_dispex(unk);
4106 IUnknown_Release(unk);
4107 IVBSAXXMLReader_Release(vbreader);
4109 ISAXXMLReader_Release(reader);
4112 static void test_mxwriter_dispex(void)
4114 IDispatchEx *dispex;
4115 IMXWriter *writer;
4116 IUnknown *unk;
4117 HRESULT hr;
4119 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4120 &IID_IMXWriter, (void**)&writer);
4121 EXPECT_HR(hr, S_OK);
4123 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4124 EXPECT_HR(hr, S_OK);
4125 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4126 test_obj_dispex(unk);
4127 IUnknown_Release(unk);
4128 IDispatchEx_Release(dispex);
4130 IMXWriter_Release(writer);
4133 static void test_mxwriter_comment(void)
4135 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4136 ISAXContentHandler *content;
4137 ISAXLexicalHandler *lexical;
4138 IMXWriter *writer;
4139 VARIANT dest;
4140 HRESULT hr;
4142 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4143 &IID_IMXWriter, (void**)&writer);
4144 EXPECT_HR(hr, S_OK);
4146 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4147 EXPECT_HR(hr, S_OK);
4149 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4150 EXPECT_HR(hr, S_OK);
4152 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4153 EXPECT_HR(hr, S_OK);
4155 hr = ISAXContentHandler_startDocument(content);
4156 EXPECT_HR(hr, S_OK);
4158 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4159 EXPECT_HR(hr, E_INVALIDARG);
4161 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4162 EXPECT_HR(hr, S_OK);
4164 V_VT(&dest) = VT_EMPTY;
4165 hr = IMXWriter_get_output(writer, &dest);
4166 EXPECT_HR(hr, S_OK);
4167 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4168 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4169 VariantClear(&dest);
4171 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4172 EXPECT_HR(hr, S_OK);
4174 V_VT(&dest) = VT_EMPTY;
4175 hr = IMXWriter_get_output(writer, &dest);
4176 EXPECT_HR(hr, S_OK);
4177 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4178 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4179 VariantClear(&dest);
4181 ISAXContentHandler_Release(content);
4182 ISAXLexicalHandler_Release(lexical);
4183 IMXWriter_Release(writer);
4184 free_bstrs();
4187 static void test_mxwriter_cdata(void)
4189 ISAXContentHandler *content;
4190 ISAXLexicalHandler *lexical;
4191 IMXWriter *writer;
4192 VARIANT dest;
4193 HRESULT hr;
4195 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4196 &IID_IMXWriter, (void**)&writer);
4197 EXPECT_HR(hr, S_OK);
4199 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4200 EXPECT_HR(hr, S_OK);
4202 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4203 EXPECT_HR(hr, S_OK);
4205 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4206 EXPECT_HR(hr, S_OK);
4208 hr = ISAXContentHandler_startDocument(content);
4209 EXPECT_HR(hr, S_OK);
4211 hr = ISAXLexicalHandler_startCDATA(lexical);
4212 EXPECT_HR(hr, S_OK);
4214 V_VT(&dest) = VT_EMPTY;
4215 hr = IMXWriter_get_output(writer, &dest);
4216 EXPECT_HR(hr, S_OK);
4217 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4218 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4219 VariantClear(&dest);
4221 hr = ISAXLexicalHandler_startCDATA(lexical);
4222 EXPECT_HR(hr, S_OK);
4224 /* all these are escaped for text nodes */
4225 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4226 EXPECT_HR(hr, S_OK);
4228 hr = ISAXLexicalHandler_endCDATA(lexical);
4229 EXPECT_HR(hr, S_OK);
4231 V_VT(&dest) = VT_EMPTY;
4232 hr = IMXWriter_get_output(writer, &dest);
4233 EXPECT_HR(hr, S_OK);
4234 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4235 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4236 VariantClear(&dest);
4238 ISAXContentHandler_Release(content);
4239 ISAXLexicalHandler_Release(lexical);
4240 IMXWriter_Release(writer);
4241 free_bstrs();
4244 static void test_mxwriter_pi(void)
4246 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4247 static const WCHAR dataW[] = {'d','a','t','a',0};
4248 ISAXContentHandler *content;
4249 IMXWriter *writer;
4250 VARIANT dest;
4251 HRESULT hr;
4253 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4254 &IID_IMXWriter, (void**)&writer);
4255 EXPECT_HR(hr, S_OK);
4257 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4258 EXPECT_HR(hr, S_OK);
4260 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4261 EXPECT_HR(hr, E_INVALIDARG);
4263 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4264 EXPECT_HR(hr, S_OK);
4266 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4267 EXPECT_HR(hr, S_OK);
4269 V_VT(&dest) = VT_EMPTY;
4270 hr = IMXWriter_get_output(writer, &dest);
4271 EXPECT_HR(hr, S_OK);
4272 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4273 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4274 VariantClear(&dest);
4276 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4277 EXPECT_HR(hr, S_OK);
4279 V_VT(&dest) = VT_EMPTY;
4280 hr = IMXWriter_get_output(writer, &dest);
4281 EXPECT_HR(hr, S_OK);
4282 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4283 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)));
4284 VariantClear(&dest);
4286 V_VT(&dest) = VT_EMPTY;
4287 hr = IMXWriter_put_output(writer, dest);
4288 EXPECT_HR(hr, S_OK);
4290 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4291 EXPECT_HR(hr, S_OK);
4293 V_VT(&dest) = VT_EMPTY;
4294 hr = IMXWriter_get_output(writer, &dest);
4295 EXPECT_HR(hr, S_OK);
4296 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4297 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4298 VariantClear(&dest);
4301 ISAXContentHandler_Release(content);
4302 IMXWriter_Release(writer);
4305 static void test_mxwriter_ignorablespaces(void)
4307 static const WCHAR dataW[] = {'d','a','t','a',0};
4308 ISAXContentHandler *content;
4309 IMXWriter *writer;
4310 VARIANT dest;
4311 HRESULT hr;
4313 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4314 &IID_IMXWriter, (void**)&writer);
4315 EXPECT_HR(hr, S_OK);
4317 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4318 EXPECT_HR(hr, S_OK);
4320 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4321 EXPECT_HR(hr, E_INVALIDARG);
4323 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4324 EXPECT_HR(hr, S_OK);
4326 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4327 EXPECT_HR(hr, S_OK);
4329 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4330 EXPECT_HR(hr, S_OK);
4332 V_VT(&dest) = VT_EMPTY;
4333 hr = IMXWriter_get_output(writer, &dest);
4334 EXPECT_HR(hr, S_OK);
4335 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4336 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4337 VariantClear(&dest);
4339 ISAXContentHandler_Release(content);
4340 IMXWriter_Release(writer);
4343 static void test_mxwriter_dtd(void)
4345 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4346 static const WCHAR nameW[] = {'n','a','m','e'};
4347 static const WCHAR pubW[] = {'p','u','b'};
4348 static const WCHAR sysW[] = {'s','y','s'};
4349 ISAXContentHandler *content;
4350 ISAXLexicalHandler *lexical;
4351 ISAXDeclHandler *decl;
4352 IMXWriter *writer;
4353 VARIANT dest;
4354 HRESULT hr;
4356 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4357 &IID_IMXWriter, (void**)&writer);
4358 EXPECT_HR(hr, S_OK);
4360 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4361 EXPECT_HR(hr, S_OK);
4363 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4364 EXPECT_HR(hr, S_OK);
4366 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4367 EXPECT_HR(hr, S_OK);
4369 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4370 EXPECT_HR(hr, S_OK);
4372 hr = ISAXContentHandler_startDocument(content);
4373 EXPECT_HR(hr, S_OK);
4375 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4376 EXPECT_HR(hr, E_INVALIDARG);
4378 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4379 EXPECT_HR(hr, E_INVALIDARG);
4381 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4382 EXPECT_HR(hr, E_INVALIDARG);
4384 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4385 EXPECT_HR(hr, E_INVALIDARG);
4387 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4388 EXPECT_HR(hr, S_OK);
4390 V_VT(&dest) = VT_EMPTY;
4391 hr = IMXWriter_get_output(writer, &dest);
4392 EXPECT_HR(hr, S_OK);
4393 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4394 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4395 VariantClear(&dest);
4397 /* system id is required if public is present */
4398 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4399 EXPECT_HR(hr, E_INVALIDARG);
4401 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4402 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4403 EXPECT_HR(hr, S_OK);
4405 V_VT(&dest) = VT_EMPTY;
4406 hr = IMXWriter_get_output(writer, &dest);
4407 EXPECT_HR(hr, S_OK);
4408 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4409 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4410 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4411 VariantClear(&dest);
4413 hr = ISAXLexicalHandler_endDTD(lexical);
4414 EXPECT_HR(hr, S_OK);
4416 hr = ISAXLexicalHandler_endDTD(lexical);
4417 EXPECT_HR(hr, S_OK);
4419 V_VT(&dest) = VT_EMPTY;
4420 hr = IMXWriter_get_output(writer, &dest);
4421 EXPECT_HR(hr, S_OK);
4422 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4423 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4424 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4425 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4426 VariantClear(&dest);
4428 /* element declaration */
4429 V_VT(&dest) = VT_EMPTY;
4430 hr = IMXWriter_put_output(writer, dest);
4431 EXPECT_HR(hr, S_OK);
4433 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4434 EXPECT_HR(hr, E_INVALIDARG);
4436 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4437 EXPECT_HR(hr, E_INVALIDARG);
4439 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4440 EXPECT_HR(hr, S_OK);
4442 V_VT(&dest) = VT_EMPTY;
4443 hr = IMXWriter_get_output(writer, &dest);
4444 EXPECT_HR(hr, S_OK);
4445 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4446 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4447 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4448 VariantClear(&dest);
4450 V_VT(&dest) = VT_EMPTY;
4451 hr = IMXWriter_put_output(writer, dest);
4452 EXPECT_HR(hr, S_OK);
4454 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4455 EXPECT_HR(hr, S_OK);
4457 V_VT(&dest) = VT_EMPTY;
4458 hr = IMXWriter_get_output(writer, &dest);
4459 EXPECT_HR(hr, S_OK);
4460 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4461 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4462 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4463 VariantClear(&dest);
4465 /* attribute declaration */
4466 V_VT(&dest) = VT_EMPTY;
4467 hr = IMXWriter_put_output(writer, dest);
4468 EXPECT_HR(hr, S_OK);
4470 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4471 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4472 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4473 EXPECT_HR(hr, S_OK);
4475 V_VT(&dest) = VT_EMPTY;
4476 hr = IMXWriter_get_output(writer, &dest);
4477 EXPECT_HR(hr, S_OK);
4478 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4479 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4480 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4481 VariantClear(&dest);
4483 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4484 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4485 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4486 EXPECT_HR(hr, S_OK);
4488 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4489 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4490 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4491 EXPECT_HR(hr, S_OK);
4493 V_VT(&dest) = VT_EMPTY;
4494 hr = IMXWriter_get_output(writer, &dest);
4495 EXPECT_HR(hr, S_OK);
4496 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4497 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4498 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4499 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4500 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4501 VariantClear(&dest);
4503 /* internal entities */
4504 V_VT(&dest) = VT_EMPTY;
4505 hr = IMXWriter_put_output(writer, dest);
4506 EXPECT_HR(hr, S_OK);
4508 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4509 EXPECT_HR(hr, E_INVALIDARG);
4511 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4512 EXPECT_HR(hr, E_INVALIDARG);
4514 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4515 EXPECT_HR(hr, S_OK);
4517 V_VT(&dest) = VT_EMPTY;
4518 hr = IMXWriter_get_output(writer, &dest);
4519 EXPECT_HR(hr, S_OK);
4520 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4521 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4522 VariantClear(&dest);
4524 ISAXContentHandler_Release(content);
4525 ISAXLexicalHandler_Release(lexical);
4526 ISAXDeclHandler_Release(decl);
4527 IMXWriter_Release(writer);
4528 free_bstrs();
4531 typedef struct {
4532 const CLSID *clsid;
4533 const char *uri;
4534 const char *local;
4535 const char *qname;
4536 const char *type;
4537 const char *value;
4538 HRESULT hr;
4539 } addattribute_test_t;
4541 static const addattribute_test_t addattribute_data[] = {
4542 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4543 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4544 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4545 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4547 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4548 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4549 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4550 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4552 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4553 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4554 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4555 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4557 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4558 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4559 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4560 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4562 { NULL }
4565 static void test_mxattr_addAttribute(void)
4567 const addattribute_test_t *table = addattribute_data;
4568 int i = 0;
4570 while (table->clsid)
4572 ISAXAttributes *saxattr;
4573 IMXAttributes *mxattr;
4574 const WCHAR *value;
4575 int len, index;
4576 HRESULT hr;
4578 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4580 table++;
4581 i++;
4582 continue;
4585 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4586 &IID_IMXAttributes, (void**)&mxattr);
4587 EXPECT_HR(hr, S_OK);
4589 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4590 EXPECT_HR(hr, S_OK);
4592 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4593 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4594 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4596 hr = ISAXAttributes_getLength(saxattr, NULL);
4597 EXPECT_HR(hr, E_POINTER);
4600 len = -1;
4601 hr = ISAXAttributes_getLength(saxattr, &len);
4602 EXPECT_HR(hr, S_OK);
4603 ok(len == 0, "got %d\n", len);
4605 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4606 EXPECT_HR(hr, E_INVALIDARG);
4608 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4609 EXPECT_HR(hr, E_INVALIDARG);
4611 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4612 EXPECT_HR(hr, E_INVALIDARG);
4614 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4615 EXPECT_HR(hr, E_INVALIDARG);
4617 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4618 EXPECT_HR(hr, E_INVALIDARG);
4620 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4621 EXPECT_HR(hr, E_INVALIDARG);
4623 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4624 EXPECT_HR(hr, E_INVALIDARG);
4626 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4627 EXPECT_HR(hr, E_INVALIDARG);
4629 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4630 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4631 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4633 if (hr == S_OK)
4635 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4636 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4637 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4639 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4640 EXPECT_HR(hr, E_POINTER);
4642 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4643 EXPECT_HR(hr, E_POINTER);
4645 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4646 EXPECT_HR(hr, E_POINTER);
4648 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4649 EXPECT_HR(hr, E_POINTER);
4651 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4652 EXPECT_HR(hr, E_POINTER);
4654 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4655 EXPECT_HR(hr, E_POINTER);
4658 len = -1;
4659 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4660 EXPECT_HR(hr, S_OK);
4661 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4662 table->value);
4663 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4665 len = -1;
4666 value = (void*)0xdeadbeef;
4667 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4668 EXPECT_HR(hr, S_OK);
4670 if (table->type)
4672 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4673 table->type);
4674 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4676 else
4678 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4679 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4682 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4683 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4684 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4686 EXPECT_HR(hr, E_POINTER);
4688 else
4689 EXPECT_HR(hr, E_INVALIDARG);
4691 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4692 EXPECT_HR(hr, E_INVALIDARG);
4694 index = -1;
4695 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4696 EXPECT_HR(hr, E_INVALIDARG);
4697 ok(index == -1, "%d: got wrong index %d\n", i, index);
4699 index = -1;
4700 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4701 EXPECT_HR(hr, E_INVALIDARG);
4702 ok(index == -1, "%d: got wrong index %d\n", i, index);
4704 index = -1;
4705 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4706 EXPECT_HR(hr, S_OK);
4707 ok(index == 0, "%d: got wrong index %d\n", i, index);
4709 index = -1;
4710 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4711 EXPECT_HR(hr, E_INVALIDARG);
4712 ok(index == -1, "%d: got wrong index %d\n", i, index);
4714 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4715 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4717 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4718 EXPECT_HR(hr, E_INVALIDARG);
4720 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4721 EXPECT_HR(hr, E_INVALIDARG);
4723 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4724 EXPECT_HR(hr, E_INVALIDARG);
4726 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4727 EXPECT_HR(hr, E_INVALIDARG);
4729 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4730 EXPECT_HR(hr, E_INVALIDARG);
4732 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4733 EXPECT_HR(hr, E_INVALIDARG);
4735 else
4737 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4738 EXPECT_HR(hr, E_POINTER);
4740 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4741 EXPECT_HR(hr, E_POINTER);
4743 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4744 EXPECT_HR(hr, E_POINTER);
4746 /* versions 4 and 6 crash */
4747 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4748 EXPECT_HR(hr, E_POINTER);
4750 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4751 EXPECT_HR(hr, E_POINTER);
4753 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4754 EXPECT_HR(hr, E_POINTER);
4756 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4757 EXPECT_HR(hr, E_POINTER);
4759 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4760 EXPECT_HR(hr, E_POINTER);
4762 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4763 EXPECT_HR(hr, E_POINTER);
4765 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4766 EXPECT_HR(hr, E_POINTER);
4768 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4769 strlen(table->local), NULL, NULL);
4770 EXPECT_HR(hr, E_POINTER);
4773 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4774 EXPECT_HR(hr, S_OK);
4775 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4776 table->value);
4777 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4779 if (table->uri) {
4780 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4781 _bstr_(table->local), strlen(table->local), &value, &len);
4782 EXPECT_HR(hr, S_OK);
4783 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4784 table->value);
4785 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4789 len = -1;
4790 hr = ISAXAttributes_getLength(saxattr, &len);
4791 EXPECT_HR(hr, S_OK);
4792 if (table->hr == S_OK)
4793 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
4794 else
4795 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
4797 ISAXAttributes_Release(saxattr);
4798 IMXAttributes_Release(mxattr);
4800 table++;
4801 i++;
4804 free_bstrs();
4807 static void test_mxattr_clear(void)
4809 ISAXAttributes *saxattr;
4810 IMXAttributes *mxattr;
4811 const WCHAR *ptr;
4812 HRESULT hr;
4813 int len;
4815 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4816 &IID_IMXAttributes, (void**)&mxattr);
4817 EXPECT_HR(hr, S_OK);
4819 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4820 EXPECT_HR(hr, S_OK);
4822 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4823 EXPECT_HR(hr, E_INVALIDARG);
4825 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4826 EXPECT_HR(hr, E_INVALIDARG);
4828 hr = IMXAttributes_clear(mxattr);
4829 EXPECT_HR(hr, S_OK);
4831 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4832 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4833 EXPECT_HR(hr, S_OK);
4835 len = -1;
4836 hr = ISAXAttributes_getLength(saxattr, &len);
4837 EXPECT_HR(hr, S_OK);
4838 ok(len == 1, "got %d\n", len);
4840 len = -1;
4841 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4842 EXPECT_HR(hr, E_POINTER);
4843 ok(len == -1, "got %d\n", len);
4845 ptr = (void*)0xdeadbeef;
4846 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4847 EXPECT_HR(hr, E_POINTER);
4848 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4850 len = 0;
4851 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4852 EXPECT_HR(hr, S_OK);
4853 ok(len == 5, "got %d\n", len);
4854 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4856 hr = IMXAttributes_clear(mxattr);
4857 EXPECT_HR(hr, S_OK);
4859 len = -1;
4860 hr = ISAXAttributes_getLength(saxattr, &len);
4861 EXPECT_HR(hr, S_OK);
4862 ok(len == 0, "got %d\n", len);
4864 len = -1;
4865 ptr = (void*)0xdeadbeef;
4866 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4867 EXPECT_HR(hr, E_INVALIDARG);
4868 ok(len == -1, "got %d\n", len);
4869 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4871 IMXAttributes_Release(mxattr);
4872 ISAXAttributes_Release(saxattr);
4873 free_bstrs();
4876 static void test_mxattr_dispex(void)
4878 IMXAttributes *mxattr;
4879 IDispatchEx *dispex;
4880 IUnknown *unk;
4881 HRESULT hr;
4883 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4884 &IID_IMXAttributes, (void**)&mxattr);
4885 EXPECT_HR(hr, S_OK);
4887 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4888 EXPECT_HR(hr, S_OK);
4889 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4890 test_obj_dispex(unk);
4891 IUnknown_Release(unk);
4892 IDispatchEx_Release(dispex);
4894 IMXAttributes_Release(mxattr);
4897 static void test_mxattr_qi(void)
4899 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4900 ISAXAttributes *saxattr;
4901 IMXAttributes *mxattr;
4902 HRESULT hr;
4904 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4905 &IID_IMXAttributes, (void**)&mxattr);
4906 EXPECT_HR(hr, S_OK);
4908 EXPECT_REF(mxattr, 1);
4909 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4910 EXPECT_HR(hr, S_OK);
4912 EXPECT_REF(mxattr, 2);
4913 EXPECT_REF(saxattr, 2);
4915 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4916 EXPECT_HR(hr, S_OK);
4918 EXPECT_REF(vbsaxattr, 3);
4919 EXPECT_REF(mxattr, 3);
4920 EXPECT_REF(saxattr, 3);
4922 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4923 EXPECT_HR(hr, S_OK);
4925 EXPECT_REF(vbsaxattr, 4);
4926 EXPECT_REF(mxattr, 4);
4927 EXPECT_REF(saxattr, 4);
4929 IMXAttributes_Release(mxattr);
4930 ISAXAttributes_Release(saxattr);
4931 IVBSAXAttributes_Release(vbsaxattr);
4932 IVBSAXAttributes_Release(vbsaxattr2);
4935 static struct msxmlsupported_data_t saxattr_support_data[] =
4937 { &CLSID_SAXAttributes, "SAXAttributes" },
4938 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4939 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4940 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4941 { NULL }
4944 static void test_mxattr_localname(void)
4946 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4947 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4948 static const WCHAR uri1W[] = {'u','r','i','1',0};
4949 static const WCHAR uriW[] = {'u','r','i',0};
4951 const struct msxmlsupported_data_t *table = saxattr_support_data;
4953 while (table->clsid)
4955 ISAXAttributes *saxattr;
4956 IMXAttributes *mxattr;
4957 HRESULT hr;
4958 int index;
4960 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4962 table++;
4963 continue;
4966 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4967 &IID_IMXAttributes, (void**)&mxattr);
4968 EXPECT_HR(hr, S_OK);
4970 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4971 EXPECT_HR(hr, S_OK);
4973 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4974 EXPECT_HR(hr, E_INVALIDARG);
4976 /* add some ambiguos attribute names */
4977 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4978 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4979 EXPECT_HR(hr, S_OK);
4980 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4981 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4982 EXPECT_HR(hr, S_OK);
4984 index = -1;
4985 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4986 EXPECT_HR(hr, S_OK);
4987 ok(index == 0, "%s: got index %d\n", table->name, index);
4989 index = -1;
4990 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4991 EXPECT_HR(hr, E_INVALIDARG);
4992 ok(index == -1, "%s: got index %d\n", table->name, index);
4994 index = -1;
4995 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4996 EXPECT_HR(hr, E_INVALIDARG);
4997 ok(index == -1, "%s: got index %d\n", table->name, index);
4999 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5000 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5002 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5003 EXPECT_HR(hr, E_POINTER);
5005 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5006 EXPECT_HR(hr, E_POINTER);
5008 else
5010 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5011 EXPECT_HR(hr, E_INVALIDARG);
5013 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5014 EXPECT_HR(hr, E_INVALIDARG);
5017 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5018 EXPECT_HR(hr, E_INVALIDARG);
5020 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5021 EXPECT_HR(hr, E_INVALIDARG);
5023 table++;
5025 ISAXAttributes_Release(saxattr);
5026 IMXAttributes_Release(mxattr);
5030 START_TEST(saxreader)
5032 ISAXXMLReader *reader;
5033 HRESULT hr;
5035 hr = CoInitialize(NULL);
5036 ok(hr == S_OK, "failed to init com\n");
5038 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5039 &IID_ISAXXMLReader, (void**)&reader);
5041 if(FAILED(hr))
5043 skip("Failed to create SAXXMLReader instance\n");
5044 CoUninitialize();
5045 return;
5047 ISAXXMLReader_Release(reader);
5049 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5051 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5053 test_saxreader();
5054 test_saxreader_properties();
5055 test_saxreader_features();
5056 test_saxreader_encoding();
5057 test_dispex();
5059 /* MXXMLWriter tests */
5060 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5061 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5063 test_mxwriter_handlers();
5064 test_mxwriter_startenddocument();
5065 test_mxwriter_startendelement();
5066 test_mxwriter_characters();
5067 test_mxwriter_comment();
5068 test_mxwriter_cdata();
5069 test_mxwriter_pi();
5070 test_mxwriter_ignorablespaces();
5071 test_mxwriter_dtd();
5072 test_mxwriter_properties();
5073 test_mxwriter_flush();
5074 test_mxwriter_stream();
5075 test_mxwriter_encoding();
5076 test_mxwriter_dispex();
5078 else
5079 win_skip("MXXMLWriter not supported\n");
5081 /* SAXAttributes tests */
5082 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5083 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5085 test_mxattr_qi();
5086 test_mxattr_addAttribute();
5087 test_mxattr_clear();
5088 test_mxattr_localname();
5089 test_mxattr_dispex();
5091 else
5092 skip("SAXAttributes not supported\n");
5094 CoUninitialize();