Release 1.6-rc2.
[wine/testsucceed.git] / dlls / msxml3 / tests / saxreader.c
blobdf0aa47a45df41d827a8437627d38da2d4c51d3e
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 LH_STARTCDATA,
172 LH_ENDCDATA,
173 EH_ERROR,
174 EH_FATALERROR,
175 EH_IGNORABLEWARNING,
176 EVENT_LAST
177 } CH;
179 static const char *event_names[EVENT_LAST] = {
180 "endtest",
181 "putDocumentLocator",
182 "startDocument",
183 "endDocument",
184 "startPrefixMapping",
185 "endPrefixMapping",
186 "startElement",
187 "endElement",
188 "characters",
189 "ignorableWhitespace",
190 "processingInstruction",
191 "skippedEntity",
192 "startCDATA",
193 "endCDATA",
194 "error",
195 "fatalError",
196 "ignorableWarning"
199 struct attribute_entry {
200 const char *uri;
201 const char *local;
202 const char *qname;
203 const char *value;
205 /* used for actual call data only, null for expected call data */
206 BSTR uriW;
207 BSTR localW;
208 BSTR qnameW;
209 BSTR valueW;
212 struct call_entry {
213 CH id;
214 int line;
215 int column;
216 HRESULT ret;
217 const char *arg1;
218 const char *arg2;
219 const char *arg3;
221 /* allocated once at startElement callback */
222 struct attribute_entry *attributes;
223 int attr_count;
225 /* used for actual call data only, null for expected call data */
226 BSTR arg1W;
227 BSTR arg2W;
228 BSTR arg3W;
231 struct call_sequence
233 int count;
234 int size;
235 struct call_entry *sequence;
238 #define CONTENT_HANDLER_INDEX 0
239 #define NUM_CALL_SEQUENCES 1
240 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
242 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
244 memset(call, 0, sizeof(*call));
245 ISAXLocator_getLineNumber(locator, &call->line);
246 ISAXLocator_getColumnNumber(locator, &call->column);
249 static void add_call(struct call_sequence **seq, int sequence_index,
250 const struct call_entry *call)
252 struct call_sequence *call_seq = seq[sequence_index];
254 if (!call_seq->sequence)
256 call_seq->size = 10;
257 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
258 call_seq->size * sizeof (struct call_entry));
261 if (call_seq->count == call_seq->size)
263 call_seq->size *= 2;
264 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
265 call_seq->sequence,
266 call_seq->size * sizeof (struct call_entry));
269 assert(call_seq->sequence);
271 call_seq->sequence[call_seq->count].id = call->id;
272 call_seq->sequence[call_seq->count].line = call->line;
273 call_seq->sequence[call_seq->count].column = call->column;
274 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
275 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
276 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
277 call_seq->sequence[call_seq->count].ret = call->ret;
278 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
279 call_seq->sequence[call_seq->count].attributes = call->attributes;
281 call_seq->count++;
284 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
286 int i;
288 struct call_sequence *call_seq = seg[sequence_index];
290 for (i = 0; i < call_seq->count; i++)
292 int j;
294 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
296 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
297 SysFreeString(call_seq->sequence[i].attributes[j].localW);
298 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
301 SysFreeString(call_seq->sequence[i].arg1W);
302 SysFreeString(call_seq->sequence[i].arg2W);
303 SysFreeString(call_seq->sequence[i].arg3W);
306 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
307 call_seq->sequence = NULL;
308 call_seq->count = call_seq->size = 0;
311 static inline void flush_sequences(struct call_sequence **seq, int n)
313 int i;
314 for (i = 0; i < n; i++)
315 flush_sequence(seq, i);
318 static const char *get_event_name(CH event)
320 return event_names[event];
323 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
324 int todo, const char *file, int line, int *failcount)
326 int i, lenexp = 0;
328 /* attribute count is not stored for expected data */
329 if (expected->attributes)
331 struct attribute_entry *ptr = expected->attributes;
332 while (ptr->uri) { lenexp++; ptr++; };
335 /* check count first and exit earlier */
336 if (actual->attr_count != lenexp && todo)
338 (*failcount)++;
339 todo_wine
340 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
341 context, get_event_name(actual->id), lenexp, actual->attr_count);
343 else
344 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
345 context, get_event_name(actual->id), lenexp, actual->attr_count);
347 if (actual->attr_count != lenexp) return;
349 /* now compare all attributes strings */
350 for (i = 0; i < actual->attr_count; i++)
352 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
353 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
354 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
355 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
359 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
360 const struct call_entry *expected, const char *context, int todo,
361 const char *file, int line)
363 struct call_sequence *call_seq = seq[sequence_index];
364 static const struct call_entry end_of_sequence = { CH_ENDTEST };
365 const struct call_entry *actual, *sequence;
366 int failcount = 0;
368 add_call(seq, sequence_index, &end_of_sequence);
370 sequence = call_seq->sequence;
371 actual = sequence;
373 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
375 if (expected->id == actual->id)
377 /* always test position data */
378 if (expected->line != actual->line && todo)
380 todo_wine
382 failcount++;
383 ok_(file, line) (FALSE,
384 "%s: in event %s expecting line %d got %d\n",
385 context, get_event_name(actual->id), expected->line, actual->line);
388 else
390 ok_(file, line) (expected->line == actual->line,
391 "%s: in event %s expecting line %d got %d\n",
392 context, get_event_name(actual->id), expected->line, actual->line);
395 if (expected->column != actual->column && todo)
397 todo_wine
399 failcount++;
400 ok_(file, line) (FALSE,
401 "%s: in event %s expecting column %d got %d\n",
402 context, get_event_name(actual->id), expected->column, actual->column);
405 else
407 ok_(file, line) (expected->column == actual->column,
408 "%s: in event %s expecting column %d got %d\n",
409 context, get_event_name(actual->id), expected->column, actual->column);
412 switch (actual->id)
414 case CH_PUTDOCUMENTLOCATOR:
415 case CH_STARTDOCUMENT:
416 case CH_ENDDOCUMENT:
417 case LH_STARTCDATA:
418 case LH_ENDCDATA:
419 break;
420 case CH_STARTPREFIXMAPPING:
421 /* prefix, uri */
422 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
423 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
424 break;
425 case CH_ENDPREFIXMAPPING:
426 /* prefix */
427 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
428 break;
429 case CH_STARTELEMENT:
430 /* compare attributes */
431 compare_attributes(actual, expected, context, todo, file, line, &failcount);
432 /* fallthrough */
433 case CH_ENDELEMENT:
434 /* uri, localname, qname */
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
436 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
437 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
438 break;
439 case CH_CHARACTERS:
440 case CH_IGNORABLEWHITESPACE:
441 /* char data */
442 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
443 break;
444 case CH_PROCESSINGINSTRUCTION:
445 /* target, data */
446 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
447 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
448 break;
449 case CH_SKIPPEDENTITY:
450 /* name */
451 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
452 break;
453 case EH_FATALERROR:
454 /* test return value only */
455 if (expected->ret != actual->ret && todo)
457 failcount++;
458 ok_(file, line) (FALSE,
459 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
460 context, get_event_name(actual->id), expected->ret, actual->ret);
462 else
463 ok_(file, line) (expected->ret == actual->ret,
464 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
465 context, get_event_name(actual->id), expected->ret, actual->ret);
466 break;
467 case EH_ERROR:
468 case EH_IGNORABLEWARNING:
469 default:
470 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
472 expected++;
473 actual++;
475 else if (todo)
477 failcount++;
478 todo_wine
480 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
481 context, get_event_name(expected->id), get_event_name(actual->id));
484 flush_sequence(seq, sequence_index);
485 return;
487 else
489 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
490 context, get_event_name(expected->id), get_event_name(actual->id));
491 expected++;
492 actual++;
496 if (todo)
498 todo_wine
500 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
502 failcount++;
503 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
504 context, get_event_name(expected->id), get_event_name(actual->id));
508 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
510 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
511 context, get_event_name(expected->id), get_event_name(actual->id));
514 if (todo && !failcount) /* succeeded yet marked todo */
516 todo_wine
518 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
522 flush_sequence(seq, sequence_index);
525 #define ok_sequence(seq, index, exp, contx, todo) \
526 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
528 static void init_call_sequences(struct call_sequence **seq, int n)
530 int i;
532 for (i = 0; i < n; i++)
533 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
536 static const WCHAR szSimpleXML[] = {
537 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
538 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
539 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
540 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
541 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
544 static const WCHAR carriage_ret_test[] = {
545 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
546 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
547 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
548 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
549 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
552 static const WCHAR szUtf16XML[] = {
553 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
554 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
555 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
558 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
560 static const CHAR szUtf8XML[] =
561 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
563 static const char utf8xml2[] =
564 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
566 static const char testXML[] =
567 "<?xml version=\"1.0\" ?>\n"
568 "<BankAccount>\n"
569 " <Number>1234</Number>\n"
570 " <Name>Captain Ahab</Name>\n"
571 "</BankAccount>\n";
573 static const char test_attributes[] =
574 "<?xml version=\"1.0\" ?>\n"
575 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
576 "<node1 xmlns:p=\"test\" />"
577 "</document>\n";
579 static const char test_cdata_xml[] =
580 "<?xml version=\"1.0\" ?>"
581 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
583 static const char test2_cdata_xml[] =
584 "<?xml version=\"1.0\" ?>"
585 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
587 static const char test3_cdata_xml[] =
588 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
590 static struct call_entry content_handler_test1[] = {
591 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
592 { CH_STARTDOCUMENT, 0, 0, S_OK },
593 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
594 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
595 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
596 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
597 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
598 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
599 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
600 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
601 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
602 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
603 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
604 { CH_ENDDOCUMENT, 0, 0, S_OK},
605 { CH_ENDTEST }
608 /* applies to versions 4 and 6 */
609 static struct call_entry content_handler_test1_alternate[] = {
610 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
611 { CH_STARTDOCUMENT, 1, 22, S_OK },
612 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
613 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
614 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
615 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
616 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
617 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
618 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
619 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
620 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
621 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
622 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
623 { CH_ENDDOCUMENT, 6, 0, S_OK },
624 { CH_ENDTEST }
627 static struct call_entry content_handler_test2[] = {
628 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
629 { CH_STARTDOCUMENT, 0, 0, S_OK },
630 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
631 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
632 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
633 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
634 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
635 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
636 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
637 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
638 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
639 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
640 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
641 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
642 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
643 { CH_ENDDOCUMENT, 0, 0, S_OK },
644 { CH_ENDTEST }
647 static struct call_entry content_handler_test2_alternate[] = {
648 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
649 { CH_STARTDOCUMENT, 1, 21, S_OK },
650 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
651 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
652 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
653 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
654 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
655 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
656 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
657 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
658 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
659 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
660 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
661 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
662 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
663 { CH_ENDDOCUMENT, 6, 0, S_OK },
664 { CH_ENDTEST }
667 static struct call_entry content_handler_testerror[] = {
668 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
669 { EH_FATALERROR, 0, 0, E_FAIL },
670 { CH_ENDTEST }
673 static struct call_entry content_handler_testerror_alternate[] = {
674 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
675 { EH_FATALERROR, 1, 0, E_FAIL },
676 { CH_ENDTEST }
679 static struct call_entry content_handler_test_callback_rets[] = {
680 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
681 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
682 { EH_FATALERROR, 0, 0, S_FALSE },
683 { CH_ENDTEST }
686 static struct call_entry content_handler_test_callback_rets_alt[] = {
687 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
688 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
689 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
690 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
691 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
692 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
693 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
694 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
695 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
696 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
697 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
698 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
699 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
700 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
701 { CH_ENDTEST }
704 static struct attribute_entry ch_attributes1[] = {
705 { "", "", "xmlns:test", "prefix_test" },
706 { "", "", "xmlns", "prefix" },
707 { "prefix_test", "arg1", "test:arg1", "arg1" },
708 { "", "arg2", "arg2", "arg2" },
709 { "prefix_test", "ar3", "test:ar3", "arg3" },
710 { NULL }
713 static struct attribute_entry ch_attributes2[] = {
714 { "", "", "xmlns:p", "test" },
715 { NULL }
718 static struct call_entry content_handler_test_attributes[] = {
719 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
720 { CH_STARTDOCUMENT, 0, 0, S_OK },
721 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
722 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
723 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
724 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
725 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
726 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
727 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
728 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
729 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
730 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
731 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
732 { CH_ENDDOCUMENT, 0, 0 },
733 { CH_ENDTEST }
736 static struct attribute_entry ch_attributes_alt_4[] = {
737 { "prefix_test", "arg1", "test:arg1", "arg1" },
738 { "", "arg2", "arg2", "arg2" },
739 { "prefix_test", "ar3", "test:ar3", "arg3" },
740 { "", "", "xmlns:test", "prefix_test" },
741 { "", "", "xmlns", "prefix" },
742 { NULL }
745 static struct call_entry content_handler_test_attributes_alternate_4[] = {
746 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
747 { CH_STARTDOCUMENT, 1, 22, S_OK },
748 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
749 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
750 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
751 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
752 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
753 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
754 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
755 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
756 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
757 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
758 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
759 { CH_ENDDOCUMENT, 4, 0, S_OK },
760 { CH_ENDTEST }
763 /* 'namespace' feature switched off */
764 static struct attribute_entry ch_attributes_alt_no_ns[] = {
765 { "", "", "xmlns:test", "prefix_test" },
766 { "", "", "xmlns", "prefix" },
767 { "", "", "test:arg1", "arg1" },
768 { "", "", "arg2", "arg2" },
769 { "", "", "test:ar3", "arg3" },
770 { NULL }
773 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
774 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
775 { CH_STARTDOCUMENT, 1, 22, S_OK },
776 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
777 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
778 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
779 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
780 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
781 { CH_ENDDOCUMENT, 4, 0, S_OK },
782 { CH_ENDTEST }
785 static struct attribute_entry ch_attributes_alt_6[] = {
786 { "prefix_test", "arg1", "test:arg1", "arg1" },
787 { "", "arg2", "arg2", "arg2" },
788 { "prefix_test", "ar3", "test:ar3", "arg3" },
789 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
790 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
791 { NULL }
794 static struct attribute_entry ch_attributes2_6[] = {
795 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
796 { NULL }
799 static struct call_entry content_handler_test_attributes_alternate_6[] = {
800 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
801 { CH_STARTDOCUMENT, 1, 22, S_OK },
802 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
803 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
804 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
805 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
806 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
807 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
808 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
809 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
810 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
811 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
812 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
813 { CH_ENDDOCUMENT, 4, 0, S_OK },
814 { CH_ENDTEST }
817 /* 'namespaces' is on, 'namespace-prefixes' if off */
818 static struct attribute_entry ch_attributes_no_prefix[] = {
819 { "prefix_test", "arg1", "test:arg1", "arg1" },
820 { "", "arg2", "arg2", "arg2" },
821 { "prefix_test", "ar3", "test:ar3", "arg3" },
822 { NULL }
825 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
826 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
827 { CH_STARTDOCUMENT, 1, 22, S_OK },
828 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
829 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
830 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
831 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
832 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
833 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
834 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
835 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
836 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
837 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
838 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
839 { CH_ENDDOCUMENT, 4, 0, S_OK },
840 { CH_ENDTEST }
843 static struct call_entry content_handler_test_attributes_no_prefix[] = {
844 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
845 { CH_STARTDOCUMENT, 0, 0, S_OK },
846 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
847 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
848 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
849 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
850 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
851 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
852 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
853 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
854 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
855 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
856 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
857 { CH_ENDDOCUMENT, 0, 0 },
858 { CH_ENDTEST }
861 static struct attribute_entry xmlspace_attrs[] = {
862 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
863 { NULL }
866 static struct call_entry xmlspaceattr_test[] = {
867 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
868 { CH_STARTDOCUMENT, 0, 0, S_OK },
869 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
870 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
871 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
872 { CH_ENDDOCUMENT, 0, 0, S_OK },
873 { CH_ENDTEST }
876 static struct call_entry xmlspaceattr_test_alternate[] = {
877 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
878 { CH_STARTDOCUMENT, 1, 39, S_OK },
879 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
880 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
881 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
882 { CH_ENDDOCUMENT, 1, 83, S_OK },
883 { CH_ENDTEST }
886 /* attribute value normalization test */
887 static const char attribute_normalize[] =
888 "<?xml version=\"1.0\" ?>\n"
889 "<a attr1=\" \r \n \tattr_value &#65; \t \r \n\r\n \n\"/>\n";
891 static struct attribute_entry attribute_norm_attrs[] = {
892 { "", "attr1", "attr1", " attr_value A " },
893 { NULL }
896 static struct call_entry attribute_norm[] = {
897 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
898 { CH_STARTDOCUMENT, 0, 0, S_OK },
899 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
900 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
901 { CH_ENDDOCUMENT, 0, 0, S_OK },
902 { CH_ENDTEST }
905 static struct call_entry attribute_norm_alt[] = {
906 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
907 { CH_STARTDOCUMENT, 1, 22, S_OK },
908 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
909 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
910 { CH_ENDDOCUMENT, 9, 0, S_OK },
911 { CH_ENDTEST }
914 static struct call_entry cdata_test[] = {
915 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
916 { CH_STARTDOCUMENT, 0, 0, S_OK },
917 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
918 { LH_STARTCDATA, 1, 35, S_OK },
919 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
920 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
921 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
922 { LH_ENDCDATA, 1, 49, S_OK },
923 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
924 { CH_ENDDOCUMENT, 0, 0, S_OK },
925 { CH_ENDTEST }
928 static struct call_entry cdata_test2[] = {
929 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
930 { CH_STARTDOCUMENT, 0, 0, S_OK },
931 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
932 { LH_STARTCDATA, 1, 35, S_OK },
933 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
934 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
935 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
936 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
937 { LH_ENDCDATA, 1, 52, S_OK },
938 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
939 { CH_ENDDOCUMENT, 0, 0, S_OK },
940 { CH_ENDTEST }
943 static struct call_entry cdata_test3[] = {
944 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
945 { CH_STARTDOCUMENT, 0, 0, S_OK },
946 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
947 { LH_STARTCDATA, 1, 35, S_OK },
948 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
949 { LH_ENDCDATA, 1, 35, S_OK },
950 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
951 { CH_ENDDOCUMENT, 0, 0, S_OK },
952 { CH_ENDTEST }
955 /* this is what MSXML6 does */
956 static struct call_entry cdata_test_alt[] = {
957 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
958 { CH_STARTDOCUMENT, 1, 22, S_OK },
959 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
960 { LH_STARTCDATA, 1, 34, S_OK },
961 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
962 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
963 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
964 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
965 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
966 { LH_ENDCDATA, 6, 3, S_OK },
967 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
968 { CH_ENDDOCUMENT, 6, 7, S_OK },
969 { CH_ENDTEST }
972 static struct call_entry cdata_test2_alt[] = {
973 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
974 { CH_STARTDOCUMENT, 1, 22, S_OK },
975 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
976 { LH_STARTCDATA, 1, 34, S_OK },
977 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
978 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
979 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
980 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
981 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
982 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
983 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
984 { LH_ENDCDATA, 8, 3, S_OK },
985 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
986 { CH_ENDDOCUMENT, 8, 7, S_OK },
987 { CH_ENDTEST }
990 static struct call_entry cdata_test3_alt[] = {
991 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
992 { CH_STARTDOCUMENT, 1, 22, S_OK },
993 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
994 { LH_STARTCDATA, 1, 34, S_OK },
995 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
996 { LH_ENDCDATA, 1, 51, S_OK },
997 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
998 { CH_ENDDOCUMENT, 1, 55, S_OK },
999 { CH_ENDTEST }
1002 static const char xmlspace_attr[] =
1003 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1004 "<a xml:space=\"preserve\"> Some text data </a>";
1006 static struct call_entry *expectCall;
1007 static ISAXLocator *locator;
1008 static ISAXXMLReader *g_reader;
1009 int msxml_version;
1011 static void set_expected_seq(struct call_entry *expected)
1013 expectCall = expected;
1016 /* to be called once on each tested callback return */
1017 static HRESULT get_expected_ret(void)
1019 HRESULT hr = expectCall->ret;
1020 if (expectCall->id != CH_ENDTEST) expectCall++;
1021 return hr;
1024 static HRESULT WINAPI contentHandler_QueryInterface(
1025 ISAXContentHandler* iface,
1026 REFIID riid,
1027 void **ppvObject)
1029 *ppvObject = NULL;
1031 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1033 *ppvObject = iface;
1035 else
1037 return E_NOINTERFACE;
1040 return S_OK;
1043 static ULONG WINAPI contentHandler_AddRef(
1044 ISAXContentHandler* iface)
1046 return 2;
1049 static ULONG WINAPI contentHandler_Release(
1050 ISAXContentHandler* iface)
1052 return 1;
1055 static HRESULT WINAPI contentHandler_putDocumentLocator(
1056 ISAXContentHandler* iface,
1057 ISAXLocator *pLocator)
1059 struct call_entry call;
1060 HRESULT hr;
1062 locator = pLocator;
1064 init_call_entry(locator, &call);
1065 call.id = CH_PUTDOCUMENTLOCATOR;
1066 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1068 if (msxml_version >= 6) {
1069 ISAXAttributes *attr, *attr1;
1070 IMXAttributes *mxattr;
1072 EXPECT_REF(pLocator, 1);
1073 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1074 EXPECT_HR(hr, S_OK);
1075 EXPECT_REF(pLocator, 2);
1076 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1077 EXPECT_HR(hr, S_OK);
1078 EXPECT_REF(pLocator, 3);
1079 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1081 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1082 EXPECT_HR(hr, E_NOINTERFACE);
1084 ISAXAttributes_Release(attr);
1085 ISAXAttributes_Release(attr1);
1088 return get_expected_ret();
1091 static ISAXAttributes *test_attr_ptr;
1092 static HRESULT WINAPI contentHandler_startDocument(
1093 ISAXContentHandler* iface)
1095 struct call_entry call;
1097 init_call_entry(locator, &call);
1098 call.id = CH_STARTDOCUMENT;
1099 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1101 test_attr_ptr = NULL;
1103 return get_expected_ret();
1106 static HRESULT WINAPI contentHandler_endDocument(
1107 ISAXContentHandler* iface)
1109 struct call_entry call;
1111 init_call_entry(locator, &call);
1112 call.id = CH_ENDDOCUMENT;
1113 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1115 return get_expected_ret();
1118 static HRESULT WINAPI contentHandler_startPrefixMapping(
1119 ISAXContentHandler* iface,
1120 const WCHAR *prefix, int prefix_len,
1121 const WCHAR *uri, int uri_len)
1123 struct call_entry call;
1125 init_call_entry(locator, &call);
1126 call.id = CH_STARTPREFIXMAPPING;
1127 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1128 call.arg2W = SysAllocStringLen(uri, uri_len);
1129 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1131 return get_expected_ret();
1134 static HRESULT WINAPI contentHandler_endPrefixMapping(
1135 ISAXContentHandler* iface,
1136 const WCHAR *prefix, int len)
1138 struct call_entry call;
1140 init_call_entry(locator, &call);
1141 call.id = CH_ENDPREFIXMAPPING;
1142 call.arg1W = SysAllocStringLen(prefix, len);
1143 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1145 return get_expected_ret();
1148 static HRESULT WINAPI contentHandler_startElement(
1149 ISAXContentHandler* iface,
1150 const WCHAR *uri, int uri_len,
1151 const WCHAR *localname, int local_len,
1152 const WCHAR *qname, int qname_len,
1153 ISAXAttributes *saxattr)
1155 struct call_entry call;
1156 IMXAttributes *mxattr;
1157 HRESULT hr;
1158 int len;
1160 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1161 EXPECT_HR(hr, E_NOINTERFACE);
1163 init_call_entry(locator, &call);
1164 call.id = CH_STARTELEMENT;
1165 call.arg1W = SysAllocStringLen(uri, uri_len);
1166 call.arg2W = SysAllocStringLen(localname, local_len);
1167 call.arg3W = SysAllocStringLen(qname, qname_len);
1169 if(!test_attr_ptr)
1170 test_attr_ptr = saxattr;
1171 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1173 /* store actual attributes */
1174 len = 0;
1175 hr = ISAXAttributes_getLength(saxattr, &len);
1176 EXPECT_HR(hr, S_OK);
1178 if (len)
1180 VARIANT_BOOL v;
1181 int i;
1183 struct attribute_entry *attr;
1184 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1186 v = VARIANT_TRUE;
1187 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1188 EXPECT_HR(hr, S_OK);
1190 for (i = 0; i < len; i++)
1192 const WCHAR *value;
1193 int value_len;
1195 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1196 &localname, &local_len, &qname, &qname_len);
1197 EXPECT_HR(hr, S_OK);
1199 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1200 EXPECT_HR(hr, S_OK);
1202 /* if 'namespaces' switched off uri and local name contains garbage */
1203 if (v == VARIANT_FALSE && msxml_version > 0)
1205 attr[i].uriW = SysAllocStringLen(NULL, 0);
1206 attr[i].localW = SysAllocStringLen(NULL, 0);
1208 else
1210 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1211 attr[i].localW = SysAllocStringLen(localname, local_len);
1214 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1215 attr[i].valueW = SysAllocStringLen(value, value_len);
1218 call.attributes = attr;
1219 call.attr_count = len;
1222 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1224 return get_expected_ret();
1227 static HRESULT WINAPI contentHandler_endElement(
1228 ISAXContentHandler* iface,
1229 const WCHAR *uri, int uri_len,
1230 const WCHAR *localname, int local_len,
1231 const WCHAR *qname, int qname_len)
1233 struct call_entry call;
1235 init_call_entry(locator, &call);
1236 call.id = CH_ENDELEMENT;
1237 call.arg1W = SysAllocStringLen(uri, uri_len);
1238 call.arg2W = SysAllocStringLen(localname, local_len);
1239 call.arg3W = SysAllocStringLen(qname, qname_len);
1240 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1242 return get_expected_ret();
1245 static HRESULT WINAPI contentHandler_characters(
1246 ISAXContentHandler* iface,
1247 const WCHAR *chars,
1248 int len)
1250 struct call_entry call;
1252 init_call_entry(locator, &call);
1253 call.id = CH_CHARACTERS;
1254 call.arg1W = SysAllocStringLen(chars, len);
1255 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1257 return get_expected_ret();
1260 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1261 ISAXContentHandler* iface,
1262 const WCHAR *chars, int len)
1264 struct call_entry call;
1266 init_call_entry(locator, &call);
1267 call.id = CH_IGNORABLEWHITESPACE;
1268 call.arg1W = SysAllocStringLen(chars, len);
1269 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1271 return get_expected_ret();
1274 static HRESULT WINAPI contentHandler_processingInstruction(
1275 ISAXContentHandler* iface,
1276 const WCHAR *target, int target_len,
1277 const WCHAR *data, int data_len)
1279 struct call_entry call;
1281 init_call_entry(locator, &call);
1282 call.id = CH_PROCESSINGINSTRUCTION;
1283 call.arg1W = SysAllocStringLen(target, target_len);
1284 call.arg2W = SysAllocStringLen(data, data_len);
1285 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1287 return get_expected_ret();
1290 static HRESULT WINAPI contentHandler_skippedEntity(
1291 ISAXContentHandler* iface,
1292 const WCHAR *name, int len)
1294 struct call_entry call;
1296 init_call_entry(locator, &call);
1297 call.id = CH_SKIPPEDENTITY;
1298 call.arg1W = SysAllocStringLen(name, len);
1299 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1301 return get_expected_ret();
1304 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1306 contentHandler_QueryInterface,
1307 contentHandler_AddRef,
1308 contentHandler_Release,
1309 contentHandler_putDocumentLocator,
1310 contentHandler_startDocument,
1311 contentHandler_endDocument,
1312 contentHandler_startPrefixMapping,
1313 contentHandler_endPrefixMapping,
1314 contentHandler_startElement,
1315 contentHandler_endElement,
1316 contentHandler_characters,
1317 contentHandler_ignorableWhitespace,
1318 contentHandler_processingInstruction,
1319 contentHandler_skippedEntity
1322 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1324 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1325 ISAXErrorHandler* iface,
1326 REFIID riid,
1327 void **ppvObject)
1329 *ppvObject = NULL;
1331 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1333 *ppvObject = iface;
1335 else
1337 return E_NOINTERFACE;
1340 return S_OK;
1343 static ULONG WINAPI isaxerrorHandler_AddRef(
1344 ISAXErrorHandler* iface)
1346 return 2;
1349 static ULONG WINAPI isaxerrorHandler_Release(
1350 ISAXErrorHandler* iface)
1352 return 1;
1355 static HRESULT WINAPI isaxerrorHandler_error(
1356 ISAXErrorHandler* iface,
1357 ISAXLocator *pLocator,
1358 const WCHAR *pErrorMessage,
1359 HRESULT hrErrorCode)
1361 ok(0, "unexpected call\n");
1362 return S_OK;
1365 static HRESULT WINAPI isaxerrorHandler_fatalError(
1366 ISAXErrorHandler* iface,
1367 ISAXLocator *pLocator,
1368 const WCHAR *message,
1369 HRESULT hr)
1371 struct call_entry call;
1373 init_call_entry(locator, &call);
1374 call.id = EH_FATALERROR;
1375 call.ret = hr;
1377 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1379 get_expected_ret();
1380 return S_OK;
1383 static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
1384 ISAXErrorHandler* iface,
1385 ISAXLocator *pLocator,
1386 const WCHAR *pErrorMessage,
1387 HRESULT hrErrorCode)
1389 ok(0, "unexpected call\n");
1390 return S_OK;
1393 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1395 isaxerrorHandler_QueryInterface,
1396 isaxerrorHandler_AddRef,
1397 isaxerrorHandler_Release,
1398 isaxerrorHandler_error,
1399 isaxerrorHandler_fatalError,
1400 isaxerrorHandler_ignorableWarning
1403 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1405 static HRESULT WINAPI isaxattributes_QueryInterface(
1406 ISAXAttributes* iface,
1407 REFIID riid,
1408 void **ppvObject)
1410 *ppvObject = NULL;
1412 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1414 *ppvObject = iface;
1416 else
1418 return E_NOINTERFACE;
1421 return S_OK;
1424 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1426 return 2;
1429 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1431 return 1;
1434 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1436 *length = 3;
1437 return S_OK;
1440 static HRESULT WINAPI isaxattributes_getURI(
1441 ISAXAttributes* iface,
1442 int nIndex,
1443 const WCHAR **pUrl,
1444 int *pUriSize)
1446 ok(0, "unexpected call\n");
1447 return E_NOTIMPL;
1450 static HRESULT WINAPI isaxattributes_getLocalName(
1451 ISAXAttributes* iface,
1452 int nIndex,
1453 const WCHAR **pLocalName,
1454 int *pLocalNameLength)
1456 ok(0, "unexpected call\n");
1457 return E_NOTIMPL;
1460 static HRESULT WINAPI isaxattributes_getQName(
1461 ISAXAttributes* iface,
1462 int index,
1463 const WCHAR **QName,
1464 int *QNameLength)
1466 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1467 {'a','t','t','r','2','j','u','n','k',0},
1468 {'a','t','t','r','3',0}};
1469 static const int attrqnamelen[] = {7, 5, 5};
1471 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1473 *QName = attrqnamesW[index];
1474 *QNameLength = attrqnamelen[index];
1476 return S_OK;
1479 static HRESULT WINAPI isaxattributes_getName(
1480 ISAXAttributes* iface,
1481 int nIndex,
1482 const WCHAR **pUri,
1483 int * pUriLength,
1484 const WCHAR ** pLocalName,
1485 int * pLocalNameSize,
1486 const WCHAR ** pQName,
1487 int * pQNameLength)
1489 ok(0, "unexpected call\n");
1490 return E_NOTIMPL;
1493 static HRESULT WINAPI isaxattributes_getIndexFromName(
1494 ISAXAttributes* iface,
1495 const WCHAR * pUri,
1496 int cUriLength,
1497 const WCHAR * pLocalName,
1498 int cocalNameLength,
1499 int * index)
1501 ok(0, "unexpected call\n");
1502 return E_NOTIMPL;
1505 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1506 ISAXAttributes* iface,
1507 const WCHAR * pQName,
1508 int nQNameLength,
1509 int * index)
1511 ok(0, "unexpected call\n");
1512 return E_NOTIMPL;
1515 static HRESULT WINAPI isaxattributes_getType(
1516 ISAXAttributes* iface,
1517 int nIndex,
1518 const WCHAR ** pType,
1519 int * pTypeLength)
1521 ok(0, "unexpected call\n");
1522 return E_NOTIMPL;
1525 static HRESULT WINAPI isaxattributes_getTypeFromName(
1526 ISAXAttributes* iface,
1527 const WCHAR * pUri,
1528 int nUri,
1529 const WCHAR * pLocalName,
1530 int nLocalName,
1531 const WCHAR ** pType,
1532 int * nType)
1534 ok(0, "unexpected call\n");
1535 return E_NOTIMPL;
1538 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1539 ISAXAttributes* iface,
1540 const WCHAR * pQName,
1541 int nQName,
1542 const WCHAR ** pType,
1543 int * nType)
1545 ok(0, "unexpected call\n");
1546 return E_NOTIMPL;
1549 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1550 const WCHAR **value, int *nValue)
1552 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1553 {'a','2','j','u','n','k',0},
1554 {'<','&','"','>',0}};
1555 static const int attrvalueslen[] = {2, 2, 4};
1557 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1559 *value = attrvaluesW[index];
1560 *nValue = attrvalueslen[index];
1562 return S_OK;
1565 static HRESULT WINAPI isaxattributes_getValueFromName(
1566 ISAXAttributes* iface,
1567 const WCHAR * pUri,
1568 int nUri,
1569 const WCHAR * pLocalName,
1570 int nLocalName,
1571 const WCHAR ** pValue,
1572 int * nValue)
1574 ok(0, "unexpected call\n");
1575 return E_NOTIMPL;
1578 static HRESULT WINAPI isaxattributes_getValueFromQName(
1579 ISAXAttributes* iface,
1580 const WCHAR * pQName,
1581 int nQName,
1582 const WCHAR ** pValue,
1583 int * nValue)
1585 ok(0, "unexpected call\n");
1586 return E_NOTIMPL;
1589 static const ISAXAttributesVtbl SAXAttributesVtbl =
1591 isaxattributes_QueryInterface,
1592 isaxattributes_AddRef,
1593 isaxattributes_Release,
1594 isaxattributes_getLength,
1595 isaxattributes_getURI,
1596 isaxattributes_getLocalName,
1597 isaxattributes_getQName,
1598 isaxattributes_getName,
1599 isaxattributes_getIndexFromName,
1600 isaxattributes_getIndexFromQName,
1601 isaxattributes_getType,
1602 isaxattributes_getTypeFromName,
1603 isaxattributes_getTypeFromQName,
1604 isaxattributes_getValue,
1605 isaxattributes_getValueFromName,
1606 isaxattributes_getValueFromQName
1609 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1611 struct saxlexicalhandler
1613 ISAXLexicalHandler ISAXLexicalHandler_iface;
1614 LONG ref;
1616 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1619 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1621 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
1624 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1626 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1628 *out = NULL;
1630 if (IsEqualGUID(riid, &IID_IUnknown))
1632 *out = iface;
1633 ok(0, "got unexpected IID_IUnknown query\n");
1635 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1637 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1638 *out = iface;
1641 if (*out)
1642 ISAXLexicalHandler_AddRef(iface);
1643 else
1644 return E_NOINTERFACE;
1646 return S_OK;
1649 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1651 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1652 return InterlockedIncrement(&handler->ref);
1655 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1657 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
1658 return InterlockedDecrement(&handler->ref);
1661 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1662 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1663 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1665 ok(0, "call not expected\n");
1666 return E_NOTIMPL;
1669 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1671 ok(0, "call not expected\n");
1672 return E_NOTIMPL;
1675 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1676 const WCHAR * pName, int nName)
1678 ok(0, "call not expected\n");
1679 return E_NOTIMPL;
1682 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1683 const WCHAR * pName, int nName)
1685 ok(0, "call not expected\n");
1686 return E_NOTIMPL;
1689 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1691 struct call_entry call;
1693 init_call_entry(locator, &call);
1694 call.id = LH_STARTCDATA;
1695 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1697 return get_expected_ret();
1700 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1702 struct call_entry call;
1704 init_call_entry(locator, &call);
1705 call.id = LH_ENDCDATA;
1706 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1708 return get_expected_ret();
1711 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1712 const WCHAR * pChars, int nChars)
1714 ok(0, "call not expected\n");
1715 return E_NOTIMPL;
1718 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1720 isaxlexical_QueryInterface,
1721 isaxlexical_AddRef,
1722 isaxlexical_Release,
1723 isaxlexical_startDTD,
1724 isaxlexical_endDTD,
1725 isaxlexical_startEntity,
1726 isaxlexical_endEntity,
1727 isaxlexical_startCDATA,
1728 isaxlexical_endCDATA,
1729 isaxlexical_comment
1732 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
1734 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1735 handler->ref = 1;
1736 handler->qi_hr = hr;
1739 struct saxdeclhandler
1741 ISAXDeclHandler ISAXDeclHandler_iface;
1742 LONG ref;
1744 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1747 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1749 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
1752 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1754 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1756 *out = NULL;
1758 if (IsEqualGUID(riid, &IID_IUnknown))
1760 *out = iface;
1761 ok(0, "got unexpected IID_IUnknown query\n");
1763 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1765 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1766 *out = iface;
1769 if (*out)
1770 ISAXDeclHandler_AddRef(iface);
1771 else
1772 return E_NOINTERFACE;
1774 return S_OK;
1777 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1779 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1780 return InterlockedIncrement(&handler->ref);
1783 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1785 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
1786 return InterlockedDecrement(&handler->ref);
1789 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1790 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1792 ok(0, "call not expected\n");
1793 return E_NOTIMPL;
1796 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1797 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1798 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1799 int nValueDefault, const WCHAR * pValue, int nValue)
1801 ok(0, "call not expected\n");
1802 return E_NOTIMPL;
1805 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1806 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1808 ok(0, "call not expected\n");
1809 return E_NOTIMPL;
1812 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1813 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1814 const WCHAR * pSystemId, int nSystemId)
1816 ok(0, "call not expected\n");
1817 return E_NOTIMPL;
1820 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1822 isaxdecl_QueryInterface,
1823 isaxdecl_AddRef,
1824 isaxdecl_Release,
1825 isaxdecl_elementDecl,
1826 isaxdecl_attributeDecl,
1827 isaxdecl_internalEntityDecl,
1828 isaxdecl_externalEntityDecl
1831 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
1833 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1834 handler->ref = 1;
1835 handler->qi_hr = hr;
1838 typedef struct mxwriter_write_test_t {
1839 BOOL last;
1840 const BYTE *data;
1841 DWORD cb;
1842 BOOL null_written;
1843 BOOL fail_write;
1844 } mxwriter_write_test;
1846 typedef struct mxwriter_stream_test_t {
1847 VARIANT_BOOL bom;
1848 const char *encoding;
1849 mxwriter_write_test expected_writes[4];
1850 } mxwriter_stream_test;
1852 static const mxwriter_write_test *current_write_test;
1853 static DWORD current_stream_test_index;
1855 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1857 *ppvObject = NULL;
1859 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1860 *ppvObject = iface;
1861 else
1862 return E_NOINTERFACE;
1864 return S_OK;
1867 static ULONG WINAPI istream_AddRef(IStream *iface)
1869 return 2;
1872 static ULONG WINAPI istream_Release(IStream *iface)
1874 return 1;
1877 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1879 ok(0, "unexpected call\n");
1880 return E_NOTIMPL;
1883 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1885 BOOL fail = FALSE;
1887 ok(pv != NULL, "pv == NULL\n");
1889 if(current_write_test->last) {
1890 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1891 return E_FAIL;
1894 fail = current_write_test->fail_write;
1896 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1897 current_write_test->cb, cb, current_stream_test_index);
1899 if(!pcbWritten)
1900 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1901 else
1902 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1904 ++current_write_test;
1906 if(pcbWritten)
1907 *pcbWritten = cb;
1909 return fail ? E_FAIL : S_OK;
1912 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1913 ULARGE_INTEGER *plibNewPosition)
1915 ok(0, "unexpected call\n");
1916 return E_NOTIMPL;
1919 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1921 ok(0, "unexpected call\n");
1922 return E_NOTIMPL;
1925 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1926 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1928 ok(0, "unexpected call\n");
1929 return E_NOTIMPL;
1932 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1934 ok(0, "unexpected call\n");
1935 return E_NOTIMPL;
1938 static HRESULT WINAPI istream_Revert(IStream *iface)
1940 ok(0, "unexpected call\n");
1941 return E_NOTIMPL;
1944 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1945 ULARGE_INTEGER cb, DWORD dwLockType)
1947 ok(0, "unexpected call\n");
1948 return E_NOTIMPL;
1951 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1952 ULARGE_INTEGER cb, DWORD dwLockType)
1954 ok(0, "unexpected call\n");
1955 return E_NOTIMPL;
1958 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1960 ok(0, "unexpected call\n");
1961 return E_NOTIMPL;
1964 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1966 ok(0, "unexpected call\n");
1967 return E_NOTIMPL;
1970 static const IStreamVtbl StreamVtbl = {
1971 istream_QueryInterface,
1972 istream_AddRef,
1973 istream_Release,
1974 istream_Read,
1975 istream_Write,
1976 istream_Seek,
1977 istream_SetSize,
1978 istream_CopyTo,
1979 istream_Commit,
1980 istream_Revert,
1981 istream_LockRegion,
1982 istream_UnlockRegion,
1983 istream_Stat,
1984 istream_Clone
1987 static IStream mxstream = { &StreamVtbl };
1989 static struct msxmlsupported_data_t reader_support_data[] =
1991 { &CLSID_SAXXMLReader, "SAXReader" },
1992 { &CLSID_SAXXMLReader30, "SAXReader30" },
1993 { &CLSID_SAXXMLReader40, "SAXReader40" },
1994 { &CLSID_SAXXMLReader60, "SAXReader60" },
1995 { NULL }
1998 static struct saxlexicalhandler lexicalhandler;
1999 static struct saxdeclhandler declhandler;
2001 static IStream *create_test_stream(const char *data, int len)
2003 ULARGE_INTEGER size;
2004 LARGE_INTEGER pos;
2005 IStream *stream;
2006 ULONG written;
2008 if (len == -1) len = strlen(data);
2009 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2010 size.QuadPart = len;
2011 IStream_SetSize(stream, size);
2012 IStream_Write(stream, data, len, &written);
2013 pos.QuadPart = 0;
2014 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2016 return stream;
2019 static void test_saxreader(void)
2021 const struct msxmlsupported_data_t *table = reader_support_data;
2022 HRESULT hr;
2023 ISAXXMLReader *reader = NULL;
2024 VARIANT var;
2025 ISAXContentHandler *content;
2026 ISAXErrorHandler *lpErrorHandler;
2027 SAFEARRAY *sa;
2028 SAFEARRAYBOUND SADim[1];
2029 char *ptr = NULL;
2030 IStream *stream;
2031 ULONG written;
2032 HANDLE file;
2033 static const CHAR testXmlA[] = "test.xml";
2034 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2035 IXMLDOMDocument *doc;
2036 VARIANT_BOOL v;
2038 while (table->clsid)
2040 struct call_entry *test_seq;
2041 ISAXEntityResolver *resolver;
2042 BSTR str;
2044 if (!is_clsid_supported(table->clsid, reader_support_data))
2046 table++;
2047 continue;
2050 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2051 EXPECT_HR(hr, S_OK);
2052 g_reader = reader;
2054 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2055 msxml_version = 4;
2056 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2057 msxml_version = 6;
2058 else
2059 msxml_version = 0;
2061 /* crashes on old versions */
2062 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2063 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2065 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2066 EXPECT_HR(hr, E_POINTER);
2068 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2069 EXPECT_HR(hr, E_POINTER);
2072 hr = ISAXXMLReader_getContentHandler(reader, &content);
2073 EXPECT_HR(hr, S_OK);
2074 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2076 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2077 EXPECT_HR(hr, S_OK);
2078 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2080 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2081 EXPECT_HR(hr, S_OK);
2083 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2084 EXPECT_HR(hr, S_OK);
2086 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2087 EXPECT_HR(hr, S_OK);
2089 hr = ISAXXMLReader_getContentHandler(reader, &content);
2090 EXPECT_HR(hr, S_OK);
2091 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2093 V_VT(&var) = VT_BSTR;
2094 V_BSTR(&var) = SysAllocString(szSimpleXML);
2096 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2097 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2098 test_seq = content_handler_test1_alternate;
2099 else
2100 test_seq = content_handler_test1;
2101 set_expected_seq(test_seq);
2102 hr = ISAXXMLReader_parse(reader, var);
2103 EXPECT_HR(hr, S_OK);
2104 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2106 VariantClear(&var);
2108 SADim[0].lLbound = 0;
2109 SADim[0].cElements = sizeof(testXML)-1;
2110 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2111 SafeArrayAccessData(sa, (void**)&ptr);
2112 memcpy(ptr, testXML, sizeof(testXML)-1);
2113 SafeArrayUnaccessData(sa);
2114 V_VT(&var) = VT_ARRAY|VT_UI1;
2115 V_ARRAY(&var) = sa;
2117 set_expected_seq(test_seq);
2118 hr = ISAXXMLReader_parse(reader, var);
2119 EXPECT_HR(hr, S_OK);
2120 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2122 SafeArrayDestroy(sa);
2124 stream = create_test_stream(testXML, -1);
2125 V_VT(&var) = VT_UNKNOWN;
2126 V_UNKNOWN(&var) = (IUnknown*)stream;
2128 set_expected_seq(test_seq);
2129 hr = ISAXXMLReader_parse(reader, var);
2130 EXPECT_HR(hr, S_OK);
2131 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2133 IStream_Release(stream);
2135 stream = create_test_stream(test_attributes, -1);
2136 V_VT(&var) = VT_UNKNOWN;
2137 V_UNKNOWN(&var) = (IUnknown*)stream;
2139 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2140 test_seq = content_handler_test_attributes_alternate_4;
2141 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2142 test_seq = content_handler_test_attributes_alternate_6;
2143 else
2144 test_seq = content_handler_test_attributes;
2146 set_expected_seq(test_seq);
2147 hr = ISAXXMLReader_parse(reader, var);
2148 EXPECT_HR(hr, S_OK);
2150 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2151 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2152 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2153 else
2154 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2156 IStream_Release(stream);
2158 V_VT(&var) = VT_BSTR;
2159 V_BSTR(&var) = SysAllocString(carriage_ret_test);
2161 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2162 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2163 test_seq = content_handler_test2_alternate;
2164 else
2165 test_seq = content_handler_test2;
2167 set_expected_seq(test_seq);
2168 hr = ISAXXMLReader_parse(reader, var);
2169 EXPECT_HR(hr, S_OK);
2170 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2172 VariantClear(&var);
2174 /* from file url */
2175 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2176 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2177 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2178 CloseHandle(file);
2180 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2181 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2182 test_seq = content_handler_test1_alternate;
2183 else
2184 test_seq = content_handler_test1;
2185 set_expected_seq(test_seq);
2186 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2187 EXPECT_HR(hr, S_OK);
2188 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2190 /* error handler */
2191 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2192 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2193 test_seq = content_handler_testerror_alternate;
2194 else
2195 test_seq = content_handler_testerror;
2196 set_expected_seq(test_seq);
2197 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2198 EXPECT_HR(hr, E_FAIL);
2199 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2201 /* callback ret values */
2202 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2203 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2205 test_seq = content_handler_test_callback_rets_alt;
2206 set_expected_seq(test_seq);
2207 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2208 EXPECT_HR(hr, S_OK);
2210 else
2212 test_seq = content_handler_test_callback_rets;
2213 set_expected_seq(test_seq);
2214 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2215 EXPECT_HR(hr, S_FALSE);
2217 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2219 DeleteFileA(testXmlA);
2221 /* parse from IXMLDOMDocument */
2222 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2223 &IID_IXMLDOMDocument, (void**)&doc);
2224 EXPECT_HR(hr, S_OK);
2226 str = SysAllocString(szSimpleXML);
2227 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2228 EXPECT_HR(hr, S_OK);
2229 SysFreeString(str);
2231 V_VT(&var) = VT_UNKNOWN;
2232 V_UNKNOWN(&var) = (IUnknown*)doc;
2234 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2235 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2236 test_seq = content_handler_test2_alternate;
2237 else
2238 test_seq = content_handler_test2;
2240 set_expected_seq(test_seq);
2241 hr = ISAXXMLReader_parse(reader, var);
2242 EXPECT_HR(hr, S_OK);
2243 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2244 IXMLDOMDocument_Release(doc);
2246 /* xml:space test */
2247 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2248 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2250 test_seq = xmlspaceattr_test_alternate;
2252 else
2253 test_seq = xmlspaceattr_test;
2255 set_expected_seq(test_seq);
2256 V_VT(&var) = VT_BSTR;
2257 V_BSTR(&var) = _bstr_(xmlspace_attr);
2258 hr = ISAXXMLReader_parse(reader, var);
2259 EXPECT_HR(hr, S_OK);
2261 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2262 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2264 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2266 else
2267 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2269 /* switch off 'namespaces' feature */
2270 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2271 EXPECT_HR(hr, S_OK);
2273 stream = create_test_stream(test_attributes, -1);
2274 V_VT(&var) = VT_UNKNOWN;
2275 V_UNKNOWN(&var) = (IUnknown*)stream;
2277 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2278 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2280 test_seq = content_handler_test_attributes_alt_no_ns;
2282 else
2283 test_seq = content_handler_test_attributes;
2285 set_expected_seq(test_seq);
2286 hr = ISAXXMLReader_parse(reader, var);
2287 EXPECT_HR(hr, S_OK);
2288 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2289 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2290 EXPECT_HR(hr, S_OK);
2292 /* switch off 'namespace-prefixes' feature */
2293 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2294 EXPECT_HR(hr, S_OK);
2296 stream = create_test_stream(test_attributes, -1);
2297 V_VT(&var) = VT_UNKNOWN;
2298 V_UNKNOWN(&var) = (IUnknown*)stream;
2300 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2301 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2303 test_seq = content_handler_test_attributes_alt_no_prefix;
2305 else
2306 test_seq = content_handler_test_attributes_no_prefix;
2308 set_expected_seq(test_seq);
2309 hr = ISAXXMLReader_parse(reader, var);
2310 EXPECT_HR(hr, S_OK);
2311 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2313 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2314 EXPECT_HR(hr, S_OK);
2316 /* attribute normalization */
2317 stream = create_test_stream(attribute_normalize, -1);
2318 V_VT(&var) = VT_UNKNOWN;
2319 V_UNKNOWN(&var) = (IUnknown*)stream;
2321 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2322 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2324 test_seq = attribute_norm_alt;
2326 else
2327 test_seq = attribute_norm;
2329 set_expected_seq(test_seq);
2330 hr = ISAXXMLReader_parse(reader, var);
2331 EXPECT_HR(hr, S_OK);
2332 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2334 resolver = (void*)0xdeadbeef;
2335 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2336 ok(hr == S_OK, "got 0x%08x\n", hr);
2337 ok(resolver == NULL, "got %p\n", resolver);
2339 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2340 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2342 /* CDATA sections */
2343 init_saxlexicalhandler(&lexicalhandler, S_OK);
2345 V_VT(&var) = VT_UNKNOWN;
2346 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2347 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2348 ok(hr == S_OK, "got 0x%08x\n", hr);
2350 stream = create_test_stream(test_cdata_xml, -1);
2351 V_VT(&var) = VT_UNKNOWN;
2352 V_UNKNOWN(&var) = (IUnknown*)stream;
2354 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2355 test_seq = cdata_test_alt;
2356 else
2357 test_seq = cdata_test;
2359 set_expected_seq(test_seq);
2360 hr = ISAXXMLReader_parse(reader, var);
2361 ok(hr == S_OK, "got 0x%08x\n", hr);
2362 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test", TRUE);
2364 /* 2. CDATA sections */
2365 stream = create_test_stream(test2_cdata_xml, -1);
2366 V_VT(&var) = VT_UNKNOWN;
2367 V_UNKNOWN(&var) = (IUnknown*)stream;
2369 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2370 test_seq = cdata_test2_alt;
2371 else
2372 test_seq = cdata_test2;
2374 set_expected_seq(test_seq);
2375 hr = ISAXXMLReader_parse(reader, var);
2376 ok(hr == S_OK, "got 0x%08x\n", hr);
2377 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test 2", TRUE);
2379 IStream_Release(stream);
2381 /* 3. CDATA sections */
2382 stream = create_test_stream(test3_cdata_xml, -1);
2383 V_VT(&var) = VT_UNKNOWN;
2384 V_UNKNOWN(&var) = (IUnknown*)stream;
2386 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2387 test_seq = cdata_test3_alt;
2388 else
2389 test_seq = cdata_test3;
2391 set_expected_seq(test_seq);
2392 hr = ISAXXMLReader_parse(reader, var);
2393 ok(hr == S_OK, "got 0x%08x\n", hr);
2394 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test 3", TRUE);
2396 IStream_Release(stream);
2398 ISAXXMLReader_Release(reader);
2399 table++;
2402 free_bstrs();
2405 struct saxreader_props_test_t
2407 const char *prop_name;
2408 IUnknown *iface;
2411 static const struct saxreader_props_test_t props_test_data[] = {
2412 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2413 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2414 { 0 }
2417 static void test_saxreader_properties(void)
2419 const struct saxreader_props_test_t *ptr = props_test_data;
2420 ISAXXMLReader *reader;
2421 HRESULT hr;
2422 VARIANT v;
2424 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2425 &IID_ISAXXMLReader, (void**)&reader);
2426 EXPECT_HR(hr, S_OK);
2428 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2429 EXPECT_HR(hr, E_POINTER);
2431 while (ptr->prop_name)
2433 LONG ref;
2435 init_saxlexicalhandler(&lexicalhandler, S_OK);
2436 init_saxdeclhandler(&declhandler, S_OK);
2438 V_VT(&v) = VT_EMPTY;
2439 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2440 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2441 EXPECT_HR(hr, S_OK);
2442 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2443 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2445 V_VT(&v) = VT_UNKNOWN;
2446 V_UNKNOWN(&v) = ptr->iface;
2447 ref = get_refcount(ptr->iface);
2448 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2449 EXPECT_HR(hr, S_OK);
2450 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2452 V_VT(&v) = VT_EMPTY;
2453 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2455 ref = get_refcount(ptr->iface);
2456 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2457 EXPECT_HR(hr, S_OK);
2458 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2459 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2460 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2461 VariantClear(&v);
2463 V_VT(&v) = VT_EMPTY;
2464 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2465 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2466 EXPECT_HR(hr, S_OK);
2468 V_VT(&v) = VT_EMPTY;
2469 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2470 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2471 EXPECT_HR(hr, S_OK);
2472 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2473 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2475 V_VT(&v) = VT_UNKNOWN;
2476 V_UNKNOWN(&v) = ptr->iface;
2477 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2478 EXPECT_HR(hr, S_OK);
2480 /* only VT_EMPTY seems to be valid to reset property */
2481 V_VT(&v) = VT_I4;
2482 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2483 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2484 EXPECT_HR(hr, E_INVALIDARG);
2486 V_VT(&v) = VT_EMPTY;
2487 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2488 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2489 EXPECT_HR(hr, S_OK);
2490 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2491 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2492 VariantClear(&v);
2494 V_VT(&v) = VT_UNKNOWN;
2495 V_UNKNOWN(&v) = NULL;
2496 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2497 EXPECT_HR(hr, S_OK);
2499 V_VT(&v) = VT_EMPTY;
2500 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2501 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2502 EXPECT_HR(hr, S_OK);
2503 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2504 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2506 /* block QueryInterface on handler riid */
2507 V_VT(&v) = VT_UNKNOWN;
2508 V_UNKNOWN(&v) = ptr->iface;
2509 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2510 EXPECT_HR(hr, S_OK);
2512 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
2513 init_saxdeclhandler(&declhandler, E_NOINTERFACE);
2515 V_VT(&v) = VT_UNKNOWN;
2516 V_UNKNOWN(&v) = ptr->iface;
2517 EXPECT_REF(ptr->iface, 1);
2518 ref = get_refcount(ptr->iface);
2519 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2520 EXPECT_HR(hr, E_NOINTERFACE);
2521 EXPECT_REF(ptr->iface, 1);
2523 V_VT(&v) = VT_EMPTY;
2524 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2525 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2526 EXPECT_HR(hr, S_OK);
2527 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2528 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2530 ptr++;
2531 free_bstrs();
2534 ISAXXMLReader_Release(reader);
2536 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2537 return;
2539 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2540 &IID_ISAXXMLReader, (void**)&reader);
2541 EXPECT_HR(hr, S_OK);
2543 /* xmldecl-version property */
2544 V_VT(&v) = VT_EMPTY;
2545 V_BSTR(&v) = (void*)0xdeadbeef;
2546 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2547 EXPECT_HR(hr, S_OK);
2548 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2549 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2551 /* stream without declaration */
2552 V_VT(&v) = VT_BSTR;
2553 V_BSTR(&v) = _bstr_("<element></element>");
2554 hr = ISAXXMLReader_parse(reader, v);
2555 EXPECT_HR(hr, S_OK);
2557 V_VT(&v) = VT_EMPTY;
2558 V_BSTR(&v) = (void*)0xdeadbeef;
2559 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2560 EXPECT_HR(hr, S_OK);
2561 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2562 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2564 /* stream with declaration */
2565 V_VT(&v) = VT_BSTR;
2566 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2567 hr = ISAXXMLReader_parse(reader, v);
2568 EXPECT_HR(hr, S_OK);
2570 V_VT(&v) = VT_EMPTY;
2571 V_BSTR(&v) = (void*)0xdeadbeef;
2572 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2573 EXPECT_HR(hr, S_OK);
2574 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2575 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2576 VariantClear(&v);
2578 ISAXXMLReader_Release(reader);
2579 free_bstrs();
2582 struct feature_ns_entry_t {
2583 const GUID *guid;
2584 const char *clsid;
2585 VARIANT_BOOL value;
2586 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2589 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2590 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2591 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2592 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2593 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2594 { 0 }
2597 static const char *feature_names[] = {
2598 "http://xml.org/sax/features/namespaces",
2599 "http://xml.org/sax/features/namespace-prefixes",
2603 static void test_saxreader_features(void)
2605 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2606 ISAXXMLReader *reader;
2608 while (entry->guid)
2610 VARIANT_BOOL value;
2611 const char **name;
2612 HRESULT hr;
2614 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2615 if (hr != S_OK)
2617 win_skip("can't create %s instance\n", entry->clsid);
2618 entry++;
2619 continue;
2622 name = feature_names;
2623 while (*name)
2625 value = 0xc;
2626 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2627 EXPECT_HR(hr, S_OK);
2628 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2630 value = 0xc;
2631 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2632 EXPECT_HR(hr, S_OK);
2634 value = 0xd;
2635 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2636 EXPECT_HR(hr, S_OK);
2637 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2639 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2640 EXPECT_HR(hr, S_OK);
2641 value = 0xd;
2642 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2643 EXPECT_HR(hr, S_OK);
2644 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2646 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2647 EXPECT_HR(hr, S_OK);
2648 value = 0xd;
2649 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2650 EXPECT_HR(hr, S_OK);
2651 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2653 name++;
2656 ISAXXMLReader_Release(reader);
2658 entry++;
2662 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2663 static const CHAR UTF8BOMTest[] =
2664 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2665 "<a></a>\n";
2667 struct enc_test_entry_t {
2668 const GUID *guid;
2669 const char *clsid;
2670 const char *data;
2671 HRESULT hr;
2672 int todo;
2675 static const struct enc_test_entry_t encoding_test_data[] = {
2676 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2677 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2678 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2679 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2680 { 0 }
2683 static void test_saxreader_encoding(void)
2685 const struct enc_test_entry_t *entry = encoding_test_data;
2686 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2687 static const CHAR testXmlA[] = "test.xml";
2689 while (entry->guid)
2691 ISAXXMLReader *reader;
2692 VARIANT input;
2693 DWORD written;
2694 HANDLE file;
2695 HRESULT hr;
2697 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2698 if (hr != S_OK)
2700 win_skip("can't create %s instance\n", entry->clsid);
2701 entry++;
2702 continue;
2705 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2706 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2707 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2708 CloseHandle(file);
2710 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2711 if (entry->todo)
2712 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2713 else
2714 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2716 DeleteFileA(testXmlA);
2718 /* try BSTR input with no BOM or '<?xml' instruction */
2719 V_VT(&input) = VT_BSTR;
2720 V_BSTR(&input) = _bstr_("<element></element>");
2721 hr = ISAXXMLReader_parse(reader, input);
2722 EXPECT_HR(hr, S_OK);
2724 ISAXXMLReader_Release(reader);
2726 free_bstrs();
2727 entry++;
2731 static void test_mxwriter_handlers(void)
2733 ISAXContentHandler *handler;
2734 IMXWriter *writer, *writer2;
2735 ISAXDeclHandler *decl;
2736 ISAXLexicalHandler *lh;
2737 HRESULT hr;
2739 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2740 &IID_IMXWriter, (void**)&writer);
2741 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2743 EXPECT_REF(writer, 1);
2745 /* ISAXContentHandler */
2746 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2747 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2748 EXPECT_REF(writer, 2);
2749 EXPECT_REF(handler, 2);
2751 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2752 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2753 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2754 EXPECT_REF(writer, 3);
2755 EXPECT_REF(writer2, 3);
2756 IMXWriter_Release(writer2);
2757 ISAXContentHandler_Release(handler);
2759 /* ISAXLexicalHandler */
2760 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2761 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2762 EXPECT_REF(writer, 2);
2763 EXPECT_REF(lh, 2);
2765 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2766 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2767 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2768 EXPECT_REF(writer, 3);
2769 EXPECT_REF(writer2, 3);
2770 IMXWriter_Release(writer2);
2771 ISAXLexicalHandler_Release(lh);
2773 /* ISAXDeclHandler */
2774 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2775 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2776 EXPECT_REF(writer, 2);
2777 EXPECT_REF(lh, 2);
2779 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2780 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2781 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2782 EXPECT_REF(writer, 3);
2783 EXPECT_REF(writer2, 3);
2784 IMXWriter_Release(writer2);
2785 ISAXDeclHandler_Release(decl);
2787 IMXWriter_Release(writer);
2791 static struct msxmlsupported_data_t mxwriter_support_data[] =
2793 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2794 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2795 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2796 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2797 { NULL }
2800 static struct msxmlsupported_data_t mxattributes_support_data[] =
2802 { &CLSID_SAXAttributes, "SAXAttributes" },
2803 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2804 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2805 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2806 { NULL }
2809 struct mxwriter_props_t
2811 const GUID *clsid;
2812 VARIANT_BOOL bom;
2813 VARIANT_BOOL disable_escape;
2814 VARIANT_BOOL indent;
2815 VARIANT_BOOL omitdecl;
2816 VARIANT_BOOL standalone;
2817 const char *encoding;
2820 static const struct mxwriter_props_t mxwriter_default_props[] =
2822 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2823 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2824 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2825 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2826 { NULL }
2829 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2831 int i = 0;
2833 while (table->clsid)
2835 IMXWriter *writer;
2836 VARIANT_BOOL b;
2837 BSTR encoding;
2838 HRESULT hr;
2840 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2842 table++;
2843 i++;
2844 continue;
2847 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2848 &IID_IMXWriter, (void**)&writer);
2849 EXPECT_HR(hr, S_OK);
2851 b = !table->bom;
2852 hr = IMXWriter_get_byteOrderMark(writer, &b);
2853 EXPECT_HR(hr, S_OK);
2854 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2856 b = !table->disable_escape;
2857 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2858 EXPECT_HR(hr, S_OK);
2859 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2860 table->disable_escape);
2862 b = !table->indent;
2863 hr = IMXWriter_get_indent(writer, &b);
2864 EXPECT_HR(hr, S_OK);
2865 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2867 b = !table->omitdecl;
2868 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2869 EXPECT_HR(hr, S_OK);
2870 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2872 b = !table->standalone;
2873 hr = IMXWriter_get_standalone(writer, &b);
2874 EXPECT_HR(hr, S_OK);
2875 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2877 hr = IMXWriter_get_encoding(writer, &encoding);
2878 EXPECT_HR(hr, S_OK);
2879 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2880 i, wine_dbgstr_w(encoding), table->encoding);
2881 SysFreeString(encoding);
2883 IMXWriter_Release(writer);
2885 table++;
2886 i++;
2890 static void test_mxwriter_properties(void)
2892 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2893 static const WCHAR emptyW[] = {0};
2894 static const WCHAR testW[] = {'t','e','s','t',0};
2895 ISAXContentHandler *content;
2896 IMXWriter *writer;
2897 VARIANT_BOOL b;
2898 HRESULT hr;
2899 BSTR str, str2;
2900 VARIANT dest;
2902 test_mxwriter_default_properties(mxwriter_default_props);
2904 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2905 &IID_IMXWriter, (void**)&writer);
2906 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2908 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2909 ok(hr == E_POINTER, "got %08x\n", hr);
2911 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2912 ok(hr == E_POINTER, "got %08x\n", hr);
2914 hr = IMXWriter_get_indent(writer, NULL);
2915 ok(hr == E_POINTER, "got %08x\n", hr);
2917 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2918 ok(hr == E_POINTER, "got %08x\n", hr);
2920 hr = IMXWriter_get_standalone(writer, NULL);
2921 ok(hr == E_POINTER, "got %08x\n", hr);
2923 /* set and check */
2924 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2925 ok(hr == S_OK, "got %08x\n", hr);
2927 b = VARIANT_FALSE;
2928 hr = IMXWriter_get_standalone(writer, &b);
2929 ok(hr == S_OK, "got %08x\n", hr);
2930 ok(b == VARIANT_TRUE, "got %d\n", b);
2932 hr = IMXWriter_get_encoding(writer, NULL);
2933 EXPECT_HR(hr, E_POINTER);
2935 /* UTF-16 is a default setting apparently */
2936 str = (void*)0xdeadbeef;
2937 hr = IMXWriter_get_encoding(writer, &str);
2938 EXPECT_HR(hr, S_OK);
2939 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2941 str2 = (void*)0xdeadbeef;
2942 hr = IMXWriter_get_encoding(writer, &str2);
2943 ok(hr == S_OK, "got %08x\n", hr);
2944 ok(str != str2, "expected newly allocated, got same %p\n", str);
2946 SysFreeString(str2);
2947 SysFreeString(str);
2949 /* put empty string */
2950 str = SysAllocString(emptyW);
2951 hr = IMXWriter_put_encoding(writer, str);
2952 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2953 SysFreeString(str);
2955 str = (void*)0xdeadbeef;
2956 hr = IMXWriter_get_encoding(writer, &str);
2957 EXPECT_HR(hr, S_OK);
2958 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2959 SysFreeString(str);
2961 /* invalid encoding name */
2962 str = SysAllocString(testW);
2963 hr = IMXWriter_put_encoding(writer, str);
2964 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2965 SysFreeString(str);
2967 /* test case sensivity */
2968 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2969 EXPECT_HR(hr, S_OK);
2970 str = (void*)0xdeadbeef;
2971 hr = IMXWriter_get_encoding(writer, &str);
2972 EXPECT_HR(hr, S_OK);
2973 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2974 SysFreeString(str);
2976 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2977 EXPECT_HR(hr, S_OK);
2978 str = (void*)0xdeadbeef;
2979 hr = IMXWriter_get_encoding(writer, &str);
2980 EXPECT_HR(hr, S_OK);
2981 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2982 SysFreeString(str);
2984 /* how it affects document creation */
2985 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2986 EXPECT_HR(hr, S_OK);
2988 hr = ISAXContentHandler_startDocument(content);
2989 EXPECT_HR(hr, S_OK);
2990 hr = ISAXContentHandler_endDocument(content);
2991 EXPECT_HR(hr, S_OK);
2993 V_VT(&dest) = VT_EMPTY;
2994 hr = IMXWriter_get_output(writer, &dest);
2995 EXPECT_HR(hr, S_OK);
2996 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2997 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2998 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2999 VariantClear(&dest);
3000 ISAXContentHandler_Release(content);
3002 hr = IMXWriter_get_version(writer, NULL);
3003 ok(hr == E_POINTER, "got %08x\n", hr);
3004 /* default version is 'surprisingly' 1.0 */
3005 hr = IMXWriter_get_version(writer, &str);
3006 ok(hr == S_OK, "got %08x\n", hr);
3007 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3008 SysFreeString(str);
3010 /* store version string as is */
3011 hr = IMXWriter_put_version(writer, NULL);
3012 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3014 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3015 ok(hr == S_OK, "got %08x\n", hr);
3017 hr = IMXWriter_put_version(writer, _bstr_(""));
3018 ok(hr == S_OK, "got %08x\n", hr);
3019 hr = IMXWriter_get_version(writer, &str);
3020 ok(hr == S_OK, "got %08x\n", hr);
3021 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3022 SysFreeString(str);
3024 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3025 ok(hr == S_OK, "got %08x\n", hr);
3026 hr = IMXWriter_get_version(writer, &str);
3027 ok(hr == S_OK, "got %08x\n", hr);
3028 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3029 SysFreeString(str);
3031 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3032 ok(hr == S_OK, "got %08x\n", hr);
3033 hr = IMXWriter_get_version(writer, &str);
3034 ok(hr == S_OK, "got %08x\n", hr);
3035 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3036 SysFreeString(str);
3038 IMXWriter_Release(writer);
3039 free_bstrs();
3042 static void test_mxwriter_flush(void)
3044 static const WCHAR emptyW[] = {0};
3045 ISAXContentHandler *content;
3046 IMXWriter *writer;
3047 LARGE_INTEGER pos;
3048 ULARGE_INTEGER pos2;
3049 IStream *stream;
3050 VARIANT dest;
3051 HRESULT hr;
3052 char *buff;
3053 LONG ref;
3054 int len;
3056 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3057 &IID_IMXWriter, (void**)&writer);
3058 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3060 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3061 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3062 EXPECT_REF(stream, 1);
3064 /* detach when nothing was attached */
3065 V_VT(&dest) = VT_EMPTY;
3066 hr = IMXWriter_put_output(writer, dest);
3067 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3069 /* attach stream */
3070 V_VT(&dest) = VT_UNKNOWN;
3071 V_UNKNOWN(&dest) = (IUnknown*)stream;
3072 hr = IMXWriter_put_output(writer, dest);
3073 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3074 todo_wine EXPECT_REF(stream, 3);
3076 /* detach setting VT_EMPTY destination */
3077 V_VT(&dest) = VT_EMPTY;
3078 hr = IMXWriter_put_output(writer, dest);
3079 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3080 EXPECT_REF(stream, 1);
3082 V_VT(&dest) = VT_UNKNOWN;
3083 V_UNKNOWN(&dest) = (IUnknown*)stream;
3084 hr = IMXWriter_put_output(writer, dest);
3085 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3087 /* flush() doesn't detach a stream */
3088 hr = IMXWriter_flush(writer);
3089 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3090 todo_wine EXPECT_REF(stream, 3);
3092 pos.QuadPart = 0;
3093 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3094 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3095 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3097 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3098 ok(hr == S_OK, "got %08x\n", hr);
3100 hr = ISAXContentHandler_startDocument(content);
3101 ok(hr == S_OK, "got %08x\n", hr);
3103 pos.QuadPart = 0;
3104 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3105 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3106 ok(pos2.QuadPart != 0, "expected stream beginning\n");
3108 /* already started */
3109 hr = ISAXContentHandler_startDocument(content);
3110 ok(hr == S_OK, "got %08x\n", hr);
3112 hr = ISAXContentHandler_endDocument(content);
3113 ok(hr == S_OK, "got %08x\n", hr);
3115 /* flushed on endDocument() */
3116 pos.QuadPart = 0;
3117 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3118 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3119 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3121 IStream_Release(stream);
3123 /* auto-flush feature */
3124 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3125 EXPECT_HR(hr, S_OK);
3126 EXPECT_REF(stream, 1);
3128 V_VT(&dest) = VT_UNKNOWN;
3129 V_UNKNOWN(&dest) = (IUnknown*)stream;
3130 hr = IMXWriter_put_output(writer, dest);
3131 EXPECT_HR(hr, S_OK);
3133 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
3134 EXPECT_HR(hr, S_OK);
3136 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3137 EXPECT_HR(hr, S_OK);
3139 hr = ISAXContentHandler_startDocument(content);
3140 EXPECT_HR(hr, S_OK);
3142 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3143 EXPECT_HR(hr, S_OK);
3145 /* internal buffer is flushed automatically on certain threshold */
3146 pos.QuadPart = 0;
3147 pos2.QuadPart = 1;
3148 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3149 EXPECT_HR(hr, S_OK);
3150 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3152 len = 2048;
3153 buff = HeapAlloc(GetProcessHeap(), 0, len);
3154 memset(buff, 'A', len);
3155 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3156 EXPECT_HR(hr, S_OK);
3158 pos.QuadPart = 0;
3159 pos2.QuadPart = 0;
3160 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3161 EXPECT_HR(hr, S_OK);
3162 todo_wine
3163 ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
3165 hr = IMXWriter_get_output(writer, NULL);
3166 EXPECT_HR(hr, E_POINTER);
3168 ref = get_refcount(stream);
3169 V_VT(&dest) = VT_EMPTY;
3170 hr = IMXWriter_get_output(writer, &dest);
3171 EXPECT_HR(hr, S_OK);
3172 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
3173 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
3174 ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
3175 VariantClear(&dest);
3177 hr = ISAXContentHandler_endDocument(content);
3178 EXPECT_HR(hr, S_OK);
3180 IStream_Release(stream);
3182 /* test char count lower than threshold */
3183 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3184 EXPECT_HR(hr, S_OK);
3185 EXPECT_REF(stream, 1);
3187 hr = ISAXContentHandler_startDocument(content);
3188 EXPECT_HR(hr, S_OK);
3190 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3191 EXPECT_HR(hr, S_OK);
3193 pos.QuadPart = 0;
3194 pos2.QuadPart = 1;
3195 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3196 EXPECT_HR(hr, S_OK);
3197 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3199 memset(buff, 'A', len);
3200 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
3201 EXPECT_HR(hr, S_OK);
3203 pos.QuadPart = 0;
3204 pos2.QuadPart = 1;
3205 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3206 EXPECT_HR(hr, S_OK);
3207 ok(pos2.QuadPart == 0, "expected stream beginning\n");
3209 hr = ISAXContentHandler_endDocument(content);
3210 EXPECT_HR(hr, S_OK);
3212 /* test auto-flush function when stream is not set */
3213 V_VT(&dest) = VT_EMPTY;
3214 hr = IMXWriter_put_output(writer, dest);
3215 EXPECT_HR(hr, S_OK);
3217 hr = ISAXContentHandler_startDocument(content);
3218 EXPECT_HR(hr, S_OK);
3220 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL);
3221 EXPECT_HR(hr, S_OK);
3223 memset(buff, 'A', len);
3224 hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
3225 EXPECT_HR(hr, S_OK);
3227 V_VT(&dest) = VT_EMPTY;
3228 hr = IMXWriter_get_output(writer, &dest);
3229 EXPECT_HR(hr, S_OK);
3230 len += strlen("<a>");
3231 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
3232 VariantClear(&dest);
3234 HeapFree(GetProcessHeap(), 0, buff);
3235 ISAXContentHandler_Release(content);
3236 IStream_Release(stream);
3237 IMXWriter_Release(writer);
3238 free_bstrs();
3241 static void test_mxwriter_startenddocument(void)
3243 ISAXContentHandler *content;
3244 IMXWriter *writer;
3245 VARIANT dest;
3246 HRESULT hr;
3248 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3249 &IID_IMXWriter, (void**)&writer);
3250 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3252 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3253 ok(hr == S_OK, "got %08x\n", hr);
3255 hr = ISAXContentHandler_startDocument(content);
3256 ok(hr == S_OK, "got %08x\n", hr);
3258 hr = ISAXContentHandler_endDocument(content);
3259 ok(hr == S_OK, "got %08x\n", hr);
3261 V_VT(&dest) = VT_EMPTY;
3262 hr = IMXWriter_get_output(writer, &dest);
3263 ok(hr == S_OK, "got %08x\n", hr);
3264 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3265 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3266 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3267 VariantClear(&dest);
3269 /* now try another startDocument */
3270 hr = ISAXContentHandler_startDocument(content);
3271 ok(hr == S_OK, "got %08x\n", hr);
3272 /* and get duplicated prolog */
3273 V_VT(&dest) = VT_EMPTY;
3274 hr = IMXWriter_get_output(writer, &dest);
3275 ok(hr == S_OK, "got %08x\n", hr);
3276 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3277 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
3278 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3279 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3280 VariantClear(&dest);
3282 ISAXContentHandler_Release(content);
3283 IMXWriter_Release(writer);
3285 /* now with omitted declaration */
3286 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3287 &IID_IMXWriter, (void**)&writer);
3288 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3290 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3291 ok(hr == S_OK, "got %08x\n", hr);
3293 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3294 ok(hr == S_OK, "got %08x\n", hr);
3296 hr = ISAXContentHandler_startDocument(content);
3297 ok(hr == S_OK, "got %08x\n", hr);
3299 hr = ISAXContentHandler_endDocument(content);
3300 ok(hr == S_OK, "got %08x\n", hr);
3302 V_VT(&dest) = VT_EMPTY;
3303 hr = IMXWriter_get_output(writer, &dest);
3304 ok(hr == S_OK, "got %08x\n", hr);
3305 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3306 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3307 VariantClear(&dest);
3309 ISAXContentHandler_Release(content);
3310 IMXWriter_Release(writer);
3312 free_bstrs();
3315 enum startendtype
3317 StartElement = 0x001,
3318 EndElement = 0x010,
3319 StartEndElement = 0x011,
3320 DisableEscaping = 0x100
3323 struct writer_startendelement_t {
3324 const GUID *clsid;
3325 enum startendtype type;
3326 const char *uri;
3327 const char *local_name;
3328 const char *qname;
3329 const char *output;
3330 HRESULT hr;
3331 ISAXAttributes *attr;
3334 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\">";
3335 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\"/>";
3336 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\"/>";
3338 static const struct writer_startendelement_t writer_startendelement[] = {
3339 /* 0 */
3340 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3341 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3342 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3343 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
3344 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3345 /* 5 */
3346 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3347 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3348 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
3349 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3350 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3351 /* 10 */
3352 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3353 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
3354 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3355 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3356 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3357 /* 15 */
3358 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
3359 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3360 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3361 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3362 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
3363 /* 20 */
3364 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3365 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3366 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3367 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
3368 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3369 /* 25 */
3370 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3371 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3372 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
3373 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3374 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3375 /* 30 */
3376 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3377 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
3378 /* endElement tests */
3379 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3380 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3381 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
3382 /* 35 */
3383 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
3384 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3385 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3386 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
3387 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
3388 /* 40 */
3389 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3390 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3391 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
3392 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
3393 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3394 /* 45 */
3395 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3396 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
3397 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
3398 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3399 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3400 /* 50 */
3401 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3402 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
3403 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3404 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3405 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
3406 /* 55 */
3407 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
3408 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3409 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3410 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3411 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
3412 /* 60 */
3413 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3414 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3415 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3416 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
3418 /* with attributes */
3419 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3420 /* 65 */
3421 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3422 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3423 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
3424 /* empty elements */
3425 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3426 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3427 /* 70 */
3428 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3429 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3430 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
3431 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
3432 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
3433 /* 75 */
3434 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
3436 /* with disabled output escaping */
3437 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3438 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes },
3439 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3440 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
3442 { NULL }
3445 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
3447 while (table->clsid)
3449 IUnknown *unk;
3450 HRESULT hr;
3452 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
3453 if (hr == S_OK) IUnknown_Release(unk);
3455 table->supported = hr == S_OK;
3456 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
3458 table++;
3462 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
3464 int i = 0;
3466 while (table->clsid)
3468 ISAXContentHandler *content;
3469 IMXWriter *writer;
3470 HRESULT hr;
3472 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3474 table++;
3475 i++;
3476 continue;
3479 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3480 &IID_IMXWriter, (void**)&writer);
3481 EXPECT_HR(hr, S_OK);
3483 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3484 EXPECT_HR(hr, S_OK);
3486 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3487 EXPECT_HR(hr, S_OK);
3489 hr = ISAXContentHandler_startDocument(content);
3490 EXPECT_HR(hr, S_OK);
3492 if (table->type & DisableEscaping)
3494 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3495 EXPECT_HR(hr, S_OK);
3498 if (table->type & StartElement)
3500 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3501 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3502 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3505 if (table->type & EndElement)
3507 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3508 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3509 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3512 /* test output */
3513 if (hr == S_OK)
3515 VARIANT dest;
3517 V_VT(&dest) = VT_EMPTY;
3518 hr = IMXWriter_get_output(writer, &dest);
3519 EXPECT_HR(hr, S_OK);
3520 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3521 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3522 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3523 VariantClear(&dest);
3526 ISAXContentHandler_Release(content);
3527 IMXWriter_Release(writer);
3529 table++;
3530 i++;
3533 free_bstrs();
3536 /* point of these test is to start/end element with different names and name lengths */
3537 struct writer_startendelement2_t {
3538 const GUID *clsid;
3539 const char *qnamestart;
3540 int qnamestart_len;
3541 const char *qnameend;
3542 int qnameend_len;
3543 const char *output;
3544 HRESULT hr;
3547 static const struct writer_startendelement2_t writer_startendelement2[] = {
3548 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK },
3549 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK },
3550 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK },
3551 /* -1 length is not allowed for version 6 */
3552 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG },
3554 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK },
3555 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK },
3556 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK },
3557 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK },
3558 { NULL }
3561 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
3563 int i = 0;
3565 while (table->clsid)
3567 ISAXContentHandler *content;
3568 IMXWriter *writer;
3569 HRESULT hr;
3571 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3573 table++;
3574 i++;
3575 continue;
3578 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3579 &IID_IMXWriter, (void**)&writer);
3580 EXPECT_HR(hr, S_OK);
3582 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3583 EXPECT_HR(hr, S_OK);
3585 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3586 EXPECT_HR(hr, S_OK);
3588 hr = ISAXContentHandler_startDocument(content);
3589 EXPECT_HR(hr, S_OK);
3591 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0,
3592 _bstr_(table->qnamestart), table->qnamestart_len, NULL);
3593 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3595 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0,
3596 _bstr_(table->qnameend), table->qnameend_len);
3597 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3599 /* test output */
3600 if (hr == S_OK)
3602 VARIANT dest;
3604 V_VT(&dest) = VT_EMPTY;
3605 hr = IMXWriter_get_output(writer, &dest);
3606 EXPECT_HR(hr, S_OK);
3607 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3608 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3609 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3610 VariantClear(&dest);
3613 ISAXContentHandler_Release(content);
3614 IMXWriter_Release(writer);
3616 table++;
3617 i++;
3619 free_bstrs();
3624 static void test_mxwriter_startendelement(void)
3626 ISAXContentHandler *content;
3627 IMXWriter *writer;
3628 VARIANT dest;
3629 HRESULT hr;
3631 test_mxwriter_startendelement_batch(writer_startendelement);
3632 test_mxwriter_startendelement_batch2(writer_startendelement2);
3634 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3635 &IID_IMXWriter, (void**)&writer);
3636 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3638 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3639 ok(hr == S_OK, "got %08x\n", hr);
3641 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3642 ok(hr == S_OK, "got %08x\n", hr);
3644 hr = ISAXContentHandler_startDocument(content);
3645 ok(hr == S_OK, "got %08x\n", hr);
3647 /* all string pointers should be not null */
3648 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3649 ok(hr == S_OK, "got %08x\n", hr);
3651 V_VT(&dest) = VT_EMPTY;
3652 hr = IMXWriter_get_output(writer, &dest);
3653 ok(hr == S_OK, "got %08x\n", hr);
3654 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3655 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3656 VariantClear(&dest);
3658 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3659 ok(hr == S_OK, "got %08x\n", hr);
3661 V_VT(&dest) = VT_EMPTY;
3662 hr = IMXWriter_get_output(writer, &dest);
3663 ok(hr == S_OK, "got %08x\n", hr);
3664 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3665 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3666 VariantClear(&dest);
3668 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3669 EXPECT_HR(hr, E_INVALIDARG);
3671 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3672 EXPECT_HR(hr, E_INVALIDARG);
3674 /* only local name is an error too */
3675 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3676 EXPECT_HR(hr, E_INVALIDARG);
3678 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3679 EXPECT_HR(hr, S_OK);
3681 V_VT(&dest) = VT_EMPTY;
3682 hr = IMXWriter_get_output(writer, &dest);
3683 EXPECT_HR(hr, S_OK);
3684 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3685 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3686 VariantClear(&dest);
3688 hr = ISAXContentHandler_endDocument(content);
3689 EXPECT_HR(hr, S_OK);
3691 V_VT(&dest) = VT_EMPTY;
3692 hr = IMXWriter_put_output(writer, dest);
3693 EXPECT_HR(hr, S_OK);
3695 V_VT(&dest) = VT_EMPTY;
3696 hr = IMXWriter_get_output(writer, &dest);
3697 EXPECT_HR(hr, S_OK);
3698 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3699 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3700 VariantClear(&dest);
3702 hr = ISAXContentHandler_startDocument(content);
3703 EXPECT_HR(hr, S_OK);
3705 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3706 EXPECT_HR(hr, S_OK);
3708 V_VT(&dest) = VT_EMPTY;
3709 hr = IMXWriter_get_output(writer, &dest);
3710 EXPECT_HR(hr, S_OK);
3711 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3712 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3713 VariantClear(&dest);
3715 ISAXContentHandler_endDocument(content);
3716 IMXWriter_flush(writer);
3718 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3719 EXPECT_HR(hr, S_OK);
3720 V_VT(&dest) = VT_EMPTY;
3721 hr = IMXWriter_get_output(writer, &dest);
3722 EXPECT_HR(hr, S_OK);
3723 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3724 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3725 VariantClear(&dest);
3727 V_VT(&dest) = VT_EMPTY;
3728 hr = IMXWriter_put_output(writer, dest);
3729 EXPECT_HR(hr, S_OK);
3731 /* length -1 */
3732 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL);
3733 EXPECT_HR(hr, S_OK);
3734 V_VT(&dest) = VT_EMPTY;
3735 hr = IMXWriter_get_output(writer, &dest);
3736 EXPECT_HR(hr, S_OK);
3737 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3738 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3739 VariantClear(&dest);
3741 ISAXContentHandler_Release(content);
3742 IMXWriter_Release(writer);
3743 free_bstrs();
3746 struct writer_characters_t {
3747 const GUID *clsid;
3748 const char *data;
3749 const char *output;
3752 static const struct writer_characters_t writer_characters[] = {
3753 { &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
3754 { &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
3755 { &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
3756 { &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
3757 { NULL }
3760 static void test_mxwriter_characters(void)
3762 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3763 const struct writer_characters_t *table = writer_characters;
3764 ISAXContentHandler *content;
3765 IMXWriter *writer;
3766 VARIANT dest;
3767 HRESULT hr;
3768 int i = 0;
3770 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3771 &IID_IMXWriter, (void**)&writer);
3772 EXPECT_HR(hr, S_OK);
3774 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3775 EXPECT_HR(hr, S_OK);
3777 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3778 EXPECT_HR(hr, S_OK);
3780 hr = ISAXContentHandler_startDocument(content);
3781 EXPECT_HR(hr, S_OK);
3783 hr = ISAXContentHandler_characters(content, NULL, 0);
3784 EXPECT_HR(hr, E_INVALIDARG);
3786 hr = ISAXContentHandler_characters(content, chardataW, 0);
3787 EXPECT_HR(hr, S_OK);
3789 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3790 EXPECT_HR(hr, S_OK);
3792 V_VT(&dest) = VT_EMPTY;
3793 hr = IMXWriter_get_output(writer, &dest);
3794 EXPECT_HR(hr, S_OK);
3795 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3796 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3797 VariantClear(&dest);
3799 hr = ISAXContentHandler_endDocument(content);
3800 EXPECT_HR(hr, S_OK);
3802 ISAXContentHandler_Release(content);
3803 IMXWriter_Release(writer);
3805 /* try empty characters data to see if element is closed */
3806 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3807 &IID_IMXWriter, (void**)&writer);
3808 EXPECT_HR(hr, S_OK);
3810 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3811 EXPECT_HR(hr, S_OK);
3813 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3814 EXPECT_HR(hr, S_OK);
3816 hr = ISAXContentHandler_startDocument(content);
3817 EXPECT_HR(hr, S_OK);
3819 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3820 EXPECT_HR(hr, S_OK);
3822 hr = ISAXContentHandler_characters(content, chardataW, 0);
3823 EXPECT_HR(hr, S_OK);
3825 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3826 EXPECT_HR(hr, S_OK);
3828 V_VT(&dest) = VT_EMPTY;
3829 hr = IMXWriter_get_output(writer, &dest);
3830 EXPECT_HR(hr, S_OK);
3831 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3832 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3833 VariantClear(&dest);
3835 ISAXContentHandler_Release(content);
3836 IMXWriter_Release(writer);
3838 /* batch tests */
3839 while (table->clsid)
3841 ISAXContentHandler *content;
3842 IMXWriter *writer;
3843 VARIANT dest;
3844 HRESULT hr;
3846 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3848 table++;
3849 i++;
3850 continue;
3853 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3854 &IID_IMXWriter, (void**)&writer);
3855 EXPECT_HR(hr, S_OK);
3857 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3858 EXPECT_HR(hr, S_OK);
3860 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3861 EXPECT_HR(hr, S_OK);
3863 hr = ISAXContentHandler_startDocument(content);
3864 EXPECT_HR(hr, S_OK);
3866 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3867 EXPECT_HR(hr, S_OK);
3869 /* test output */
3870 if (hr == S_OK)
3872 V_VT(&dest) = VT_EMPTY;
3873 hr = IMXWriter_get_output(writer, &dest);
3874 EXPECT_HR(hr, S_OK);
3875 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3876 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3877 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3878 VariantClear(&dest);
3881 /* with disabled escaping */
3882 V_VT(&dest) = VT_EMPTY;
3883 hr = IMXWriter_put_output(writer, dest);
3884 EXPECT_HR(hr, S_OK);
3886 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3887 EXPECT_HR(hr, S_OK);
3889 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3890 EXPECT_HR(hr, S_OK);
3892 /* test output */
3893 if (hr == S_OK)
3895 V_VT(&dest) = VT_EMPTY;
3896 hr = IMXWriter_get_output(writer, &dest);
3897 EXPECT_HR(hr, S_OK);
3898 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3899 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3900 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3901 VariantClear(&dest);
3904 ISAXContentHandler_Release(content);
3905 IMXWriter_Release(writer);
3907 table++;
3908 i++;
3911 free_bstrs();
3914 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3916 VARIANT_TRUE,"UTF-16",
3918 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3919 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3920 {TRUE}
3924 VARIANT_FALSE,"UTF-16",
3926 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3927 {TRUE}
3931 VARIANT_TRUE,"UTF-8",
3933 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3934 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3935 * and the writer is released.
3937 {FALSE,NULL,0},
3938 {TRUE}
3942 VARIANT_TRUE,"utf-8",
3944 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3945 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3946 * and the writer is released.
3948 {FALSE,NULL,0},
3949 {TRUE}
3953 VARIANT_TRUE,"UTF-16",
3955 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3956 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3957 {TRUE}
3961 VARIANT_TRUE,"UTF-16",
3963 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3964 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3965 {TRUE}
3970 static void test_mxwriter_stream(void)
3972 IMXWriter *writer;
3973 ISAXContentHandler *content;
3974 HRESULT hr;
3975 VARIANT dest;
3976 IStream *stream;
3977 LARGE_INTEGER pos;
3978 ULARGE_INTEGER pos2;
3979 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3981 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3982 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3984 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3985 &IID_IMXWriter, (void**)&writer);
3986 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3988 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3989 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3991 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3992 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3994 V_VT(&dest) = VT_UNKNOWN;
3995 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3996 hr = IMXWriter_put_output(writer, dest);
3997 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3998 VariantClear(&dest);
4000 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
4001 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
4003 current_write_test = test->expected_writes;
4005 hr = ISAXContentHandler_startDocument(content);
4006 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4008 hr = ISAXContentHandler_endDocument(content);
4009 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
4011 ISAXContentHandler_Release(content);
4012 IMXWriter_Release(writer);
4014 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
4015 (int)(current_write_test-test->expected_writes), current_stream_test_index);
4018 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4019 &IID_IMXWriter, (void**)&writer);
4020 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
4022 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4023 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
4025 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4026 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
4028 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4029 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
4031 V_VT(&dest) = VT_UNKNOWN;
4032 V_UNKNOWN(&dest) = (IUnknown*)stream;
4033 hr = IMXWriter_put_output(writer, dest);
4034 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4036 hr = ISAXContentHandler_startDocument(content);
4037 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4039 /* Setting output of the mxwriter causes the current output to be flushed,
4040 * and the writer to start over.
4042 V_VT(&dest) = VT_EMPTY;
4043 hr = IMXWriter_put_output(writer, dest);
4044 ok(hr == S_OK, "put_output failed: %08x\n", hr);
4046 pos.QuadPart = 0;
4047 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4048 ok(hr == S_OK, "Seek failed: %08x\n", hr);
4049 ok(pos2.QuadPart != 0, "expected stream position moved\n");
4051 hr = ISAXContentHandler_startDocument(content);
4052 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
4054 hr = ISAXContentHandler_endDocument(content);
4055 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
4057 V_VT(&dest) = VT_EMPTY;
4058 hr = IMXWriter_get_output(writer, &dest);
4059 ok(hr == S_OK, "get_output failed: %08x\n", hr);
4060 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4061 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4062 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4063 VariantClear(&dest);
4065 /* test when BOM is written to output stream */
4066 V_VT(&dest) = VT_EMPTY;
4067 hr = IMXWriter_put_output(writer, dest);
4068 EXPECT_HR(hr, S_OK);
4070 pos.QuadPart = 0;
4071 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
4072 EXPECT_HR(hr, S_OK);
4074 V_VT(&dest) = VT_UNKNOWN;
4075 V_UNKNOWN(&dest) = (IUnknown*)stream;
4076 hr = IMXWriter_put_output(writer, dest);
4077 EXPECT_HR(hr, S_OK);
4079 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
4080 EXPECT_HR(hr, S_OK);
4082 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4083 EXPECT_HR(hr, S_OK);
4085 hr = ISAXContentHandler_startDocument(content);
4086 EXPECT_HR(hr, S_OK);
4088 pos.QuadPart = 0;
4089 pos2.QuadPart = 0;
4090 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
4091 EXPECT_HR(hr, S_OK);
4092 ok(pos2.QuadPart == 2, "got wrong position\n");
4094 ISAXContentHandler_Release(content);
4095 IMXWriter_Release(writer);
4097 free_bstrs();
4100 static const char *encoding_names[] = {
4101 "iso-8859-1",
4102 "iso-8859-2",
4103 "iso-8859-3",
4104 "iso-8859-4",
4105 "iso-8859-5",
4106 "iso-8859-7",
4107 "iso-8859-9",
4108 "iso-8859-13",
4109 "iso-8859-15",
4110 NULL
4113 static void test_mxwriter_encoding(void)
4115 ISAXContentHandler *content;
4116 IMXWriter *writer;
4117 IStream *stream;
4118 const char *enc;
4119 VARIANT dest;
4120 HRESULT hr;
4121 HGLOBAL g;
4122 char *ptr;
4123 BSTR s;
4124 int i;
4126 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4127 &IID_IMXWriter, (void**)&writer);
4128 EXPECT_HR(hr, S_OK);
4130 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4131 EXPECT_HR(hr, S_OK);
4133 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4134 EXPECT_HR(hr, S_OK);
4136 hr = ISAXContentHandler_startDocument(content);
4137 EXPECT_HR(hr, S_OK);
4139 hr = ISAXContentHandler_endDocument(content);
4140 EXPECT_HR(hr, S_OK);
4142 /* The content is always re-encoded to UTF-16 when the output is
4143 * retrieved as a BSTR.
4145 V_VT(&dest) = VT_EMPTY;
4146 hr = IMXWriter_get_output(writer, &dest);
4147 EXPECT_HR(hr, S_OK);
4148 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
4149 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
4150 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4151 VariantClear(&dest);
4153 /* switch encoding when something is written already */
4154 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4155 EXPECT_HR(hr, S_OK);
4157 V_VT(&dest) = VT_UNKNOWN;
4158 V_UNKNOWN(&dest) = (IUnknown*)stream;
4159 hr = IMXWriter_put_output(writer, dest);
4160 EXPECT_HR(hr, S_OK);
4162 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
4163 EXPECT_HR(hr, S_OK);
4165 /* write empty element */
4166 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
4167 EXPECT_HR(hr, S_OK);
4169 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
4170 EXPECT_HR(hr, S_OK);
4172 /* switch */
4173 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
4174 EXPECT_HR(hr, S_OK);
4176 hr = IMXWriter_flush(writer);
4177 EXPECT_HR(hr, S_OK);
4179 hr = GetHGlobalFromStream(stream, &g);
4180 EXPECT_HR(hr, S_OK);
4182 ptr = GlobalLock(g);
4183 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
4184 GlobalUnlock(g);
4186 /* so output is unaffected, encoding name is stored however */
4187 hr = IMXWriter_get_encoding(writer, &s);
4188 EXPECT_HR(hr, S_OK);
4189 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
4190 SysFreeString(s);
4192 IStream_Release(stream);
4194 i = 0;
4195 enc = encoding_names[i];
4196 while (enc)
4198 char expectedA[200];
4200 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4201 EXPECT_HR(hr, S_OK);
4203 V_VT(&dest) = VT_UNKNOWN;
4204 V_UNKNOWN(&dest) = (IUnknown*)stream;
4205 hr = IMXWriter_put_output(writer, dest);
4206 EXPECT_HR(hr, S_OK);
4208 hr = IMXWriter_put_encoding(writer, _bstr_(enc));
4209 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
4210 "%s: encoding not accepted\n", enc);
4211 if (hr != S_OK)
4213 enc = encoding_names[++i];
4214 IStream_Release(stream);
4215 continue;
4218 hr = ISAXContentHandler_startDocument(content);
4219 EXPECT_HR(hr, S_OK);
4221 hr = ISAXContentHandler_endDocument(content);
4222 EXPECT_HR(hr, S_OK);
4224 hr = IMXWriter_flush(writer);
4225 EXPECT_HR(hr, S_OK);
4227 /* prepare expected string */
4228 *expectedA = 0;
4229 strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
4230 strcat(expectedA, enc);
4231 strcat(expectedA, "\" standalone=\"no\"?>\r\n");
4233 hr = GetHGlobalFromStream(stream, &g);
4234 EXPECT_HR(hr, S_OK);
4236 ptr = GlobalLock(g);
4237 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
4238 GlobalUnlock(g);
4240 V_VT(&dest) = VT_EMPTY;
4241 hr = IMXWriter_put_output(writer, dest);
4242 EXPECT_HR(hr, S_OK);
4244 IStream_Release(stream);
4246 enc = encoding_names[++i];
4249 ISAXContentHandler_Release(content);
4250 IMXWriter_Release(writer);
4252 free_bstrs();
4255 static void test_obj_dispex(IUnknown *obj)
4257 static const WCHAR starW[] = {'*',0};
4258 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
4259 IDispatchEx *dispex;
4260 IUnknown *unk;
4261 DWORD props;
4262 UINT ticnt;
4263 HRESULT hr;
4264 BSTR name;
4266 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
4267 EXPECT_HR(hr, S_OK);
4268 if (FAILED(hr)) return;
4270 ticnt = 0;
4271 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
4272 EXPECT_HR(hr, S_OK);
4273 ok(ticnt == 1, "ticnt=%u\n", ticnt);
4275 name = SysAllocString(starW);
4276 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
4277 EXPECT_HR(hr, E_NOTIMPL);
4278 SysFreeString(name);
4280 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
4281 EXPECT_HR(hr, E_NOTIMPL);
4283 props = 0;
4284 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
4285 EXPECT_HR(hr, E_NOTIMPL);
4286 ok(props == 0, "expected 0 got %d\n", props);
4288 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
4289 EXPECT_HR(hr, E_NOTIMPL);
4290 if (SUCCEEDED(hr)) SysFreeString(name);
4292 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
4293 EXPECT_HR(hr, E_NOTIMPL);
4295 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
4296 EXPECT_HR(hr, E_NOTIMPL);
4297 if (hr == S_OK && unk) IUnknown_Release(unk);
4299 IDispatchEx_Release(dispex);
4302 static void test_dispex(void)
4304 IVBSAXXMLReader *vbreader;
4305 ISAXXMLReader *reader;
4306 IUnknown *unk;
4307 HRESULT hr;
4309 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4310 &IID_ISAXXMLReader, (void**)&reader);
4311 EXPECT_HR(hr, S_OK);
4313 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
4314 EXPECT_HR(hr, S_OK);
4315 test_obj_dispex(unk);
4316 IUnknown_Release(unk);
4318 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
4319 EXPECT_HR(hr, S_OK);
4320 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
4321 EXPECT_HR(hr, S_OK);
4322 test_obj_dispex(unk);
4323 IUnknown_Release(unk);
4324 IVBSAXXMLReader_Release(vbreader);
4326 ISAXXMLReader_Release(reader);
4329 static void test_mxwriter_dispex(void)
4331 IDispatchEx *dispex;
4332 IMXWriter *writer;
4333 IUnknown *unk;
4334 HRESULT hr;
4336 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4337 &IID_IMXWriter, (void**)&writer);
4338 EXPECT_HR(hr, S_OK);
4340 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
4341 EXPECT_HR(hr, S_OK);
4342 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4343 test_obj_dispex(unk);
4344 IUnknown_Release(unk);
4345 IDispatchEx_Release(dispex);
4347 IMXWriter_Release(writer);
4350 static void test_mxwriter_comment(void)
4352 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
4353 ISAXContentHandler *content;
4354 ISAXLexicalHandler *lexical;
4355 IMXWriter *writer;
4356 VARIANT dest;
4357 HRESULT hr;
4359 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4360 &IID_IMXWriter, (void**)&writer);
4361 EXPECT_HR(hr, S_OK);
4363 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4364 EXPECT_HR(hr, S_OK);
4366 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4367 EXPECT_HR(hr, S_OK);
4369 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4370 EXPECT_HR(hr, S_OK);
4372 hr = ISAXContentHandler_startDocument(content);
4373 EXPECT_HR(hr, S_OK);
4375 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
4376 EXPECT_HR(hr, E_INVALIDARG);
4378 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
4379 EXPECT_HR(hr, S_OK);
4381 V_VT(&dest) = VT_EMPTY;
4382 hr = IMXWriter_get_output(writer, &dest);
4383 EXPECT_HR(hr, S_OK);
4384 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4385 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4386 VariantClear(&dest);
4388 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
4389 EXPECT_HR(hr, S_OK);
4391 V_VT(&dest) = VT_EMPTY;
4392 hr = IMXWriter_get_output(writer, &dest);
4393 EXPECT_HR(hr, S_OK);
4394 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4395 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4396 VariantClear(&dest);
4398 ISAXContentHandler_Release(content);
4399 ISAXLexicalHandler_Release(lexical);
4400 IMXWriter_Release(writer);
4401 free_bstrs();
4404 static void test_mxwriter_cdata(void)
4406 ISAXContentHandler *content;
4407 ISAXLexicalHandler *lexical;
4408 IMXWriter *writer;
4409 VARIANT dest;
4410 HRESULT hr;
4412 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4413 &IID_IMXWriter, (void**)&writer);
4414 EXPECT_HR(hr, S_OK);
4416 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4417 EXPECT_HR(hr, S_OK);
4419 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4420 EXPECT_HR(hr, S_OK);
4422 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4423 EXPECT_HR(hr, S_OK);
4425 hr = ISAXContentHandler_startDocument(content);
4426 EXPECT_HR(hr, S_OK);
4428 hr = ISAXLexicalHandler_startCDATA(lexical);
4429 EXPECT_HR(hr, S_OK);
4431 V_VT(&dest) = VT_EMPTY;
4432 hr = IMXWriter_get_output(writer, &dest);
4433 EXPECT_HR(hr, S_OK);
4434 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4435 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4436 VariantClear(&dest);
4438 hr = ISAXLexicalHandler_startCDATA(lexical);
4439 EXPECT_HR(hr, S_OK);
4441 /* all these are escaped for text nodes */
4442 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
4443 EXPECT_HR(hr, S_OK);
4445 hr = ISAXLexicalHandler_endCDATA(lexical);
4446 EXPECT_HR(hr, S_OK);
4448 V_VT(&dest) = VT_EMPTY;
4449 hr = IMXWriter_get_output(writer, &dest);
4450 EXPECT_HR(hr, S_OK);
4451 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4452 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4453 VariantClear(&dest);
4455 ISAXContentHandler_Release(content);
4456 ISAXLexicalHandler_Release(lexical);
4457 IMXWriter_Release(writer);
4458 free_bstrs();
4461 static void test_mxwriter_pi(void)
4463 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
4464 static const WCHAR dataW[] = {'d','a','t','a',0};
4465 ISAXContentHandler *content;
4466 IMXWriter *writer;
4467 VARIANT dest;
4468 HRESULT hr;
4470 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4471 &IID_IMXWriter, (void**)&writer);
4472 EXPECT_HR(hr, S_OK);
4474 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4475 EXPECT_HR(hr, S_OK);
4477 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
4478 EXPECT_HR(hr, E_INVALIDARG);
4480 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
4481 EXPECT_HR(hr, S_OK);
4483 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
4484 EXPECT_HR(hr, S_OK);
4486 V_VT(&dest) = VT_EMPTY;
4487 hr = IMXWriter_get_output(writer, &dest);
4488 EXPECT_HR(hr, S_OK);
4489 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4490 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4491 VariantClear(&dest);
4493 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
4494 EXPECT_HR(hr, S_OK);
4496 V_VT(&dest) = VT_EMPTY;
4497 hr = IMXWriter_get_output(writer, &dest);
4498 EXPECT_HR(hr, S_OK);
4499 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4500 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)));
4501 VariantClear(&dest);
4503 V_VT(&dest) = VT_EMPTY;
4504 hr = IMXWriter_put_output(writer, dest);
4505 EXPECT_HR(hr, S_OK);
4507 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
4508 EXPECT_HR(hr, S_OK);
4510 V_VT(&dest) = VT_EMPTY;
4511 hr = IMXWriter_get_output(writer, &dest);
4512 EXPECT_HR(hr, S_OK);
4513 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4514 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4515 VariantClear(&dest);
4518 ISAXContentHandler_Release(content);
4519 IMXWriter_Release(writer);
4522 static void test_mxwriter_ignorablespaces(void)
4524 static const WCHAR dataW[] = {'d','a','t','a',0};
4525 ISAXContentHandler *content;
4526 IMXWriter *writer;
4527 VARIANT dest;
4528 HRESULT hr;
4530 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4531 &IID_IMXWriter, (void**)&writer);
4532 EXPECT_HR(hr, S_OK);
4534 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4535 EXPECT_HR(hr, S_OK);
4537 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
4538 EXPECT_HR(hr, E_INVALIDARG);
4540 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
4541 EXPECT_HR(hr, S_OK);
4543 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
4544 EXPECT_HR(hr, S_OK);
4546 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
4547 EXPECT_HR(hr, S_OK);
4549 V_VT(&dest) = VT_EMPTY;
4550 hr = IMXWriter_get_output(writer, &dest);
4551 EXPECT_HR(hr, S_OK);
4552 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4553 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4554 VariantClear(&dest);
4556 ISAXContentHandler_Release(content);
4557 IMXWriter_Release(writer);
4560 static void test_mxwriter_dtd(void)
4562 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
4563 static const WCHAR nameW[] = {'n','a','m','e'};
4564 static const WCHAR pubW[] = {'p','u','b'};
4565 static const WCHAR sysW[] = {'s','y','s'};
4566 ISAXContentHandler *content;
4567 ISAXLexicalHandler *lexical;
4568 ISAXDeclHandler *decl;
4569 IMXWriter *writer;
4570 VARIANT dest;
4571 HRESULT hr;
4573 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
4574 &IID_IMXWriter, (void**)&writer);
4575 EXPECT_HR(hr, S_OK);
4577 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
4578 EXPECT_HR(hr, S_OK);
4580 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
4581 EXPECT_HR(hr, S_OK);
4583 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
4584 EXPECT_HR(hr, S_OK);
4586 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
4587 EXPECT_HR(hr, S_OK);
4589 hr = ISAXContentHandler_startDocument(content);
4590 EXPECT_HR(hr, S_OK);
4592 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
4593 EXPECT_HR(hr, E_INVALIDARG);
4595 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4596 EXPECT_HR(hr, E_INVALIDARG);
4598 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
4599 EXPECT_HR(hr, E_INVALIDARG);
4601 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4602 EXPECT_HR(hr, E_INVALIDARG);
4604 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
4605 EXPECT_HR(hr, S_OK);
4607 V_VT(&dest) = VT_EMPTY;
4608 hr = IMXWriter_get_output(writer, &dest);
4609 EXPECT_HR(hr, S_OK);
4610 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4611 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4612 VariantClear(&dest);
4614 /* system id is required if public is present */
4615 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
4616 EXPECT_HR(hr, E_INVALIDARG);
4618 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
4619 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
4620 EXPECT_HR(hr, S_OK);
4622 V_VT(&dest) = VT_EMPTY;
4623 hr = IMXWriter_get_output(writer, &dest);
4624 EXPECT_HR(hr, S_OK);
4625 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4626 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4627 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4628 VariantClear(&dest);
4630 hr = ISAXLexicalHandler_endDTD(lexical);
4631 EXPECT_HR(hr, S_OK);
4633 hr = ISAXLexicalHandler_endDTD(lexical);
4634 EXPECT_HR(hr, S_OK);
4636 V_VT(&dest) = VT_EMPTY;
4637 hr = IMXWriter_get_output(writer, &dest);
4638 EXPECT_HR(hr, S_OK);
4639 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4640 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
4641 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
4642 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4643 VariantClear(&dest);
4645 /* element declaration */
4646 V_VT(&dest) = VT_EMPTY;
4647 hr = IMXWriter_put_output(writer, dest);
4648 EXPECT_HR(hr, S_OK);
4650 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
4651 EXPECT_HR(hr, E_INVALIDARG);
4653 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
4654 EXPECT_HR(hr, E_INVALIDARG);
4656 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
4657 EXPECT_HR(hr, S_OK);
4659 V_VT(&dest) = VT_EMPTY;
4660 hr = IMXWriter_get_output(writer, &dest);
4661 EXPECT_HR(hr, S_OK);
4662 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4663 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4664 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4665 VariantClear(&dest);
4667 V_VT(&dest) = VT_EMPTY;
4668 hr = IMXWriter_put_output(writer, dest);
4669 EXPECT_HR(hr, S_OK);
4671 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4672 EXPECT_HR(hr, S_OK);
4674 V_VT(&dest) = VT_EMPTY;
4675 hr = IMXWriter_get_output(writer, &dest);
4676 EXPECT_HR(hr, S_OK);
4677 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4678 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4679 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4680 VariantClear(&dest);
4682 /* attribute declaration */
4683 V_VT(&dest) = VT_EMPTY;
4684 hr = IMXWriter_put_output(writer, dest);
4685 EXPECT_HR(hr, S_OK);
4687 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4688 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"),
4689 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value"));
4690 EXPECT_HR(hr, S_OK);
4692 V_VT(&dest) = VT_EMPTY;
4693 hr = IMXWriter_get_output(writer, &dest);
4694 EXPECT_HR(hr, S_OK);
4695 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4696 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"),
4697 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4698 VariantClear(&dest);
4700 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"),
4701 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"),
4702 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2"));
4703 EXPECT_HR(hr, S_OK);
4705 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"),
4706 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"),
4707 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3"));
4708 EXPECT_HR(hr, S_OK);
4710 V_VT(&dest) = VT_EMPTY;
4711 hr = IMXWriter_get_output(writer, &dest);
4712 EXPECT_HR(hr, S_OK);
4713 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4714 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"
4715 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n"
4716 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"),
4717 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4718 VariantClear(&dest);
4720 /* internal entities */
4721 V_VT(&dest) = VT_EMPTY;
4722 hr = IMXWriter_put_output(writer, dest);
4723 EXPECT_HR(hr, S_OK);
4725 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
4726 EXPECT_HR(hr, E_INVALIDARG);
4728 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0);
4729 EXPECT_HR(hr, E_INVALIDARG);
4731 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value"));
4732 EXPECT_HR(hr, S_OK);
4734 V_VT(&dest) = VT_EMPTY;
4735 hr = IMXWriter_get_output(writer, &dest);
4736 EXPECT_HR(hr, S_OK);
4737 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4738 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4739 VariantClear(&dest);
4741 ISAXContentHandler_Release(content);
4742 ISAXLexicalHandler_Release(lexical);
4743 ISAXDeclHandler_Release(decl);
4744 IMXWriter_Release(writer);
4745 free_bstrs();
4748 typedef struct {
4749 const CLSID *clsid;
4750 const char *uri;
4751 const char *local;
4752 const char *qname;
4753 const char *type;
4754 const char *value;
4755 HRESULT hr;
4756 } addattribute_test_t;
4758 static const addattribute_test_t addattribute_data[] = {
4759 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4760 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4761 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4762 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4764 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4765 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4766 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4767 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4769 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4770 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4771 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4772 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4774 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4775 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4776 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4777 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4779 { NULL }
4782 static void test_mxattr_addAttribute(void)
4784 const addattribute_test_t *table = addattribute_data;
4785 int i = 0;
4787 while (table->clsid)
4789 ISAXAttributes *saxattr;
4790 IMXAttributes *mxattr;
4791 const WCHAR *value;
4792 int len, index;
4793 HRESULT hr;
4795 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4797 table++;
4798 i++;
4799 continue;
4802 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4803 &IID_IMXAttributes, (void**)&mxattr);
4804 EXPECT_HR(hr, S_OK);
4806 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4807 EXPECT_HR(hr, S_OK);
4809 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4810 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4811 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4813 hr = ISAXAttributes_getLength(saxattr, NULL);
4814 EXPECT_HR(hr, E_POINTER);
4817 len = -1;
4818 hr = ISAXAttributes_getLength(saxattr, &len);
4819 EXPECT_HR(hr, S_OK);
4820 ok(len == 0, "got %d\n", len);
4822 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4823 EXPECT_HR(hr, E_INVALIDARG);
4825 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4826 EXPECT_HR(hr, E_INVALIDARG);
4828 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4829 EXPECT_HR(hr, E_INVALIDARG);
4831 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4832 EXPECT_HR(hr, E_INVALIDARG);
4834 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4835 EXPECT_HR(hr, E_INVALIDARG);
4837 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4838 EXPECT_HR(hr, E_INVALIDARG);
4840 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4841 EXPECT_HR(hr, E_INVALIDARG);
4843 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4844 EXPECT_HR(hr, E_INVALIDARG);
4846 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4847 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4848 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4850 if (hr == S_OK)
4852 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4853 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4854 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4856 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4857 EXPECT_HR(hr, E_POINTER);
4859 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4860 EXPECT_HR(hr, E_POINTER);
4862 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4863 EXPECT_HR(hr, E_POINTER);
4865 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4866 EXPECT_HR(hr, E_POINTER);
4868 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4869 EXPECT_HR(hr, E_POINTER);
4871 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4872 EXPECT_HR(hr, E_POINTER);
4875 len = -1;
4876 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4877 EXPECT_HR(hr, S_OK);
4878 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4879 table->value);
4880 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4882 len = -1;
4883 value = (void*)0xdeadbeef;
4884 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4885 EXPECT_HR(hr, S_OK);
4887 if (table->type)
4889 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4890 table->type);
4891 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4893 else
4895 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4896 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4899 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4900 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4901 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4903 EXPECT_HR(hr, E_POINTER);
4905 else
4906 EXPECT_HR(hr, E_INVALIDARG);
4908 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4909 EXPECT_HR(hr, E_INVALIDARG);
4911 index = -1;
4912 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4913 EXPECT_HR(hr, E_INVALIDARG);
4914 ok(index == -1, "%d: got wrong index %d\n", i, index);
4916 index = -1;
4917 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4918 EXPECT_HR(hr, E_INVALIDARG);
4919 ok(index == -1, "%d: got wrong index %d\n", i, index);
4921 index = -1;
4922 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4923 EXPECT_HR(hr, S_OK);
4924 ok(index == 0, "%d: got wrong index %d\n", i, index);
4926 index = -1;
4927 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4928 EXPECT_HR(hr, E_INVALIDARG);
4929 ok(index == -1, "%d: got wrong index %d\n", i, index);
4931 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4932 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4934 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4935 EXPECT_HR(hr, E_INVALIDARG);
4937 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4938 EXPECT_HR(hr, E_INVALIDARG);
4940 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4941 EXPECT_HR(hr, E_INVALIDARG);
4943 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4944 EXPECT_HR(hr, E_INVALIDARG);
4946 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4947 EXPECT_HR(hr, E_INVALIDARG);
4949 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4950 EXPECT_HR(hr, E_INVALIDARG);
4952 else
4954 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4955 EXPECT_HR(hr, E_POINTER);
4957 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4958 EXPECT_HR(hr, E_POINTER);
4960 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4961 EXPECT_HR(hr, E_POINTER);
4963 /* versions 4 and 6 crash */
4964 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4965 EXPECT_HR(hr, E_POINTER);
4967 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4968 EXPECT_HR(hr, E_POINTER);
4970 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4971 EXPECT_HR(hr, E_POINTER);
4973 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4974 EXPECT_HR(hr, E_POINTER);
4976 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4977 EXPECT_HR(hr, E_POINTER);
4979 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4980 EXPECT_HR(hr, E_POINTER);
4982 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4983 EXPECT_HR(hr, E_POINTER);
4985 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4986 strlen(table->local), NULL, NULL);
4987 EXPECT_HR(hr, E_POINTER);
4990 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4991 EXPECT_HR(hr, S_OK);
4992 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4993 table->value);
4994 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4996 if (table->uri) {
4997 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4998 _bstr_(table->local), strlen(table->local), &value, &len);
4999 EXPECT_HR(hr, S_OK);
5000 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
5001 table->value);
5002 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
5006 len = -1;
5007 hr = ISAXAttributes_getLength(saxattr, &len);
5008 EXPECT_HR(hr, S_OK);
5009 if (table->hr == S_OK)
5010 ok(len == 1, "%d: got %d length, expected 1\n", i, len);
5011 else
5012 ok(len == 0, "%d: got %d length, expected 0\n", i, len);
5014 ISAXAttributes_Release(saxattr);
5015 IMXAttributes_Release(mxattr);
5017 table++;
5018 i++;
5021 free_bstrs();
5024 static void test_mxattr_clear(void)
5026 ISAXAttributes *saxattr;
5027 IMXAttributes *mxattr;
5028 const WCHAR *ptr;
5029 HRESULT hr;
5030 int len;
5032 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5033 &IID_IMXAttributes, (void**)&mxattr);
5034 EXPECT_HR(hr, S_OK);
5036 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5037 EXPECT_HR(hr, S_OK);
5039 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
5040 EXPECT_HR(hr, E_INVALIDARG);
5042 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5043 EXPECT_HR(hr, E_INVALIDARG);
5045 hr = IMXAttributes_clear(mxattr);
5046 EXPECT_HR(hr, S_OK);
5048 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
5049 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
5050 EXPECT_HR(hr, S_OK);
5052 len = -1;
5053 hr = ISAXAttributes_getLength(saxattr, &len);
5054 EXPECT_HR(hr, S_OK);
5055 ok(len == 1, "got %d\n", len);
5057 len = -1;
5058 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
5059 EXPECT_HR(hr, E_POINTER);
5060 ok(len == -1, "got %d\n", len);
5062 ptr = (void*)0xdeadbeef;
5063 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
5064 EXPECT_HR(hr, E_POINTER);
5065 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5067 len = 0;
5068 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5069 EXPECT_HR(hr, S_OK);
5070 ok(len == 5, "got %d\n", len);
5071 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
5073 hr = IMXAttributes_clear(mxattr);
5074 EXPECT_HR(hr, S_OK);
5076 len = -1;
5077 hr = ISAXAttributes_getLength(saxattr, &len);
5078 EXPECT_HR(hr, S_OK);
5079 ok(len == 0, "got %d\n", len);
5081 len = -1;
5082 ptr = (void*)0xdeadbeef;
5083 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
5084 EXPECT_HR(hr, E_INVALIDARG);
5085 ok(len == -1, "got %d\n", len);
5086 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
5088 IMXAttributes_Release(mxattr);
5089 ISAXAttributes_Release(saxattr);
5090 free_bstrs();
5093 static void test_mxattr_dispex(void)
5095 IMXAttributes *mxattr;
5096 IDispatchEx *dispex;
5097 IUnknown *unk;
5098 HRESULT hr;
5100 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5101 &IID_IMXAttributes, (void**)&mxattr);
5102 EXPECT_HR(hr, S_OK);
5104 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
5105 EXPECT_HR(hr, S_OK);
5106 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
5107 test_obj_dispex(unk);
5108 IUnknown_Release(unk);
5109 IDispatchEx_Release(dispex);
5111 IMXAttributes_Release(mxattr);
5114 static void test_mxattr_qi(void)
5116 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
5117 ISAXAttributes *saxattr;
5118 IMXAttributes *mxattr;
5119 HRESULT hr;
5121 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
5122 &IID_IMXAttributes, (void**)&mxattr);
5123 EXPECT_HR(hr, S_OK);
5125 EXPECT_REF(mxattr, 1);
5126 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5127 EXPECT_HR(hr, S_OK);
5129 EXPECT_REF(mxattr, 2);
5130 EXPECT_REF(saxattr, 2);
5132 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
5133 EXPECT_HR(hr, S_OK);
5135 EXPECT_REF(vbsaxattr, 3);
5136 EXPECT_REF(mxattr, 3);
5137 EXPECT_REF(saxattr, 3);
5139 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
5140 EXPECT_HR(hr, S_OK);
5142 EXPECT_REF(vbsaxattr, 4);
5143 EXPECT_REF(mxattr, 4);
5144 EXPECT_REF(saxattr, 4);
5146 IMXAttributes_Release(mxattr);
5147 ISAXAttributes_Release(saxattr);
5148 IVBSAXAttributes_Release(vbsaxattr);
5149 IVBSAXAttributes_Release(vbsaxattr2);
5152 static struct msxmlsupported_data_t saxattr_support_data[] =
5154 { &CLSID_SAXAttributes, "SAXAttributes" },
5155 { &CLSID_SAXAttributes30, "SAXAttributes30" },
5156 { &CLSID_SAXAttributes40, "SAXAttributes40" },
5157 { &CLSID_SAXAttributes60, "SAXAttributes60" },
5158 { NULL }
5161 static void test_mxattr_localname(void)
5163 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
5164 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
5165 static const WCHAR uri1W[] = {'u','r','i','1',0};
5166 static const WCHAR uriW[] = {'u','r','i',0};
5168 const struct msxmlsupported_data_t *table = saxattr_support_data;
5170 while (table->clsid)
5172 ISAXAttributes *saxattr;
5173 IMXAttributes *mxattr;
5174 HRESULT hr;
5175 int index;
5177 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
5179 table++;
5180 continue;
5183 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
5184 &IID_IMXAttributes, (void**)&mxattr);
5185 EXPECT_HR(hr, S_OK);
5187 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
5188 EXPECT_HR(hr, S_OK);
5190 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
5191 EXPECT_HR(hr, E_INVALIDARG);
5193 /* add some ambiguos attribute names */
5194 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5195 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
5196 EXPECT_HR(hr, S_OK);
5197 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
5198 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
5199 EXPECT_HR(hr, S_OK);
5201 index = -1;
5202 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
5203 EXPECT_HR(hr, S_OK);
5204 ok(index == 0, "%s: got index %d\n", table->name, index);
5206 index = -1;
5207 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
5208 EXPECT_HR(hr, E_INVALIDARG);
5209 ok(index == -1, "%s: got index %d\n", table->name, index);
5211 index = -1;
5212 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
5213 EXPECT_HR(hr, E_INVALIDARG);
5214 ok(index == -1, "%s: got index %d\n", table->name, index);
5216 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
5217 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
5219 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5220 EXPECT_HR(hr, E_POINTER);
5222 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5223 EXPECT_HR(hr, E_POINTER);
5225 else
5227 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
5228 EXPECT_HR(hr, E_INVALIDARG);
5230 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
5231 EXPECT_HR(hr, E_INVALIDARG);
5234 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
5235 EXPECT_HR(hr, E_INVALIDARG);
5237 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
5238 EXPECT_HR(hr, E_INVALIDARG);
5240 table++;
5242 ISAXAttributes_Release(saxattr);
5243 IMXAttributes_Release(mxattr);
5247 START_TEST(saxreader)
5249 ISAXXMLReader *reader;
5250 HRESULT hr;
5252 hr = CoInitialize(NULL);
5253 ok(hr == S_OK, "failed to init com\n");
5255 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
5256 &IID_ISAXXMLReader, (void**)&reader);
5258 if(FAILED(hr))
5260 skip("Failed to create SAXXMLReader instance\n");
5261 CoUninitialize();
5262 return;
5264 ISAXXMLReader_Release(reader);
5266 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5268 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
5270 test_saxreader();
5271 test_saxreader_properties();
5272 test_saxreader_features();
5273 test_saxreader_encoding();
5274 test_dispex();
5276 /* MXXMLWriter tests */
5277 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
5278 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
5280 test_mxwriter_handlers();
5281 test_mxwriter_startenddocument();
5282 test_mxwriter_startendelement();
5283 test_mxwriter_characters();
5284 test_mxwriter_comment();
5285 test_mxwriter_cdata();
5286 test_mxwriter_pi();
5287 test_mxwriter_ignorablespaces();
5288 test_mxwriter_dtd();
5289 test_mxwriter_properties();
5290 test_mxwriter_flush();
5291 test_mxwriter_stream();
5292 test_mxwriter_encoding();
5293 test_mxwriter_dispex();
5295 else
5296 win_skip("MXXMLWriter not supported\n");
5298 /* SAXAttributes tests */
5299 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
5300 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
5302 test_mxattr_qi();
5303 test_mxattr_addAttribute();
5304 test_mxattr_clear();
5305 test_mxattr_localname();
5306 test_mxattr_dispex();
5308 else
5309 skip("SAXAttributes not supported\n");
5311 CoUninitialize();