msxml3: Implement internalEntityDecl() for writer.
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blob2858583d96b8bd415925777ede7513c3e5b1a7ea
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 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2336 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2338 V_VT(&v) = VT_UNKNOWN;
2339 V_UNKNOWN(&v) = ptr->iface;
2340 EXPECT_REF(ptr->iface, 1);
2341 ref = get_refcount(ptr->iface);
2342 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2343 EXPECT_HR(hr, E_NOINTERFACE);
2344 EXPECT_REF(ptr->iface, 1);
2346 ptr++;
2349 ISAXXMLReader_Release(reader);
2350 free_bstrs();
2353 struct feature_ns_entry_t {
2354 const GUID *guid;
2355 const char *clsid;
2356 VARIANT_BOOL value;
2357 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2360 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2361 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2362 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2363 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2364 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2365 { 0 }
2368 static const char *feature_names[] = {
2369 "http://xml.org/sax/features/namespaces",
2370 "http://xml.org/sax/features/namespace-prefixes",
2374 static void test_saxreader_features(void)
2376 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2377 ISAXXMLReader *reader;
2379 while (entry->guid)
2381 VARIANT_BOOL value;
2382 const char **name;
2383 HRESULT hr;
2385 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2386 if (hr != S_OK)
2388 win_skip("can't create %s instance\n", entry->clsid);
2389 entry++;
2390 continue;
2393 name = feature_names;
2394 while (*name)
2396 value = 0xc;
2397 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2398 EXPECT_HR(hr, S_OK);
2399 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2401 value = 0xc;
2402 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2403 EXPECT_HR(hr, S_OK);
2405 value = 0xd;
2406 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2407 EXPECT_HR(hr, S_OK);
2408 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2410 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2411 EXPECT_HR(hr, S_OK);
2412 value = 0xd;
2413 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2414 EXPECT_HR(hr, S_OK);
2415 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2417 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2418 EXPECT_HR(hr, S_OK);
2419 value = 0xd;
2420 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2421 EXPECT_HR(hr, S_OK);
2422 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2424 name++;
2427 ISAXXMLReader_Release(reader);
2429 entry++;
2433 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2434 static const CHAR UTF8BOMTest[] =
2435 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2436 "<a></a>\n";
2438 struct enc_test_entry_t {
2439 const GUID *guid;
2440 const char *clsid;
2441 const char *data;
2442 HRESULT hr;
2443 int todo;
2446 static const struct enc_test_entry_t encoding_test_data[] = {
2447 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2448 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2449 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2450 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2451 { 0 }
2454 static void test_saxreader_encoding(void)
2456 const struct enc_test_entry_t *entry = encoding_test_data;
2457 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2458 static const CHAR testXmlA[] = "test.xml";
2460 while (entry->guid)
2462 ISAXXMLReader *reader;
2463 VARIANT input;
2464 DWORD written;
2465 HANDLE file;
2466 HRESULT hr;
2468 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2469 if (hr != S_OK)
2471 win_skip("can't create %s instance\n", entry->clsid);
2472 entry++;
2473 continue;
2476 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2477 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2478 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2479 CloseHandle(file);
2481 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2482 if (entry->todo)
2483 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2484 else
2485 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2487 DeleteFileA(testXmlA);
2489 /* try BSTR input with no BOM or '<?xml' instruction */
2490 V_VT(&input) = VT_BSTR;
2491 V_BSTR(&input) = _bstr_("<element></element>");
2492 hr = ISAXXMLReader_parse(reader, input);
2493 EXPECT_HR(hr, S_OK);
2495 ISAXXMLReader_Release(reader);
2497 free_bstrs();
2498 entry++;
2502 static void test_mxwriter_handlers(void)
2504 ISAXContentHandler *handler;
2505 IMXWriter *writer, *writer2;
2506 ISAXDeclHandler *decl;
2507 ISAXLexicalHandler *lh;
2508 HRESULT hr;
2510 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2511 &IID_IMXWriter, (void**)&writer);
2512 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2514 EXPECT_REF(writer, 1);
2516 /* ISAXContentHandler */
2517 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2518 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2519 EXPECT_REF(writer, 2);
2520 EXPECT_REF(handler, 2);
2522 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2523 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2524 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2525 EXPECT_REF(writer, 3);
2526 EXPECT_REF(writer2, 3);
2527 IMXWriter_Release(writer2);
2528 ISAXContentHandler_Release(handler);
2530 /* ISAXLexicalHandler */
2531 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2532 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2533 EXPECT_REF(writer, 2);
2534 EXPECT_REF(lh, 2);
2536 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2537 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2538 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2539 EXPECT_REF(writer, 3);
2540 EXPECT_REF(writer2, 3);
2541 IMXWriter_Release(writer2);
2542 ISAXLexicalHandler_Release(lh);
2544 /* ISAXDeclHandler */
2545 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2546 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2547 EXPECT_REF(writer, 2);
2548 EXPECT_REF(lh, 2);
2550 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2551 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2552 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2553 EXPECT_REF(writer, 3);
2554 EXPECT_REF(writer2, 3);
2555 IMXWriter_Release(writer2);
2556 ISAXDeclHandler_Release(decl);
2558 IMXWriter_Release(writer);
2562 static struct msxmlsupported_data_t mxwriter_support_data[] =
2564 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2565 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2566 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2567 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2568 { NULL }
2571 static struct msxmlsupported_data_t mxattributes_support_data[] =
2573 { &CLSID_SAXAttributes, "SAXAttributes" },
2574 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2575 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2576 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2577 { NULL }
2580 struct mxwriter_props_t
2582 const GUID *clsid;
2583 VARIANT_BOOL bom;
2584 VARIANT_BOOL disable_escape;
2585 VARIANT_BOOL indent;
2586 VARIANT_BOOL omitdecl;
2587 VARIANT_BOOL standalone;
2588 const char *encoding;
2591 static const struct mxwriter_props_t mxwriter_default_props[] =
2593 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2594 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2595 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2596 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2597 { NULL }
2600 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2602 int i = 0;
2604 while (table->clsid)
2606 IMXWriter *writer;
2607 VARIANT_BOOL b;
2608 BSTR encoding;
2609 HRESULT hr;
2611 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2613 table++;
2614 i++;
2615 continue;
2618 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2619 &IID_IMXWriter, (void**)&writer);
2620 EXPECT_HR(hr, S_OK);
2622 b = !table->bom;
2623 hr = IMXWriter_get_byteOrderMark(writer, &b);
2624 EXPECT_HR(hr, S_OK);
2625 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2627 b = !table->disable_escape;
2628 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2629 EXPECT_HR(hr, S_OK);
2630 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2631 table->disable_escape);
2633 b = !table->indent;
2634 hr = IMXWriter_get_indent(writer, &b);
2635 EXPECT_HR(hr, S_OK);
2636 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2638 b = !table->omitdecl;
2639 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2640 EXPECT_HR(hr, S_OK);
2641 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2643 b = !table->standalone;
2644 hr = IMXWriter_get_standalone(writer, &b);
2645 EXPECT_HR(hr, S_OK);
2646 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2648 hr = IMXWriter_get_encoding(writer, &encoding);
2649 EXPECT_HR(hr, S_OK);
2650 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2651 i, wine_dbgstr_w(encoding), table->encoding);
2652 SysFreeString(encoding);
2654 IMXWriter_Release(writer);
2656 table++;
2657 i++;
2661 static void test_mxwriter_properties(void)
2663 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2664 static const WCHAR emptyW[] = {0};
2665 static const WCHAR testW[] = {'t','e','s','t',0};
2666 ISAXContentHandler *content;
2667 IMXWriter *writer;
2668 VARIANT_BOOL b;
2669 HRESULT hr;
2670 BSTR str, str2;
2671 VARIANT dest;
2673 test_mxwriter_default_properties(mxwriter_default_props);
2675 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2676 &IID_IMXWriter, (void**)&writer);
2677 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2679 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2680 ok(hr == E_POINTER, "got %08x\n", hr);
2682 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2683 ok(hr == E_POINTER, "got %08x\n", hr);
2685 hr = IMXWriter_get_indent(writer, NULL);
2686 ok(hr == E_POINTER, "got %08x\n", hr);
2688 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2689 ok(hr == E_POINTER, "got %08x\n", hr);
2691 hr = IMXWriter_get_standalone(writer, NULL);
2692 ok(hr == E_POINTER, "got %08x\n", hr);
2694 /* set and check */
2695 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2696 ok(hr == S_OK, "got %08x\n", hr);
2698 b = VARIANT_FALSE;
2699 hr = IMXWriter_get_standalone(writer, &b);
2700 ok(hr == S_OK, "got %08x\n", hr);
2701 ok(b == VARIANT_TRUE, "got %d\n", b);
2703 hr = IMXWriter_get_encoding(writer, NULL);
2704 EXPECT_HR(hr, E_POINTER);
2706 /* UTF-16 is a default setting apparently */
2707 str = (void*)0xdeadbeef;
2708 hr = IMXWriter_get_encoding(writer, &str);
2709 EXPECT_HR(hr, S_OK);
2710 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2712 str2 = (void*)0xdeadbeef;
2713 hr = IMXWriter_get_encoding(writer, &str2);
2714 ok(hr == S_OK, "got %08x\n", hr);
2715 ok(str != str2, "expected newly allocated, got same %p\n", str);
2717 SysFreeString(str2);
2718 SysFreeString(str);
2720 /* put empty string */
2721 str = SysAllocString(emptyW);
2722 hr = IMXWriter_put_encoding(writer, str);
2723 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2724 SysFreeString(str);
2726 str = (void*)0xdeadbeef;
2727 hr = IMXWriter_get_encoding(writer, &str);
2728 EXPECT_HR(hr, S_OK);
2729 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2730 SysFreeString(str);
2732 /* invalid encoding name */
2733 str = SysAllocString(testW);
2734 hr = IMXWriter_put_encoding(writer, str);
2735 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2736 SysFreeString(str);
2738 /* test case sensivity */
2739 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2740 EXPECT_HR(hr, S_OK);
2741 str = (void*)0xdeadbeef;
2742 hr = IMXWriter_get_encoding(writer, &str);
2743 EXPECT_HR(hr, S_OK);
2744 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2745 SysFreeString(str);
2747 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2748 EXPECT_HR(hr, S_OK);
2749 str = (void*)0xdeadbeef;
2750 hr = IMXWriter_get_encoding(writer, &str);
2751 EXPECT_HR(hr, S_OK);
2752 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2753 SysFreeString(str);
2755 /* how it affects document creation */
2756 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2757 EXPECT_HR(hr, S_OK);
2759 hr = ISAXContentHandler_startDocument(content);
2760 EXPECT_HR(hr, S_OK);
2761 hr = ISAXContentHandler_endDocument(content);
2762 EXPECT_HR(hr, S_OK);
2764 V_VT(&dest) = VT_EMPTY;
2765 hr = IMXWriter_get_output(writer, &dest);
2766 EXPECT_HR(hr, S_OK);
2767 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2768 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2769 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2770 VariantClear(&dest);
2771 ISAXContentHandler_Release(content);
2773 hr = IMXWriter_get_version(writer, NULL);
2774 ok(hr == E_POINTER, "got %08x\n", hr);
2775 /* default version is 'surprisingly' 1.0 */
2776 hr = IMXWriter_get_version(writer, &str);
2777 ok(hr == S_OK, "got %08x\n", hr);
2778 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2779 SysFreeString(str);
2781 /* store version string as is */
2782 hr = IMXWriter_put_version(writer, NULL);
2783 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2785 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2786 ok(hr == S_OK, "got %08x\n", hr);
2788 hr = IMXWriter_put_version(writer, _bstr_(""));
2789 ok(hr == S_OK, "got %08x\n", hr);
2790 hr = IMXWriter_get_version(writer, &str);
2791 ok(hr == S_OK, "got %08x\n", hr);
2792 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2793 SysFreeString(str);
2795 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2796 ok(hr == S_OK, "got %08x\n", hr);
2797 hr = IMXWriter_get_version(writer, &str);
2798 ok(hr == S_OK, "got %08x\n", hr);
2799 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2800 SysFreeString(str);
2802 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2803 ok(hr == S_OK, "got %08x\n", hr);
2804 hr = IMXWriter_get_version(writer, &str);
2805 ok(hr == S_OK, "got %08x\n", hr);
2806 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2807 SysFreeString(str);
2809 IMXWriter_Release(writer);
2810 free_bstrs();
2813 static void test_mxwriter_flush(void)
2815 static const WCHAR emptyW[] = {0};
2816 ISAXContentHandler *content;
2817 IMXWriter *writer;
2818 LARGE_INTEGER pos;
2819 ULARGE_INTEGER pos2;
2820 IStream *stream;
2821 VARIANT dest;
2822 HRESULT hr;
2823 char *buff;
2824 LONG ref;
2825 int len;
2827 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2828 &IID_IMXWriter, (void**)&writer);
2829 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2831 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2832 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2833 EXPECT_REF(stream, 1);
2835 /* detach when nothing was attached */
2836 V_VT(&dest) = VT_EMPTY;
2837 hr = IMXWriter_put_output(writer, dest);
2838 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2840 /* attach stream */
2841 V_VT(&dest) = VT_UNKNOWN;
2842 V_UNKNOWN(&dest) = (IUnknown*)stream;
2843 hr = IMXWriter_put_output(writer, dest);
2844 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2845 todo_wine EXPECT_REF(stream, 3);
2847 /* detach setting VT_EMPTY destination */
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);
2851 EXPECT_REF(stream, 1);
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);
2858 /* flush() doesn't detach a stream */
2859 hr = IMXWriter_flush(writer);
2860 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2861 todo_wine EXPECT_REF(stream, 3);
2863 pos.QuadPart = 0;
2864 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2865 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2866 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2868 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2869 ok(hr == S_OK, "got %08x\n", hr);
2871 hr = ISAXContentHandler_startDocument(content);
2872 ok(hr == S_OK, "got %08x\n", hr);
2874 pos.QuadPart = 0;
2875 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2876 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2877 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2879 /* already started */
2880 hr = ISAXContentHandler_startDocument(content);
2881 ok(hr == S_OK, "got %08x\n", hr);
2883 hr = ISAXContentHandler_endDocument(content);
2884 ok(hr == S_OK, "got %08x\n", hr);
2886 /* flushed on endDocument() */
2887 pos.QuadPart = 0;
2888 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2889 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2890 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2892 IStream_Release(stream);
2894 /* auto-flush feature */
2895 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2896 EXPECT_HR(hr, S_OK);
2897 EXPECT_REF(stream, 1);
2899 V_VT(&dest) = VT_UNKNOWN;
2900 V_UNKNOWN(&dest) = (IUnknown*)stream;
2901 hr = IMXWriter_put_output(writer, dest);
2902 EXPECT_HR(hr, S_OK);
2904 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
2905 EXPECT_HR(hr, S_OK);
2907 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2908 EXPECT_HR(hr, S_OK);
2910 hr = ISAXContentHandler_startDocument(content);
2911 EXPECT_HR(hr, S_OK);
2913 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
2914 EXPECT_HR(hr, S_OK);
2916 /* internal buffer is flushed automatically on certain threshold */
2917 pos.QuadPart = 0;
2918 pos2.QuadPart = 1;
2919 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2920 EXPECT_HR(hr, S_OK);
2921 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2923 len = 2048;
2924 buff = HeapAlloc(GetProcessHeap(), 0, len);
2925 memset(buff, 'A', len);
2926 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
2927 EXPECT_HR(hr, S_OK);
2929 pos.QuadPart = 0;
2930 pos2.QuadPart = 0;
2931 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2932 EXPECT_HR(hr, S_OK);
2933 todo_wine
2934 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
2936 hr = IMXWriter_get_output(writer, NULL);
2937 EXPECT_HR(hr, E_POINTER);
2939 ref = get_refcount(stream);
2940 V_VT(&dest) = VT_EMPTY;
2941 hr = IMXWriter_get_output(writer, &dest);
2942 EXPECT_HR(hr, S_OK);
2943 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
2944 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
2945 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
2946 VariantClear(&dest);
2948 hr = ISAXContentHandler_endDocument(content);
2949 EXPECT_HR(hr, S_OK);
2951 IStream_Release(stream);
2953 /* test char count lower than threshold */
2954 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2955 EXPECT_HR(hr, S_OK);
2956 EXPECT_REF(stream, 1);
2958 hr = ISAXContentHandler_startDocument(content);
2959 EXPECT_HR(hr, S_OK);
2961 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
2962 EXPECT_HR(hr, S_OK);
2964 pos.QuadPart = 0;
2965 pos2.QuadPart = 1;
2966 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2967 EXPECT_HR(hr, S_OK);
2968 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2970 memset(buff, 'A', len);
2971 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
2972 EXPECT_HR(hr, S_OK);
2974 pos.QuadPart = 0;
2975 pos2.QuadPart = 1;
2976 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2977 EXPECT_HR(hr, S_OK);
2978 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2980 hr = ISAXContentHandler_endDocument(content);
2981 EXPECT_HR(hr, S_OK);
2983 /* test auto-flush function when stream is not set */
2984 V_VT(&dest) = VT_EMPTY;
2985 hr = IMXWriter_put_output(writer, dest);
2986 EXPECT_HR(hr, S_OK);
2988 hr = ISAXContentHandler_startDocument(content);
2989 EXPECT_HR(hr, S_OK);
2991 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
2992 EXPECT_HR(hr, S_OK);
2994 memset(buff, 'A', len);
2995 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
2996 EXPECT_HR(hr, S_OK);
2998 V_VT(&dest) = VT_EMPTY;
2999 hr = IMXWriter_get_output(writer, &dest);
3000 EXPECT_HR(hr, S_OK);
3001 len += strlen("<a>");
3002 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3003 VariantClear(&dest);
3005 HeapFree(GetProcessHeap(), 0, buff);
3006 ISAXContentHandler_Release(content);
3007 IStream_Release(stream);
3008 IMXWriter_Release(writer);
3009 free_bstrs();
3012 static void test_mxwriter_startenddocument(void)
3014 ISAXContentHandler *content;
3015 IMXWriter *writer;
3016 VARIANT dest;
3017 HRESULT hr;
3019 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3020 &IID_IMXWriter, (void**)&writer);
3021 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3023 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3024 ok(hr == S_OK, "got %08x\n", hr);
3026 hr = ISAXContentHandler_startDocument(content);
3027 ok(hr == S_OK, "got %08x\n", hr);
3029 hr = ISAXContentHandler_endDocument(content);
3030 ok(hr == S_OK, "got %08x\n", hr);
3032 V_VT(&dest) = VT_EMPTY;
3033 hr = IMXWriter_get_output(writer, &dest);
3034 ok(hr == S_OK, "got %08x\n", hr);
3035 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3036 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3037 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3038 VariantClear(&dest);
3040 /* now try another startDocument */
3041 hr = ISAXContentHandler_startDocument(content);
3042 ok(hr == S_OK, "got %08x\n", hr);
3043 /* and get duplicated prolog */
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"
3049 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3050 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3051 VariantClear(&dest);
3053 ISAXContentHandler_Release(content);
3054 IMXWriter_Release(writer);
3056 /* now with omitted declaration */
3057 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3058 &IID_IMXWriter, (void**)&writer);
3059 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3061 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3062 ok(hr == S_OK, "got %08x\n", hr);
3064 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3065 ok(hr == S_OK, "got %08x\n", hr);
3067 hr = ISAXContentHandler_startDocument(content);
3068 ok(hr == S_OK, "got %08x\n", hr);
3070 hr = ISAXContentHandler_endDocument(content);
3071 ok(hr == S_OK, "got %08x\n", hr);
3073 V_VT(&dest) = VT_EMPTY;
3074 hr = IMXWriter_get_output(writer, &dest);
3075 ok(hr == S_OK, "got %08x\n", hr);
3076 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3077 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3078 VariantClear(&dest);
3080 ISAXContentHandler_Release(content);
3081 IMXWriter_Release(writer);
3083 free_bstrs();
3086 enum startendtype
3088 StartElement = 0x001,
3089 EndElement = 0x010,
3090 StartEndElement = 0x011,
3091 DisableEscaping = 0x100
3094 struct writer_startendelement_t {
3095 const GUID *clsid;
3096 enum startendtype type;
3097 const char *uri;
3098 const char *local_name;
3099 const char *qname;
3100 const char *output;
3101 HRESULT hr;
3102 ISAXAttributes *attr;
3105 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\">";
3106 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\"/>";
3107 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
3109 static const struct writer_startendelement_t writer_startendelement[] = {
3110 /* 0 */
3111 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3112 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3113 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3114 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3115 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3116 /* 5 */
3117 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3118 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3119 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3120 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3121 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3122 /* 10 */
3123 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3124 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3125 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3126 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3127 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3128 /* 15 */
3129 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3130 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3131 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3132 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3133 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3134 /* 20 */
3135 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3136 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3137 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3138 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3139 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3140 /* 25 */
3141 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3142 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3143 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3144 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3145 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3146 /* 30 */
3147 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3148 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3149 /* endElement tests */
3150 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3151 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3152 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3153 /* 35 */
3154 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3155 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3156 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3157 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3158 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3159 /* 40 */
3160 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3161 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3162 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3163 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3164 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3165 /* 45 */
3166 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3167 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3168 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3169 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3170 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3171 /* 50 */
3172 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3173 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3174 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3175 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3176 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3177 /* 55 */
3178 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3179 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3180 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3181 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3182 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3183 /* 60 */
3184 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3185 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3186 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3187 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3189 /* with attributes */
3190 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3191 /* 65 */
3192 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3193 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3194 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3195 /* empty elements */
3196 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3197 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3198 /* 70 */
3199 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3200 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3201 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3202 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3203 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3204 /* 75 */
3205 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3207 /* with disabled output escaping */
3208 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3209 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3210 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3211 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3213 { NULL }
3216 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3218 while (table->clsid)
3220 IUnknown *unk;
3221 HRESULT hr;
3223 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3224 if (hr == S_OK) IUnknown_Release(unk);
3226 table->supported = hr == S_OK;
3227 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3229 table++;
3233 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3235 int i = 0;
3237 while (table->clsid)
3239 ISAXContentHandler *content;
3240 IMXWriter *writer;
3241 HRESULT hr;
3243 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3245 table++;
3246 i++;
3247 continue;
3250 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3251 &IID_IMXWriter, (void**)&writer);
3252 EXPECT_HR(hr, S_OK);
3254 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3255 EXPECT_HR(hr, S_OK);
3257 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3258 EXPECT_HR(hr, S_OK);
3260 hr = ISAXContentHandler_startDocument(content);
3261 EXPECT_HR(hr, S_OK);
3263 if (table->type & DisableEscaping)
3265 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3266 EXPECT_HR(hr, S_OK);
3269 if (table->type & StartElement)
3271 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3272 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3273 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3276 if (table->type & EndElement)
3278 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3279 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3280 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3283 /* test output */
3284 if (hr == S_OK)
3286 VARIANT dest;
3288 V_VT(&dest) = VT_EMPTY;
3289 hr = IMXWriter_get_output(writer, &dest);
3290 EXPECT_HR(hr, S_OK);
3291 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3292 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3293 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3294 VariantClear(&dest);
3297 ISAXContentHandler_Release(content);
3298 IMXWriter_Release(writer);
3300 table++;
3301 i++;
3304 free_bstrs();
3307 /* point of these test is to start/end element with different names and name lengths */
3308 struct writer_startendelement2_t {
3309 const GUID *clsid;
3310 const char *qnamestart;
3311 int qnamestart_len;
3312 const char *qnameend;
3313 int qnameend_len;
3314 const char *output;
3315 HRESULT hr;
3318 static const struct writer_startendelement2_t writer_startendelement2[] = {
3319 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3320 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3321 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3322 /* -1 length is not allowed for version 6 */
3323 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3325 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3326 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3327 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3328 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3329 { NULL }
3332 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3334 int i = 0;
3336 while (table->clsid)
3338 ISAXContentHandler *content;
3339 IMXWriter *writer;
3340 HRESULT hr;
3342 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3344 table++;
3345 i++;
3346 continue;
3349 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3350 &IID_IMXWriter, (void**)&writer);
3351 EXPECT_HR(hr, S_OK);
3353 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3354 EXPECT_HR(hr, S_OK);
3356 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3357 EXPECT_HR(hr, S_OK);
3359 hr = ISAXContentHandler_startDocument(content);
3360 EXPECT_HR(hr, S_OK);
3362 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3363 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3364 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3366 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3367 _bstr_(table->qnameend), table->qnameend_len);
3368 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3370 /* test output */
3371 if (hr == S_OK)
3373 VARIANT dest;
3375 V_VT(&dest) = VT_EMPTY;
3376 hr = IMXWriter_get_output(writer, &dest);
3377 EXPECT_HR(hr, S_OK);
3378 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3379 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3380 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3381 VariantClear(&dest);
3384 ISAXContentHandler_Release(content);
3385 IMXWriter_Release(writer);
3387 table++;
3388 i++;
3390 free_bstrs();
3395 static void test_mxwriter_startendelement(void)
3397 ISAXContentHandler *content;
3398 IMXWriter *writer;
3399 VARIANT dest;
3400 HRESULT hr;
3402 test_mxwriter_startendelement_batch(writer_startendelement);
3403 test_mxwriter_startendelement_batch2(writer_startendelement2);
3405 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3406 &IID_IMXWriter, (void**)&writer);
3407 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3409 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3410 ok(hr == S_OK, "got %08x\n", hr);
3412 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3413 ok(hr == S_OK, "got %08x\n", hr);
3415 hr = ISAXContentHandler_startDocument(content);
3416 ok(hr == S_OK, "got %08x\n", hr);
3418 /* all string pointers should be not null */
3419 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3420 ok(hr == S_OK, "got %08x\n", hr);
3422 V_VT(&dest) = VT_EMPTY;
3423 hr = IMXWriter_get_output(writer, &dest);
3424 ok(hr == S_OK, "got %08x\n", hr);
3425 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3426 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3427 VariantClear(&dest);
3429 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3430 ok(hr == S_OK, "got %08x\n", hr);
3432 V_VT(&dest) = VT_EMPTY;
3433 hr = IMXWriter_get_output(writer, &dest);
3434 ok(hr == S_OK, "got %08x\n", hr);
3435 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3436 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3437 VariantClear(&dest);
3439 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3440 EXPECT_HR(hr, E_INVALIDARG);
3442 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3443 EXPECT_HR(hr, E_INVALIDARG);
3445 /* only local name is an error too */
3446 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3447 EXPECT_HR(hr, E_INVALIDARG);
3449 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3450 EXPECT_HR(hr, S_OK);
3452 V_VT(&dest) = VT_EMPTY;
3453 hr = IMXWriter_get_output(writer, &dest);
3454 EXPECT_HR(hr, S_OK);
3455 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3456 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3457 VariantClear(&dest);
3459 hr = ISAXContentHandler_endDocument(content);
3460 EXPECT_HR(hr, S_OK);
3462 V_VT(&dest) = VT_EMPTY;
3463 hr = IMXWriter_put_output(writer, dest);
3464 EXPECT_HR(hr, S_OK);
3466 V_VT(&dest) = VT_EMPTY;
3467 hr = IMXWriter_get_output(writer, &dest);
3468 EXPECT_HR(hr, S_OK);
3469 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3470 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3471 VariantClear(&dest);
3473 hr = ISAXContentHandler_startDocument(content);
3474 EXPECT_HR(hr, S_OK);
3476 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3477 EXPECT_HR(hr, S_OK);
3479 V_VT(&dest) = VT_EMPTY;
3480 hr = IMXWriter_get_output(writer, &dest);
3481 EXPECT_HR(hr, S_OK);
3482 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3483 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3484 VariantClear(&dest);
3486 ISAXContentHandler_endDocument(content);
3487 IMXWriter_flush(writer);
3489 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3490 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></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3496 VariantClear(&dest);
3498 V_VT(&dest) = VT_EMPTY;
3499 hr = IMXWriter_put_output(writer, dest);
3500 EXPECT_HR(hr, S_OK);
3502 /* length -1 */
3503 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3504 EXPECT_HR(hr, S_OK);
3505 V_VT(&dest) = VT_EMPTY;
3506 hr = IMXWriter_get_output(writer, &dest);
3507 EXPECT_HR(hr, S_OK);
3508 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3509 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3510 VariantClear(&dest);
3512 ISAXContentHandler_Release(content);
3513 IMXWriter_Release(writer);
3514 free_bstrs();
3517 struct writer_characters_t {
3518 const GUID *clsid;
3519 const char *data;
3520 const char *output;
3523 static const struct writer_characters_t writer_characters[] = {
3524 { &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
3525 { &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
3526 { &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
3527 { &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
3528 { NULL }
3531 static void test_mxwriter_characters(void)
3533 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3534 const struct writer_characters_t *table = writer_characters;
3535 ISAXContentHandler *content;
3536 IMXWriter *writer;
3537 VARIANT dest;
3538 HRESULT hr;
3539 int i = 0;
3541 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3542 &IID_IMXWriter, (void**)&writer);
3543 EXPECT_HR(hr, S_OK);
3545 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3546 EXPECT_HR(hr, S_OK);
3548 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3549 EXPECT_HR(hr, S_OK);
3551 hr = ISAXContentHandler_startDocument(content);
3552 EXPECT_HR(hr, S_OK);
3554 hr = ISAXContentHandler_characters(content, NULL, 0);
3555 EXPECT_HR(hr, E_INVALIDARG);
3557 hr = ISAXContentHandler_characters(content, chardataW, 0);
3558 EXPECT_HR(hr, S_OK);
3560 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3561 EXPECT_HR(hr, S_OK);
3563 V_VT(&dest) = VT_EMPTY;
3564 hr = IMXWriter_get_output(writer, &dest);
3565 EXPECT_HR(hr, S_OK);
3566 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3567 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3568 VariantClear(&dest);
3570 hr = ISAXContentHandler_endDocument(content);
3571 EXPECT_HR(hr, S_OK);
3573 ISAXContentHandler_Release(content);
3574 IMXWriter_Release(writer);
3576 /* try empty characters data to see if element is closed */
3577 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3578 &IID_IMXWriter, (void**)&writer);
3579 EXPECT_HR(hr, S_OK);
3581 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3582 EXPECT_HR(hr, S_OK);
3584 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3585 EXPECT_HR(hr, S_OK);
3587 hr = ISAXContentHandler_startDocument(content);
3588 EXPECT_HR(hr, S_OK);
3590 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3591 EXPECT_HR(hr, S_OK);
3593 hr = ISAXContentHandler_characters(content, chardataW, 0);
3594 EXPECT_HR(hr, S_OK);
3596 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3597 EXPECT_HR(hr, S_OK);
3599 V_VT(&dest) = VT_EMPTY;
3600 hr = IMXWriter_get_output(writer, &dest);
3601 EXPECT_HR(hr, S_OK);
3602 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3603 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3604 VariantClear(&dest);
3606 ISAXContentHandler_Release(content);
3607 IMXWriter_Release(writer);
3609 /* batch tests */
3610 while (table->clsid)
3612 ISAXContentHandler *content;
3613 IMXWriter *writer;
3614 VARIANT dest;
3615 HRESULT hr;
3617 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3619 table++;
3620 i++;
3621 continue;
3624 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3625 &IID_IMXWriter, (void**)&writer);
3626 EXPECT_HR(hr, S_OK);
3628 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3629 EXPECT_HR(hr, S_OK);
3631 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3632 EXPECT_HR(hr, S_OK);
3634 hr = ISAXContentHandler_startDocument(content);
3635 EXPECT_HR(hr, S_OK);
3637 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3638 EXPECT_HR(hr, S_OK);
3640 /* test output */
3641 if (hr == S_OK)
3643 V_VT(&dest) = VT_EMPTY;
3644 hr = IMXWriter_get_output(writer, &dest);
3645 EXPECT_HR(hr, S_OK);
3646 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3647 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3648 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3649 VariantClear(&dest);
3652 /* with disabled escaping */
3653 V_VT(&dest) = VT_EMPTY;
3654 hr = IMXWriter_put_output(writer, dest);
3655 EXPECT_HR(hr, S_OK);
3657 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3658 EXPECT_HR(hr, S_OK);
3660 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3661 EXPECT_HR(hr, S_OK);
3663 /* test output */
3664 if (hr == S_OK)
3666 V_VT(&dest) = VT_EMPTY;
3667 hr = IMXWriter_get_output(writer, &dest);
3668 EXPECT_HR(hr, S_OK);
3669 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3670 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3671 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3672 VariantClear(&dest);
3675 ISAXContentHandler_Release(content);
3676 IMXWriter_Release(writer);
3678 table++;
3679 i++;
3682 free_bstrs();
3685 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3687 VARIANT_TRUE,"UTF-16",
3689 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3690 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3691 {TRUE}
3695 VARIANT_FALSE,"UTF-16",
3697 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3698 {TRUE}
3702 VARIANT_TRUE,"UTF-8",
3704 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3705 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3706 * and the writer is released.
3708 {FALSE,NULL,0},
3709 {TRUE}
3713 VARIANT_TRUE,"utf-8",
3715 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3716 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3717 * and the writer is released.
3719 {FALSE,NULL,0},
3720 {TRUE}
3724 VARIANT_TRUE,"UTF-16",
3726 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3727 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3728 {TRUE}
3732 VARIANT_TRUE,"UTF-16",
3734 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3735 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3736 {TRUE}
3741 static void test_mxwriter_stream(void)
3743 IMXWriter *writer;
3744 ISAXContentHandler *content;
3745 HRESULT hr;
3746 VARIANT dest;
3747 IStream *stream;
3748 LARGE_INTEGER pos;
3749 ULARGE_INTEGER pos2;
3750 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3752 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3753 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3755 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3756 &IID_IMXWriter, (void**)&writer);
3757 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3759 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3760 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3762 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3763 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3765 V_VT(&dest) = VT_UNKNOWN;
3766 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3767 hr = IMXWriter_put_output(writer, dest);
3768 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3769 VariantClear(&dest);
3771 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3772 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3774 current_write_test = test->expected_writes;
3776 hr = ISAXContentHandler_startDocument(content);
3777 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3779 hr = ISAXContentHandler_endDocument(content);
3780 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3782 ISAXContentHandler_Release(content);
3783 IMXWriter_Release(writer);
3785 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3786 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3789 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3790 &IID_IMXWriter, (void**)&writer);
3791 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3793 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3794 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3796 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3797 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3799 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3800 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3802 V_VT(&dest) = VT_UNKNOWN;
3803 V_UNKNOWN(&dest) = (IUnknown*)stream;
3804 hr = IMXWriter_put_output(writer, dest);
3805 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3807 hr = ISAXContentHandler_startDocument(content);
3808 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3810 /* Setting output of the mxwriter causes the current output to be flushed,
3811 * and the writer to start over.
3813 V_VT(&dest) = VT_EMPTY;
3814 hr = IMXWriter_put_output(writer, dest);
3815 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3817 pos.QuadPart = 0;
3818 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3819 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3820 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3822 hr = ISAXContentHandler_startDocument(content);
3823 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3825 hr = ISAXContentHandler_endDocument(content);
3826 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3828 V_VT(&dest) = VT_EMPTY;
3829 hr = IMXWriter_get_output(writer, &dest);
3830 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3831 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3832 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3833 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3834 VariantClear(&dest);
3836 /* test when BOM is written to output stream */
3837 V_VT(&dest) = VT_EMPTY;
3838 hr = IMXWriter_put_output(writer, dest);
3839 EXPECT_HR(hr, S_OK);
3841 pos.QuadPart = 0;
3842 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3843 EXPECT_HR(hr, S_OK);
3845 V_VT(&dest) = VT_UNKNOWN;
3846 V_UNKNOWN(&dest) = (IUnknown*)stream;
3847 hr = IMXWriter_put_output(writer, dest);
3848 EXPECT_HR(hr, S_OK);
3850 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3851 EXPECT_HR(hr, S_OK);
3853 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3854 EXPECT_HR(hr, S_OK);
3856 hr = ISAXContentHandler_startDocument(content);
3857 EXPECT_HR(hr, S_OK);
3859 pos.QuadPart = 0;
3860 pos2.QuadPart = 0;
3861 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3862 EXPECT_HR(hr, S_OK);
3863 ok(pos2.QuadPart == 2, "got wrong position\n");
3865 ISAXContentHandler_Release(content);
3866 IMXWriter_Release(writer);
3868 free_bstrs();
3871 static const char *encoding_names[] = {
3872 "iso-8859-1",
3873 "iso-8859-2",
3874 "iso-8859-3",
3875 "iso-8859-4",
3876 "iso-8859-5",
3877 "iso-8859-7",
3878 "iso-8859-9",
3879 "iso-8859-13",
3880 "iso-8859-15",
3881 NULL
3884 static void test_mxwriter_encoding(void)
3886 ISAXContentHandler *content;
3887 IMXWriter *writer;
3888 IStream *stream;
3889 const char *enc;
3890 VARIANT dest;
3891 HRESULT hr;
3892 HGLOBAL g;
3893 char *ptr;
3894 BSTR s;
3895 int i;
3897 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3898 &IID_IMXWriter, (void**)&writer);
3899 EXPECT_HR(hr, S_OK);
3901 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3902 EXPECT_HR(hr, S_OK);
3904 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3905 EXPECT_HR(hr, S_OK);
3907 hr = ISAXContentHandler_startDocument(content);
3908 EXPECT_HR(hr, S_OK);
3910 hr = ISAXContentHandler_endDocument(content);
3911 EXPECT_HR(hr, S_OK);
3913 /* The content is always re-encoded to UTF-16 when the output is
3914 * retrieved as a BSTR.
3916 V_VT(&dest) = VT_EMPTY;
3917 hr = IMXWriter_get_output(writer, &dest);
3918 EXPECT_HR(hr, S_OK);
3919 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3920 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3921 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3922 VariantClear(&dest);
3924 /* switch encoding when something is written already */
3925 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3926 EXPECT_HR(hr, S_OK);
3928 V_VT(&dest) = VT_UNKNOWN;
3929 V_UNKNOWN(&dest) = (IUnknown*)stream;
3930 hr = IMXWriter_put_output(writer, dest);
3931 EXPECT_HR(hr, S_OK);
3933 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3934 EXPECT_HR(hr, S_OK);
3936 /* write empty element */
3937 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3938 EXPECT_HR(hr, S_OK);
3940 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3941 EXPECT_HR(hr, S_OK);
3943 /* switch */
3944 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3945 EXPECT_HR(hr, S_OK);
3947 hr = IMXWriter_flush(writer);
3948 EXPECT_HR(hr, S_OK);
3950 hr = GetHGlobalFromStream(stream, &g);
3951 EXPECT_HR(hr, S_OK);
3953 ptr = GlobalLock(g);
3954 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3955 GlobalUnlock(g);
3957 /* so output is unaffected, encoding name is stored however */
3958 hr = IMXWriter_get_encoding(writer, &s);
3959 EXPECT_HR(hr, S_OK);
3960 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3961 SysFreeString(s);
3963 IStream_Release(stream);
3965 i = 0;
3966 enc = encoding_names[i];
3967 while (enc)
3969 char expectedA[200];
3971 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3972 EXPECT_HR(hr, S_OK);
3974 V_VT(&dest) = VT_UNKNOWN;
3975 V_UNKNOWN(&dest) = (IUnknown*)stream;
3976 hr = IMXWriter_put_output(writer, dest);
3977 EXPECT_HR(hr, S_OK);
3979 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
3980 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
3981 "%s: encoding not accepted\n", enc);
3982 if (hr != S_OK)
3984 enc = encoding_names[++i];
3985 IStream_Release(stream);
3986 continue;
3989 hr = ISAXContentHandler_startDocument(content);
3990 EXPECT_HR(hr, S_OK);
3992 hr = ISAXContentHandler_endDocument(content);
3993 EXPECT_HR(hr, S_OK);
3995 hr = IMXWriter_flush(writer);
3996 EXPECT_HR(hr, S_OK);
3998 /* prepare expected string */
3999 *expectedA = 0;
4000 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4001 strcat(expectedA, enc);
4002 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4004 hr = GetHGlobalFromStream(stream, &g);
4005 EXPECT_HR(hr, S_OK);
4007 ptr = GlobalLock(g);
4008 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4009 GlobalUnlock(g);
4011 V_VT(&dest) = VT_EMPTY;
4012 hr = IMXWriter_put_output(writer, dest);
4013 EXPECT_HR(hr, S_OK);
4015 IStream_Release(stream);
4017 enc = encoding_names[++i];
4020 ISAXContentHandler_Release(content);
4021 IMXWriter_Release(writer);
4023 free_bstrs();
4026 static void test_obj_dispex(IUnknown *obj)
4028 static const WCHAR starW[] = {'*',0};
4029 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4030 IDispatchEx *dispex;
4031 IUnknown *unk;
4032 DWORD props;
4033 UINT ticnt;
4034 HRESULT hr;
4035 BSTR name;
4037 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4038 EXPECT_HR(hr, S_OK);
4039 if (FAILED(hr)) return;
4041 ticnt = 0;
4042 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4043 EXPECT_HR(hr, S_OK);
4044 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4046 name = SysAllocString(starW);
4047 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4048 EXPECT_HR(hr, E_NOTIMPL);
4049 SysFreeString(name);
4051 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4052 EXPECT_HR(hr, E_NOTIMPL);
4054 props = 0;
4055 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4056 EXPECT_HR(hr, E_NOTIMPL);
4057 ok(props == 0, "expected 0 got %d\n", props);
4059 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4060 EXPECT_HR(hr, E_NOTIMPL);
4061 if (SUCCEEDED(hr)) SysFreeString(name);
4063 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4064 EXPECT_HR(hr, E_NOTIMPL);
4066 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4067 EXPECT_HR(hr, E_NOTIMPL);
4068 if (hr == S_OK && unk) IUnknown_Release(unk);
4070 IDispatchEx_Release(dispex);
4073 static void test_dispex(void)
4075 IVBSAXXMLReader *vbreader;
4076 ISAXXMLReader *reader;
4077 IUnknown *unk;
4078 HRESULT hr;
4080 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4081 &IID_ISAXXMLReader, (void**)&reader);
4082 EXPECT_HR(hr, S_OK);
4084 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4085 EXPECT_HR(hr, S_OK);
4086 test_obj_dispex(unk);
4087 IUnknown_Release(unk);
4089 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4090 EXPECT_HR(hr, S_OK);
4091 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4092 EXPECT_HR(hr, S_OK);
4093 test_obj_dispex(unk);
4094 IUnknown_Release(unk);
4095 IVBSAXXMLReader_Release(vbreader);
4097 ISAXXMLReader_Release(reader);
4100 static void test_mxwriter_dispex(void)
4102 IDispatchEx *dispex;
4103 IMXWriter *writer;
4104 IUnknown *unk;
4105 HRESULT hr;
4107 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4108 &IID_IMXWriter, (void**)&writer);
4109 EXPECT_HR(hr, S_OK);
4111 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4112 EXPECT_HR(hr, S_OK);
4113 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4114 test_obj_dispex(unk);
4115 IUnknown_Release(unk);
4116 IDispatchEx_Release(dispex);
4118 IMXWriter_Release(writer);
4121 static void test_mxwriter_comment(void)
4123 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4124 ISAXContentHandler *content;
4125 ISAXLexicalHandler *lexical;
4126 IMXWriter *writer;
4127 VARIANT dest;
4128 HRESULT hr;
4130 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4131 &IID_IMXWriter, (void**)&writer);
4132 EXPECT_HR(hr, S_OK);
4134 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4135 EXPECT_HR(hr, S_OK);
4137 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4138 EXPECT_HR(hr, S_OK);
4140 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4141 EXPECT_HR(hr, S_OK);
4143 hr = ISAXContentHandler_startDocument(content);
4144 EXPECT_HR(hr, S_OK);
4146 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4147 EXPECT_HR(hr, E_INVALIDARG);
4149 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4150 EXPECT_HR(hr, S_OK);
4152 V_VT(&dest) = VT_EMPTY;
4153 hr = IMXWriter_get_output(writer, &dest);
4154 EXPECT_HR(hr, S_OK);
4155 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4156 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4157 VariantClear(&dest);
4159 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4160 EXPECT_HR(hr, S_OK);
4162 V_VT(&dest) = VT_EMPTY;
4163 hr = IMXWriter_get_output(writer, &dest);
4164 EXPECT_HR(hr, S_OK);
4165 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4166 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4167 VariantClear(&dest);
4169 ISAXContentHandler_Release(content);
4170 ISAXLexicalHandler_Release(lexical);
4171 IMXWriter_Release(writer);
4172 free_bstrs();
4175 static void test_mxwriter_cdata(void)
4177 ISAXContentHandler *content;
4178 ISAXLexicalHandler *lexical;
4179 IMXWriter *writer;
4180 VARIANT dest;
4181 HRESULT hr;
4183 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4184 &IID_IMXWriter, (void**)&writer);
4185 EXPECT_HR(hr, S_OK);
4187 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4188 EXPECT_HR(hr, S_OK);
4190 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4191 EXPECT_HR(hr, S_OK);
4193 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4194 EXPECT_HR(hr, S_OK);
4196 hr = ISAXContentHandler_startDocument(content);
4197 EXPECT_HR(hr, S_OK);
4199 hr = ISAXLexicalHandler_startCDATA(lexical);
4200 EXPECT_HR(hr, S_OK);
4202 V_VT(&dest) = VT_EMPTY;
4203 hr = IMXWriter_get_output(writer, &dest);
4204 EXPECT_HR(hr, S_OK);
4205 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4206 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4207 VariantClear(&dest);
4209 hr = ISAXLexicalHandler_startCDATA(lexical);
4210 EXPECT_HR(hr, S_OK);
4212 /* all these are escaped for text nodes */
4213 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4214 EXPECT_HR(hr, S_OK);
4216 hr = ISAXLexicalHandler_endCDATA(lexical);
4217 EXPECT_HR(hr, S_OK);
4219 V_VT(&dest) = VT_EMPTY;
4220 hr = IMXWriter_get_output(writer, &dest);
4221 EXPECT_HR(hr, S_OK);
4222 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4223 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4224 VariantClear(&dest);
4226 ISAXContentHandler_Release(content);
4227 ISAXLexicalHandler_Release(lexical);
4228 IMXWriter_Release(writer);
4229 free_bstrs();
4232 static void test_mxwriter_pi(void)
4234 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4235 static const WCHAR dataW[] = {'d','a','t','a',0};
4236 ISAXContentHandler *content;
4237 IMXWriter *writer;
4238 VARIANT dest;
4239 HRESULT hr;
4241 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4242 &IID_IMXWriter, (void**)&writer);
4243 EXPECT_HR(hr, S_OK);
4245 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4246 EXPECT_HR(hr, S_OK);
4248 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4249 EXPECT_HR(hr, E_INVALIDARG);
4251 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4252 EXPECT_HR(hr, S_OK);
4254 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4255 EXPECT_HR(hr, S_OK);
4257 V_VT(&dest) = VT_EMPTY;
4258 hr = IMXWriter_get_output(writer, &dest);
4259 EXPECT_HR(hr, S_OK);
4260 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4261 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4262 VariantClear(&dest);
4264 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4265 EXPECT_HR(hr, S_OK);
4267 V_VT(&dest) = VT_EMPTY;
4268 hr = IMXWriter_get_output(writer, &dest);
4269 EXPECT_HR(hr, S_OK);
4270 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4271 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)));
4272 VariantClear(&dest);
4274 V_VT(&dest) = VT_EMPTY;
4275 hr = IMXWriter_put_output(writer, dest);
4276 EXPECT_HR(hr, S_OK);
4278 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4279 EXPECT_HR(hr, S_OK);
4281 V_VT(&dest) = VT_EMPTY;
4282 hr = IMXWriter_get_output(writer, &dest);
4283 EXPECT_HR(hr, S_OK);
4284 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4285 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4286 VariantClear(&dest);
4289 ISAXContentHandler_Release(content);
4290 IMXWriter_Release(writer);
4293 static void test_mxwriter_ignorablespaces(void)
4295 static const WCHAR dataW[] = {'d','a','t','a',0};
4296 ISAXContentHandler *content;
4297 IMXWriter *writer;
4298 VARIANT dest;
4299 HRESULT hr;
4301 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4302 &IID_IMXWriter, (void**)&writer);
4303 EXPECT_HR(hr, S_OK);
4305 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4306 EXPECT_HR(hr, S_OK);
4308 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4309 EXPECT_HR(hr, E_INVALIDARG);
4311 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4312 EXPECT_HR(hr, S_OK);
4314 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4315 EXPECT_HR(hr, S_OK);
4317 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4318 EXPECT_HR(hr, S_OK);
4320 V_VT(&dest) = VT_EMPTY;
4321 hr = IMXWriter_get_output(writer, &dest);
4322 EXPECT_HR(hr, S_OK);
4323 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4324 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4325 VariantClear(&dest);
4327 ISAXContentHandler_Release(content);
4328 IMXWriter_Release(writer);
4331 static void test_mxwriter_dtd(void)
4333 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4334 static const WCHAR nameW[] = {'n','a','m','e'};
4335 static const WCHAR pubW[] = {'p','u','b'};
4336 static const WCHAR sysW[] = {'s','y','s'};
4337 ISAXContentHandler *content;
4338 ISAXLexicalHandler *lexical;
4339 ISAXDeclHandler *decl;
4340 IMXWriter *writer;
4341 VARIANT dest;
4342 HRESULT hr;
4344 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4345 &IID_IMXWriter, (void**)&writer);
4346 EXPECT_HR(hr, S_OK);
4348 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4349 EXPECT_HR(hr, S_OK);
4351 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4352 EXPECT_HR(hr, S_OK);
4354 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4355 EXPECT_HR(hr, S_OK);
4357 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4358 EXPECT_HR(hr, S_OK);
4360 hr = ISAXContentHandler_startDocument(content);
4361 EXPECT_HR(hr, S_OK);
4363 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4364 EXPECT_HR(hr, E_INVALIDARG);
4366 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4367 EXPECT_HR(hr, E_INVALIDARG);
4369 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4370 EXPECT_HR(hr, E_INVALIDARG);
4372 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4373 EXPECT_HR(hr, E_INVALIDARG);
4375 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4376 EXPECT_HR(hr, S_OK);
4378 V_VT(&dest) = VT_EMPTY;
4379 hr = IMXWriter_get_output(writer, &dest);
4380 EXPECT_HR(hr, S_OK);
4381 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4382 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4383 VariantClear(&dest);
4385 /* system id is required if public is present */
4386 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4387 EXPECT_HR(hr, E_INVALIDARG);
4389 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4390 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4391 EXPECT_HR(hr, S_OK);
4393 V_VT(&dest) = VT_EMPTY;
4394 hr = IMXWriter_get_output(writer, &dest);
4395 EXPECT_HR(hr, S_OK);
4396 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4397 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4398 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4399 VariantClear(&dest);
4401 hr = ISAXLexicalHandler_endDTD(lexical);
4402 EXPECT_HR(hr, S_OK);
4404 hr = ISAXLexicalHandler_endDTD(lexical);
4405 EXPECT_HR(hr, S_OK);
4407 V_VT(&dest) = VT_EMPTY;
4408 hr = IMXWriter_get_output(writer, &dest);
4409 EXPECT_HR(hr, S_OK);
4410 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4411 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4412 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4413 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4414 VariantClear(&dest);
4416 /* element declaration */
4417 V_VT(&dest) = VT_EMPTY;
4418 hr = IMXWriter_put_output(writer, dest);
4419 EXPECT_HR(hr, S_OK);
4421 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4422 EXPECT_HR(hr, E_INVALIDARG);
4424 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4425 EXPECT_HR(hr, E_INVALIDARG);
4427 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4428 EXPECT_HR(hr, S_OK);
4430 V_VT(&dest) = VT_EMPTY;
4431 hr = IMXWriter_get_output(writer, &dest);
4432 EXPECT_HR(hr, S_OK);
4433 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4434 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4435 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4436 VariantClear(&dest);
4438 V_VT(&dest) = VT_EMPTY;
4439 hr = IMXWriter_put_output(writer, dest);
4440 EXPECT_HR(hr, S_OK);
4442 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4443 EXPECT_HR(hr, S_OK);
4445 V_VT(&dest) = VT_EMPTY;
4446 hr = IMXWriter_get_output(writer, &dest);
4447 EXPECT_HR(hr, S_OK);
4448 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4449 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4450 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4451 VariantClear(&dest);
4453 /* attribute declaration */
4454 V_VT(&dest) = VT_EMPTY;
4455 hr = IMXWriter_put_output(writer, dest);
4456 EXPECT_HR(hr, S_OK);
4458 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4459 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4460 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4461 EXPECT_HR(hr, S_OK);
4463 V_VT(&dest) = VT_EMPTY;
4464 hr = IMXWriter_get_output(writer, &dest);
4465 EXPECT_HR(hr, S_OK);
4466 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4467 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4468 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4469 VariantClear(&dest);
4471 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4472 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4473 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4474 EXPECT_HR(hr, S_OK);
4476 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4477 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4478 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4479 EXPECT_HR(hr, S_OK);
4481 V_VT(&dest) = VT_EMPTY;
4482 hr = IMXWriter_get_output(writer, &dest);
4483 EXPECT_HR(hr, S_OK);
4484 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4485 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4486 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4487 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4488 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4489 VariantClear(&dest);
4491 /* internal entities */
4492 V_VT(&dest) = VT_EMPTY;
4493 hr = IMXWriter_put_output(writer, dest);
4494 EXPECT_HR(hr, S_OK);
4496 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4497 EXPECT_HR(hr, E_INVALIDARG);
4499 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4500 EXPECT_HR(hr, E_INVALIDARG);
4502 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4503 EXPECT_HR(hr, S_OK);
4505 V_VT(&dest) = VT_EMPTY;
4506 hr = IMXWriter_get_output(writer, &dest);
4507 EXPECT_HR(hr, S_OK);
4508 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4509 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4510 VariantClear(&dest);
4512 ISAXContentHandler_Release(content);
4513 ISAXLexicalHandler_Release(lexical);
4514 ISAXDeclHandler_Release(decl);
4515 IMXWriter_Release(writer);
4516 free_bstrs();
4519 typedef struct {
4520 const CLSID *clsid;
4521 const char *uri;
4522 const char *local;
4523 const char *qname;
4524 const char *type;
4525 const char *value;
4526 HRESULT hr;
4527 } addattribute_test_t;
4529 static const addattribute_test_t addattribute_data[] = {
4530 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4531 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4532 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4533 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4535 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4536 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4537 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4538 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4540 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4541 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4542 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4543 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4545 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4546 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4547 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4548 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4550 { NULL }
4553 static void test_mxattr_addAttribute(void)
4555 const addattribute_test_t *table = addattribute_data;
4556 int i = 0;
4558 while (table->clsid)
4560 ISAXAttributes *saxattr;
4561 IMXAttributes *mxattr;
4562 const WCHAR *value;
4563 int len, index;
4564 HRESULT hr;
4566 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4568 table++;
4569 i++;
4570 continue;
4573 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4574 &IID_IMXAttributes, (void**)&mxattr);
4575 EXPECT_HR(hr, S_OK);
4577 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4578 EXPECT_HR(hr, S_OK);
4580 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4581 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4582 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4584 hr = ISAXAttributes_getLength(saxattr, NULL);
4585 EXPECT_HR(hr, E_POINTER);
4588 len = -1;
4589 hr = ISAXAttributes_getLength(saxattr, &len);
4590 EXPECT_HR(hr, S_OK);
4591 ok(len == 0, "got %d\n", len);
4593 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4594 EXPECT_HR(hr, E_INVALIDARG);
4596 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4597 EXPECT_HR(hr, E_INVALIDARG);
4599 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4600 EXPECT_HR(hr, E_INVALIDARG);
4602 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4603 EXPECT_HR(hr, E_INVALIDARG);
4605 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4606 EXPECT_HR(hr, E_INVALIDARG);
4608 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4609 EXPECT_HR(hr, E_INVALIDARG);
4611 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4612 EXPECT_HR(hr, E_INVALIDARG);
4614 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4615 EXPECT_HR(hr, E_INVALIDARG);
4617 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4618 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4619 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4621 if (hr == S_OK)
4623 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4624 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4625 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4627 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4628 EXPECT_HR(hr, E_POINTER);
4630 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4631 EXPECT_HR(hr, E_POINTER);
4633 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4634 EXPECT_HR(hr, E_POINTER);
4636 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4637 EXPECT_HR(hr, E_POINTER);
4639 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4640 EXPECT_HR(hr, E_POINTER);
4642 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4643 EXPECT_HR(hr, E_POINTER);
4646 len = -1;
4647 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4648 EXPECT_HR(hr, S_OK);
4649 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4650 table->value);
4651 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4653 len = -1;
4654 value = (void*)0xdeadbeef;
4655 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4656 EXPECT_HR(hr, S_OK);
4658 if (table->type)
4660 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4661 table->type);
4662 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4664 else
4666 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4667 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4670 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4671 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4672 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4674 EXPECT_HR(hr, E_POINTER);
4676 else
4677 EXPECT_HR(hr, E_INVALIDARG);
4679 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4680 EXPECT_HR(hr, E_INVALIDARG);
4682 index = -1;
4683 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4684 EXPECT_HR(hr, E_INVALIDARG);
4685 ok(index == -1, "%d: got wrong index %d\n", i, index);
4687 index = -1;
4688 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4689 EXPECT_HR(hr, E_INVALIDARG);
4690 ok(index == -1, "%d: got wrong index %d\n", i, index);
4692 index = -1;
4693 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4694 EXPECT_HR(hr, S_OK);
4695 ok(index == 0, "%d: got wrong index %d\n", i, index);
4697 index = -1;
4698 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4699 EXPECT_HR(hr, E_INVALIDARG);
4700 ok(index == -1, "%d: got wrong index %d\n", i, index);
4702 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4703 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4705 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4706 EXPECT_HR(hr, E_INVALIDARG);
4708 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4709 EXPECT_HR(hr, E_INVALIDARG);
4711 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4712 EXPECT_HR(hr, E_INVALIDARG);
4714 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4715 EXPECT_HR(hr, E_INVALIDARG);
4717 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4718 EXPECT_HR(hr, E_INVALIDARG);
4720 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4721 EXPECT_HR(hr, E_INVALIDARG);
4723 else
4725 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4726 EXPECT_HR(hr, E_POINTER);
4728 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4729 EXPECT_HR(hr, E_POINTER);
4731 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4732 EXPECT_HR(hr, E_POINTER);
4734 /* versions 4 and 6 crash */
4735 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4736 EXPECT_HR(hr, E_POINTER);
4738 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4739 EXPECT_HR(hr, E_POINTER);
4741 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4742 EXPECT_HR(hr, E_POINTER);
4744 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4745 EXPECT_HR(hr, E_POINTER);
4747 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4748 EXPECT_HR(hr, E_POINTER);
4750 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4751 EXPECT_HR(hr, E_POINTER);
4753 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4754 EXPECT_HR(hr, E_POINTER);
4756 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4757 strlen(table->local), NULL, NULL);
4758 EXPECT_HR(hr, E_POINTER);
4761 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4762 EXPECT_HR(hr, S_OK);
4763 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4764 table->value);
4765 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4767 if (table->uri) {
4768 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4769 _bstr_(table->local), strlen(table->local), &value, &len);
4770 EXPECT_HR(hr, S_OK);
4771 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4772 table->value);
4773 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4777 len = -1;
4778 hr = ISAXAttributes_getLength(saxattr, &len);
4779 EXPECT_HR(hr, S_OK);
4780 if (table->hr == S_OK)
4781 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
4782 else
4783 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
4785 ISAXAttributes_Release(saxattr);
4786 IMXAttributes_Release(mxattr);
4788 table++;
4789 i++;
4792 free_bstrs();
4795 static void test_mxattr_clear(void)
4797 ISAXAttributes *saxattr;
4798 IMXAttributes *mxattr;
4799 const WCHAR *ptr;
4800 HRESULT hr;
4801 int len;
4803 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4804 &IID_IMXAttributes, (void**)&mxattr);
4805 EXPECT_HR(hr, S_OK);
4807 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4808 EXPECT_HR(hr, S_OK);
4810 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4811 EXPECT_HR(hr, E_INVALIDARG);
4813 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4814 EXPECT_HR(hr, E_INVALIDARG);
4816 hr = IMXAttributes_clear(mxattr);
4817 EXPECT_HR(hr, S_OK);
4819 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4820 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4821 EXPECT_HR(hr, S_OK);
4823 len = -1;
4824 hr = ISAXAttributes_getLength(saxattr, &len);
4825 EXPECT_HR(hr, S_OK);
4826 ok(len == 1, "got %d\n", len);
4828 len = -1;
4829 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4830 EXPECT_HR(hr, E_POINTER);
4831 ok(len == -1, "got %d\n", len);
4833 ptr = (void*)0xdeadbeef;
4834 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4835 EXPECT_HR(hr, E_POINTER);
4836 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4838 len = 0;
4839 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4840 EXPECT_HR(hr, S_OK);
4841 ok(len == 5, "got %d\n", len);
4842 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4844 hr = IMXAttributes_clear(mxattr);
4845 EXPECT_HR(hr, S_OK);
4847 len = -1;
4848 hr = ISAXAttributes_getLength(saxattr, &len);
4849 EXPECT_HR(hr, S_OK);
4850 ok(len == 0, "got %d\n", len);
4852 len = -1;
4853 ptr = (void*)0xdeadbeef;
4854 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4855 EXPECT_HR(hr, E_INVALIDARG);
4856 ok(len == -1, "got %d\n", len);
4857 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4859 IMXAttributes_Release(mxattr);
4860 ISAXAttributes_Release(saxattr);
4861 free_bstrs();
4864 static void test_mxattr_dispex(void)
4866 IMXAttributes *mxattr;
4867 IDispatchEx *dispex;
4868 IUnknown *unk;
4869 HRESULT hr;
4871 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4872 &IID_IMXAttributes, (void**)&mxattr);
4873 EXPECT_HR(hr, S_OK);
4875 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4876 EXPECT_HR(hr, S_OK);
4877 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4878 test_obj_dispex(unk);
4879 IUnknown_Release(unk);
4880 IDispatchEx_Release(dispex);
4882 IMXAttributes_Release(mxattr);
4885 static void test_mxattr_qi(void)
4887 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4888 ISAXAttributes *saxattr;
4889 IMXAttributes *mxattr;
4890 HRESULT hr;
4892 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4893 &IID_IMXAttributes, (void**)&mxattr);
4894 EXPECT_HR(hr, S_OK);
4896 EXPECT_REF(mxattr, 1);
4897 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4898 EXPECT_HR(hr, S_OK);
4900 EXPECT_REF(mxattr, 2);
4901 EXPECT_REF(saxattr, 2);
4903 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4904 EXPECT_HR(hr, S_OK);
4906 EXPECT_REF(vbsaxattr, 3);
4907 EXPECT_REF(mxattr, 3);
4908 EXPECT_REF(saxattr, 3);
4910 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4911 EXPECT_HR(hr, S_OK);
4913 EXPECT_REF(vbsaxattr, 4);
4914 EXPECT_REF(mxattr, 4);
4915 EXPECT_REF(saxattr, 4);
4917 IMXAttributes_Release(mxattr);
4918 ISAXAttributes_Release(saxattr);
4919 IVBSAXAttributes_Release(vbsaxattr);
4920 IVBSAXAttributes_Release(vbsaxattr2);
4923 static struct msxmlsupported_data_t saxattr_support_data[] =
4925 { &CLSID_SAXAttributes, "SAXAttributes" },
4926 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4927 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4928 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4929 { NULL }
4932 static void test_mxattr_localname(void)
4934 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4935 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4936 static const WCHAR uri1W[] = {'u','r','i','1',0};
4937 static const WCHAR uriW[] = {'u','r','i',0};
4939 const struct msxmlsupported_data_t *table = saxattr_support_data;
4941 while (table->clsid)
4943 ISAXAttributes *saxattr;
4944 IMXAttributes *mxattr;
4945 HRESULT hr;
4946 int index;
4948 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4950 table++;
4951 continue;
4954 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4955 &IID_IMXAttributes, (void**)&mxattr);
4956 EXPECT_HR(hr, S_OK);
4958 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4959 EXPECT_HR(hr, S_OK);
4961 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4962 EXPECT_HR(hr, E_INVALIDARG);
4964 /* add some ambiguos attribute names */
4965 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4966 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4967 EXPECT_HR(hr, S_OK);
4968 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4969 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4970 EXPECT_HR(hr, S_OK);
4972 index = -1;
4973 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4974 EXPECT_HR(hr, S_OK);
4975 ok(index == 0, "%s: got index %d\n", table->name, index);
4977 index = -1;
4978 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4979 EXPECT_HR(hr, E_INVALIDARG);
4980 ok(index == -1, "%s: got index %d\n", table->name, index);
4982 index = -1;
4983 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4984 EXPECT_HR(hr, E_INVALIDARG);
4985 ok(index == -1, "%s: got index %d\n", table->name, index);
4987 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4988 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4990 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4991 EXPECT_HR(hr, E_POINTER);
4993 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4994 EXPECT_HR(hr, E_POINTER);
4996 else
4998 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4999 EXPECT_HR(hr, E_INVALIDARG);
5001 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5002 EXPECT_HR(hr, E_INVALIDARG);
5005 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5006 EXPECT_HR(hr, E_INVALIDARG);
5008 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5009 EXPECT_HR(hr, E_INVALIDARG);
5011 table++;
5013 ISAXAttributes_Release(saxattr);
5014 IMXAttributes_Release(mxattr);
5018 START_TEST(saxreader)
5020 ISAXXMLReader *reader;
5021 HRESULT hr;
5023 hr = CoInitialize(NULL);
5024 ok(hr == S_OK, "failed to init com\n");
5026 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5027 &IID_ISAXXMLReader, (void**)&reader);
5029 if(FAILED(hr))
5031 skip("Failed to create SAXXMLReader instance\n");
5032 CoUninitialize();
5033 return;
5035 ISAXXMLReader_Release(reader);
5037 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5039 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5041 test_saxreader();
5042 test_saxreader_properties();
5043 test_saxreader_features();
5044 test_saxreader_encoding();
5045 test_dispex();
5047 /* MXXMLWriter tests */
5048 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5049 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5051 test_mxwriter_handlers();
5052 test_mxwriter_startenddocument();
5053 test_mxwriter_startendelement();
5054 test_mxwriter_characters();
5055 test_mxwriter_comment();
5056 test_mxwriter_cdata();
5057 test_mxwriter_pi();
5058 test_mxwriter_ignorablespaces();
5059 test_mxwriter_dtd();
5060 test_mxwriter_properties();
5061 test_mxwriter_flush();
5062 test_mxwriter_stream();
5063 test_mxwriter_encoding();
5064 test_mxwriter_dispex();
5066 else
5067 win_skip("MXXMLWriter not supported\n");
5069 /* SAXAttributes tests */
5070 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5071 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5073 test_mxattr_qi();
5074 test_mxattr_addAttribute();
5075 test_mxattr_clear();
5076 test_mxattr_localname();
5077 test_mxattr_dispex();
5079 else
5080 skip("SAXAttributes not supported\n");
5082 CoUninitialize();