msxml3: Support disabled escaping mode for characters() callback.
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blob04a06485d57f6b0d28978ba6ad4e14a8e0c7a76a
1 /*
2 * SAXReader/MXWriter tests
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
6 * Copyright 2012 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define CONST_VTABLE
26 #include <stdio.h>
27 #include <assert.h>
29 #include "windows.h"
30 #include "ole2.h"
31 #include "msxml2.h"
32 #include "msxml2did.h"
33 #include "ocidl.h"
34 #include "dispex.h"
36 #include "wine/test.h"
38 #define EXPECT_HR(hr,hr_exp) \
39 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
41 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
42 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
44 ULONG rc = IUnknown_AddRef(obj);
45 IUnknown_Release(obj);
46 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
49 struct msxmlsupported_data_t
51 const GUID *clsid;
52 const char *name;
53 BOOL supported;
56 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
58 while (table->clsid)
60 if (table->clsid == clsid) return table->supported;
61 table++;
63 return FALSE;
66 static BSTR alloc_str_from_narrow(const char *str)
68 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
69 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
70 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
71 return ret;
74 static BSTR alloced_bstrs[512];
75 static int alloced_bstrs_count;
77 static BSTR _bstr_(const char *str)
79 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
80 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
81 return alloced_bstrs[alloced_bstrs_count++];
84 static void free_bstrs(void)
86 int i;
87 for (i = 0; i < alloced_bstrs_count; i++)
88 SysFreeString(alloced_bstrs[i]);
89 alloced_bstrs_count = 0;
92 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, int todo, int *failcount)
94 int len, lenexp, cmp;
95 WCHAR buf[1024];
97 len = SysStringLen(str);
99 if (!expected) {
100 if (str && todo)
102 (*failcount)++;
103 todo_wine
104 ok_(file, line) (!str, "got %p, expected null str\n", str);
106 else
107 ok_(file, line) (!str, "got %p, expected null str\n", str);
109 if (len && todo)
111 (*failcount)++;
112 todo_wine
113 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
115 else
116 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
117 return;
120 lenexp = strlen(expected);
121 if (lenexp != len && todo)
123 (*failcount)++;
124 todo_wine
125 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
127 else
128 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
130 /* exit earlier on length mismatch */
131 if (lenexp != len) return;
133 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, sizeof(buf)/sizeof(WCHAR));
135 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
136 if (cmp && todo)
138 (*failcount)++;
139 todo_wine
140 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
141 wine_dbgstr_wn(str, len), expected);
143 else
144 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
145 wine_dbgstr_wn(str, len), expected);
148 typedef enum _CH {
149 CH_ENDTEST,
150 CH_PUTDOCUMENTLOCATOR,
151 CH_STARTDOCUMENT,
152 CH_ENDDOCUMENT,
153 CH_STARTPREFIXMAPPING,
154 CH_ENDPREFIXMAPPING,
155 CH_STARTELEMENT,
156 CH_ENDELEMENT,
157 CH_CHARACTERS,
158 CH_IGNORABLEWHITESPACE,
159 CH_PROCESSINGINSTRUCTION,
160 CH_SKIPPEDENTITY,
161 EH_ERROR,
162 EH_FATALERROR,
163 EG_IGNORABLEWARNING,
164 EVENT_LAST
165 } CH;
167 static const char *event_names[EVENT_LAST] = {
168 "endtest",
169 "putDocumentLocator",
170 "startDocument",
171 "endDocument",
172 "startPrefixMapping",
173 "endPrefixMapping",
174 "startElement",
175 "endElement",
176 "characters",
177 "ignorableWhitespace",
178 "processingIntruction",
179 "skippedEntity",
180 "error",
181 "fatalError",
182 "ignorableWarning"
185 struct attribute_entry {
186 const char *uri;
187 const char *local;
188 const char *qname;
189 const char *value;
191 /* used for actual call data only, null for expected call data */
192 BSTR uriW;
193 BSTR localW;
194 BSTR qnameW;
195 BSTR valueW;
198 struct call_entry {
199 CH id;
200 int line;
201 int column;
202 HRESULT ret;
203 const char *arg1;
204 const char *arg2;
205 const char *arg3;
207 /* allocated once at startElement callback */
208 struct attribute_entry *attributes;
209 int attr_count;
211 /* used for actual call data only, null for expected call data */
212 BSTR arg1W;
213 BSTR arg2W;
214 BSTR arg3W;
217 struct call_sequence
219 int count;
220 int size;
221 struct call_entry *sequence;
224 #define CONTENT_HANDLER_INDEX 0
225 #define NUM_CALL_SEQUENCES 1
226 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
228 static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
230 memset(call, 0, sizeof(*call));
231 ISAXLocator_getLineNumber(locator, &call->line);
232 ISAXLocator_getColumnNumber(locator, &call->column);
235 static void add_call(struct call_sequence **seq, int sequence_index,
236 const struct call_entry *call)
238 struct call_sequence *call_seq = seq[sequence_index];
240 if (!call_seq->sequence)
242 call_seq->size = 10;
243 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
244 call_seq->size * sizeof (struct call_entry));
247 if (call_seq->count == call_seq->size)
249 call_seq->size *= 2;
250 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
251 call_seq->sequence,
252 call_seq->size * sizeof (struct call_entry));
255 assert(call_seq->sequence);
257 call_seq->sequence[call_seq->count].id = call->id;
258 call_seq->sequence[call_seq->count].line = call->line;
259 call_seq->sequence[call_seq->count].column = call->column;
260 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
261 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
262 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
263 call_seq->sequence[call_seq->count].ret = call->ret;
264 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
265 call_seq->sequence[call_seq->count].attributes = call->attributes;
267 call_seq->count++;
270 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
272 int i;
274 struct call_sequence *call_seq = seg[sequence_index];
276 for (i = 0; i < call_seq->count; i++)
278 int j;
280 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
282 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
283 SysFreeString(call_seq->sequence[i].attributes[j].localW);
284 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
287 SysFreeString(call_seq->sequence[i].arg1W);
288 SysFreeString(call_seq->sequence[i].arg2W);
289 SysFreeString(call_seq->sequence[i].arg3W);
292 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
293 call_seq->sequence = NULL;
294 call_seq->count = call_seq->size = 0;
297 static inline void flush_sequences(struct call_sequence **seq, int n)
299 int i;
300 for (i = 0; i < n; i++)
301 flush_sequence(seq, i);
304 static const char *get_event_name(CH event)
306 return event_names[event];
309 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
310 int todo, const char *file, int line, int *failcount)
312 int i, lenexp = 0;
314 /* attribute count is not stored for expected data */
315 if (expected->attributes)
317 struct attribute_entry *ptr = expected->attributes;
318 while (ptr->uri) { lenexp++; ptr++; };
321 /* check count first and exit earlier */
322 if (actual->attr_count != lenexp && todo)
324 (*failcount)++;
325 todo_wine
326 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
327 context, get_event_name(actual->id), lenexp, actual->attr_count);
329 else
330 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
331 context, get_event_name(actual->id), lenexp, actual->attr_count);
333 if (actual->attr_count != lenexp) return;
335 /* now compare all attributes strings */
336 for (i = 0; i < actual->attr_count; i++)
338 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
339 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
340 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
341 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
345 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
346 const struct call_entry *expected, const char *context, int todo,
347 const char *file, int line)
349 struct call_sequence *call_seq = seq[sequence_index];
350 static const struct call_entry end_of_sequence = { CH_ENDTEST };
351 const struct call_entry *actual, *sequence;
352 int failcount = 0;
354 add_call(seq, sequence_index, &end_of_sequence);
356 sequence = call_seq->sequence;
357 actual = sequence;
359 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
361 if (expected->id == actual->id)
363 /* always test position data */
364 if (expected->line != actual->line && todo)
366 todo_wine
368 failcount++;
369 ok_(file, line) (FALSE,
370 "%s: in event %s expecting line %d got %d\n",
371 context, get_event_name(actual->id), expected->line, actual->line);
374 else
376 ok_(file, line) (expected->line == actual->line,
377 "%s: in event %s expecting line %d got %d\n",
378 context, get_event_name(actual->id), expected->line, actual->line);
381 if (expected->column != actual->column && todo)
383 todo_wine
385 failcount++;
386 ok_(file, line) (FALSE,
387 "%s: in event %s expecting column %d got %d\n",
388 context, get_event_name(actual->id), expected->column, actual->column);
391 else
393 ok_(file, line) (expected->column == actual->column,
394 "%s: in event %s expecting column %d got %d\n",
395 context, get_event_name(actual->id), expected->column, actual->column);
398 switch (actual->id)
400 case CH_PUTDOCUMENTLOCATOR:
401 case CH_STARTDOCUMENT:
402 case CH_ENDDOCUMENT:
403 break;
404 case CH_STARTPREFIXMAPPING:
405 /* prefix, uri */
406 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
407 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
408 break;
409 case CH_ENDPREFIXMAPPING:
410 /* prefix */
411 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
412 break;
413 case CH_STARTELEMENT:
414 /* compare attributes */
415 compare_attributes(actual, expected, context, todo, file, line, &failcount);
416 /* fallthrough */
417 case CH_ENDELEMENT:
418 /* uri, localname, qname */
419 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
420 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
421 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
422 break;
423 case CH_CHARACTERS:
424 case CH_IGNORABLEWHITESPACE:
425 /* char data */
426 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
427 break;
428 case CH_PROCESSINGINSTRUCTION:
429 /* target, data */
430 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
431 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
432 break;
433 case CH_SKIPPEDENTITY:
434 /* name */
435 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
436 break;
437 case EH_FATALERROR:
438 /* test return value only */
439 if (expected->ret != actual->ret && todo)
441 failcount++;
442 ok_(file, line) (FALSE,
443 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
444 context, get_event_name(actual->id), expected->ret, actual->ret);
446 else
447 ok_(file, line) (expected->ret == actual->ret,
448 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
449 context, get_event_name(actual->id), expected->ret, actual->ret);
450 break;
451 case EH_ERROR:
452 case EG_IGNORABLEWARNING:
453 default:
454 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
456 expected++;
457 actual++;
459 else if (todo)
461 failcount++;
462 todo_wine
464 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
465 context, get_event_name(expected->id), get_event_name(actual->id));
468 flush_sequence(seq, sequence_index);
469 return;
471 else
473 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
474 context, get_event_name(expected->id), get_event_name(actual->id));
475 expected++;
476 actual++;
480 if (todo)
482 todo_wine
484 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
486 failcount++;
487 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
488 context, get_event_name(expected->id), get_event_name(actual->id));
492 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
494 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
495 context, get_event_name(expected->id), get_event_name(actual->id));
498 if (todo && !failcount) /* succeeded yet marked todo */
500 todo_wine
502 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
506 flush_sequence(seq, sequence_index);
509 #define ok_sequence(seq, index, exp, contx, todo) \
510 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
512 static void init_call_sequences(struct call_sequence **seq, int n)
514 int i;
516 for (i = 0; i < n; i++)
517 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
520 static const WCHAR szSimpleXML[] = {
521 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
522 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
523 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
524 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
525 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
528 static const WCHAR carriage_ret_test[] = {
529 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
530 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
531 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
532 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
533 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
536 static const WCHAR szUtf16XML[] = {
537 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
538 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
539 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
542 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
544 static const CHAR szUtf8XML[] =
545 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
547 static const char utf8xml2[] =
548 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
550 static const CHAR testXML[] =
551 "<?xml version=\"1.0\" ?>\n"
552 "<BankAccount>\n"
553 " <Number>1234</Number>\n"
554 " <Name>Captain Ahab</Name>\n"
555 "</BankAccount>\n";
557 static const char test_attributes[] =
558 "<?xml version=\"1.0\" ?>\n"
559 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
560 "<node1 xmlns:p=\"test\" />"
561 "</document>\n";
563 static struct call_entry content_handler_test1[] = {
564 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
565 { CH_STARTDOCUMENT, 0, 0, S_OK },
566 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
567 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
568 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
569 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
570 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
571 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
572 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
573 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
574 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
575 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
576 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
577 { CH_ENDDOCUMENT, 0, 0, S_OK},
578 { CH_ENDTEST }
581 /* applies to versions 4 and 6 */
582 static struct call_entry content_handler_test1_alternate[] = {
583 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
584 { CH_STARTDOCUMENT, 1, 22, S_OK },
585 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
586 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
587 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
588 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
589 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
590 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
591 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
592 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
593 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
594 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
595 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
596 { CH_ENDDOCUMENT, 6, 0, S_OK },
597 { CH_ENDTEST }
600 static struct call_entry content_handler_test2[] = {
601 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
602 { CH_STARTDOCUMENT, 0, 0, S_OK },
603 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
604 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
605 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
606 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
607 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
608 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
609 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
610 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
611 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
612 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
613 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
614 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
615 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
616 { CH_ENDDOCUMENT, 0, 0, S_OK },
617 { CH_ENDTEST }
620 static struct call_entry content_handler_test2_alternate[] = {
621 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
622 { CH_STARTDOCUMENT, 1, 21, S_OK },
623 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
624 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
625 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
626 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
627 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
628 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
629 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
630 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
631 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
632 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
633 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
634 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
635 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
636 { CH_ENDDOCUMENT, 6, 0, S_OK },
637 { CH_ENDTEST }
640 static struct call_entry content_handler_testerror[] = {
641 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
642 { EH_FATALERROR, 0, 0, E_FAIL },
643 { CH_ENDTEST }
646 static struct call_entry content_handler_testerror_alternate[] = {
647 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
648 { EH_FATALERROR, 1, 0, E_FAIL },
649 { CH_ENDTEST }
652 static struct call_entry content_handler_test_callback_rets[] = {
653 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE },
654 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
655 { EH_FATALERROR, 0, 0, S_FALSE },
656 { CH_ENDTEST }
659 static struct call_entry content_handler_test_callback_rets_alt[] = {
660 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
661 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
662 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
663 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
664 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
665 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
666 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
667 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
668 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
669 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
670 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
671 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
672 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
673 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
674 { CH_ENDTEST }
677 static struct attribute_entry ch_attributes1[] = {
678 { "", "", "xmlns:test", "prefix_test" },
679 { "", "", "xmlns", "prefix" },
680 { "prefix_test", "arg1", "test:arg1", "arg1" },
681 { "", "arg2", "arg2", "arg2" },
682 { "prefix_test", "ar3", "test:ar3", "arg3" },
683 { NULL }
686 static struct attribute_entry ch_attributes2[] = {
687 { "", "", "xmlns:p", "test" },
688 { NULL }
691 static struct call_entry content_handler_test_attributes[] = {
692 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
693 { CH_STARTDOCUMENT, 0, 0, S_OK },
694 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
695 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
696 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
697 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
698 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
699 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
700 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
701 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
702 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
703 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
704 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
705 { CH_ENDDOCUMENT, 0, 0 },
706 { CH_ENDTEST }
709 static struct attribute_entry ch_attributes_alt_4[] = {
710 { "prefix_test", "arg1", "test:arg1", "arg1" },
711 { "", "arg2", "arg2", "arg2" },
712 { "prefix_test", "ar3", "test:ar3", "arg3" },
713 { "", "", "xmlns:test", "prefix_test" },
714 { "", "", "xmlns", "prefix" },
715 { NULL }
718 static struct call_entry content_handler_test_attributes_alternate_4[] = {
719 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
720 { CH_STARTDOCUMENT, 1, 22, S_OK },
721 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
722 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
723 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
724 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
725 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
726 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
727 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
728 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
729 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
730 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
731 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
732 { CH_ENDDOCUMENT, 4, 0, S_OK },
733 { CH_ENDTEST }
736 /* 'namespace' feature switched off */
737 static struct attribute_entry ch_attributes_alt_no_ns[] = {
738 { "", "", "xmlns:test", "prefix_test" },
739 { "", "", "xmlns", "prefix" },
740 { "", "", "test:arg1", "arg1" },
741 { "", "", "arg2", "arg2" },
742 { "", "", "test:ar3", "arg3" },
743 { NULL }
746 static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
747 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
748 { CH_STARTDOCUMENT, 1, 22, S_OK },
749 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
750 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
751 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
752 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
753 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
754 { CH_ENDDOCUMENT, 4, 0, S_OK },
755 { CH_ENDTEST }
758 static struct attribute_entry ch_attributes_alt_6[] = {
759 { "prefix_test", "arg1", "test:arg1", "arg1" },
760 { "", "arg2", "arg2", "arg2" },
761 { "prefix_test", "ar3", "test:ar3", "arg3" },
762 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
763 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
764 { NULL }
767 static struct attribute_entry ch_attributes2_6[] = {
768 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
769 { NULL }
772 static struct call_entry content_handler_test_attributes_alternate_6[] = {
773 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
774 { CH_STARTDOCUMENT, 1, 22, S_OK },
775 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
776 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
777 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
778 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
779 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
780 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
781 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
782 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
783 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
784 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
785 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
786 { CH_ENDDOCUMENT, 4, 0, S_OK },
787 { CH_ENDTEST }
790 /* 'namespaces' is on, 'namespace-prefixes' if off */
791 static struct attribute_entry ch_attributes_no_prefix[] = {
792 { "prefix_test", "arg1", "test:arg1", "arg1" },
793 { "", "arg2", "arg2", "arg2" },
794 { "prefix_test", "ar3", "test:ar3", "arg3" },
795 { NULL }
798 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
799 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
800 { CH_STARTDOCUMENT, 1, 22, S_OK },
801 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
802 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
803 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
804 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
805 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
806 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
807 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
808 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
809 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
810 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
811 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
812 { CH_ENDDOCUMENT, 4, 0, S_OK },
813 { CH_ENDTEST }
816 static struct call_entry content_handler_test_attributes_no_prefix[] = {
817 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
818 { CH_STARTDOCUMENT, 0, 0, S_OK },
819 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
820 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
821 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
822 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
823 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
824 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
825 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
826 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
827 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
828 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
829 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
830 { CH_ENDDOCUMENT, 0, 0 },
831 { CH_ENDTEST }
834 static struct attribute_entry xmlspace_attrs[] = {
835 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
836 { NULL }
839 static struct call_entry xmlspaceattr_test[] = {
840 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
841 { CH_STARTDOCUMENT, 0, 0, S_OK },
842 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
843 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
844 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
845 { CH_ENDDOCUMENT, 0, 0, S_OK },
846 { CH_ENDTEST }
849 static struct call_entry xmlspaceattr_test_alternate[] = {
850 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
851 { CH_STARTDOCUMENT, 1, 39, S_OK },
852 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
853 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
854 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
855 { CH_ENDDOCUMENT, 1, 83, S_OK },
856 { CH_ENDTEST }
859 static const char xmlspace_attr[] =
860 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
861 "<a xml:space=\"preserve\"> Some text data </a>";
863 static struct call_entry *expectCall;
864 static ISAXLocator *locator;
865 static ISAXXMLReader *g_reader;
866 int msxml_version;
868 static void set_expected_seq(struct call_entry *expected)
870 expectCall = expected;
873 /* to be called once on each tested callback return */
874 static HRESULT get_expected_ret(void)
876 HRESULT hr = expectCall->ret;
877 if (expectCall->id != CH_ENDTEST) expectCall++;
878 return hr;
881 static HRESULT WINAPI contentHandler_QueryInterface(
882 ISAXContentHandler* iface,
883 REFIID riid,
884 void **ppvObject)
886 *ppvObject = NULL;
888 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
890 *ppvObject = iface;
892 else
894 return E_NOINTERFACE;
897 return S_OK;
900 static ULONG WINAPI contentHandler_AddRef(
901 ISAXContentHandler* iface)
903 return 2;
906 static ULONG WINAPI contentHandler_Release(
907 ISAXContentHandler* iface)
909 return 1;
912 static HRESULT WINAPI contentHandler_putDocumentLocator(
913 ISAXContentHandler* iface,
914 ISAXLocator *pLocator)
916 struct call_entry call;
917 HRESULT hr;
919 locator = pLocator;
921 memset(&call, 0, sizeof(call));
922 init_call_entry(locator, &call);
923 call.id = CH_PUTDOCUMENTLOCATOR;
924 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
926 if (msxml_version >= 6) {
927 ISAXAttributes *attr, *attr1;
928 IMXAttributes *mxattr;
930 EXPECT_REF(pLocator, 1);
931 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
932 EXPECT_HR(hr, S_OK);
933 EXPECT_REF(pLocator, 2);
934 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
935 EXPECT_HR(hr, S_OK);
936 EXPECT_REF(pLocator, 3);
937 ok(attr == attr1, "got %p, %p\n", attr, attr1);
939 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
940 EXPECT_HR(hr, E_NOINTERFACE);
942 ISAXAttributes_Release(attr);
943 ISAXAttributes_Release(attr1);
946 return get_expected_ret();
949 static ISAXAttributes *test_attr_ptr;
950 static HRESULT WINAPI contentHandler_startDocument(
951 ISAXContentHandler* iface)
953 struct call_entry call;
955 init_call_entry(locator, &call);
956 call.id = CH_STARTDOCUMENT;
957 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
959 test_attr_ptr = NULL;
961 return get_expected_ret();
964 static HRESULT WINAPI contentHandler_endDocument(
965 ISAXContentHandler* iface)
967 struct call_entry call;
969 init_call_entry(locator, &call);
970 call.id = CH_ENDDOCUMENT;
971 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
973 return get_expected_ret();
976 static HRESULT WINAPI contentHandler_startPrefixMapping(
977 ISAXContentHandler* iface,
978 const WCHAR *prefix, int prefix_len,
979 const WCHAR *uri, int uri_len)
981 struct call_entry call;
983 init_call_entry(locator, &call);
984 call.id = CH_STARTPREFIXMAPPING;
985 call.arg1W = SysAllocStringLen(prefix, prefix_len);
986 call.arg2W = SysAllocStringLen(uri, uri_len);
987 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
989 return get_expected_ret();
992 static HRESULT WINAPI contentHandler_endPrefixMapping(
993 ISAXContentHandler* iface,
994 const WCHAR *prefix, int len)
996 struct call_entry call;
998 init_call_entry(locator, &call);
999 call.id = CH_ENDPREFIXMAPPING;
1000 call.arg1W = SysAllocStringLen(prefix, len);
1001 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1003 return get_expected_ret();
1006 static HRESULT WINAPI contentHandler_startElement(
1007 ISAXContentHandler* iface,
1008 const WCHAR *uri, int uri_len,
1009 const WCHAR *localname, int local_len,
1010 const WCHAR *qname, int qname_len,
1011 ISAXAttributes *saxattr)
1013 struct call_entry call;
1014 IMXAttributes *mxattr;
1015 HRESULT hr;
1016 int len;
1018 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1019 EXPECT_HR(hr, E_NOINTERFACE);
1021 init_call_entry(locator, &call);
1022 call.id = CH_STARTELEMENT;
1023 call.arg1W = SysAllocStringLen(uri, uri_len);
1024 call.arg2W = SysAllocStringLen(localname, local_len);
1025 call.arg3W = SysAllocStringLen(qname, qname_len);
1027 if(!test_attr_ptr)
1028 test_attr_ptr = saxattr;
1029 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1031 /* store actual attributes */
1032 len = 0;
1033 hr = ISAXAttributes_getLength(saxattr, &len);
1034 EXPECT_HR(hr, S_OK);
1036 if (len)
1038 VARIANT_BOOL v;
1039 int i;
1041 struct attribute_entry *attr;
1042 attr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(struct attribute_entry));
1044 v = VARIANT_TRUE;
1045 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1046 EXPECT_HR(hr, S_OK);
1048 for (i = 0; i < len; i++)
1050 const WCHAR *value;
1051 int value_len;
1053 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1054 &localname, &local_len, &qname, &qname_len);
1055 EXPECT_HR(hr, S_OK);
1057 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1058 EXPECT_HR(hr, S_OK);
1060 /* if 'namespaces' switched off uri and local name contains garbage */
1061 if (v == VARIANT_FALSE && msxml_version > 0)
1063 attr[i].uriW = SysAllocStringLen(NULL, 0);
1064 attr[i].localW = SysAllocStringLen(NULL, 0);
1066 else
1068 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1069 attr[i].localW = SysAllocStringLen(localname, local_len);
1072 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1073 attr[i].valueW = SysAllocStringLen(value, value_len);
1076 call.attributes = attr;
1077 call.attr_count = len;
1080 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1082 return get_expected_ret();
1085 static HRESULT WINAPI contentHandler_endElement(
1086 ISAXContentHandler* iface,
1087 const WCHAR *uri, int uri_len,
1088 const WCHAR *localname, int local_len,
1089 const WCHAR *qname, int qname_len)
1091 struct call_entry call;
1093 init_call_entry(locator, &call);
1094 call.id = CH_ENDELEMENT;
1095 call.arg1W = SysAllocStringLen(uri, uri_len);
1096 call.arg2W = SysAllocStringLen(localname, local_len);
1097 call.arg3W = SysAllocStringLen(qname, qname_len);
1098 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1100 return get_expected_ret();
1103 static HRESULT WINAPI contentHandler_characters(
1104 ISAXContentHandler* iface,
1105 const WCHAR *chars,
1106 int len)
1108 struct call_entry call;
1110 init_call_entry(locator, &call);
1111 call.id = CH_CHARACTERS;
1112 call.arg1W = SysAllocStringLen(chars, len);
1113 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1115 return get_expected_ret();
1118 static HRESULT WINAPI contentHandler_ignorableWhitespace(
1119 ISAXContentHandler* iface,
1120 const WCHAR *chars, int len)
1122 struct call_entry call;
1124 init_call_entry(locator, &call);
1125 call.id = CH_IGNORABLEWHITESPACE;
1126 call.arg1W = SysAllocStringLen(chars, len);
1127 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1129 return get_expected_ret();
1132 static HRESULT WINAPI contentHandler_processingInstruction(
1133 ISAXContentHandler* iface,
1134 const WCHAR *target, int target_len,
1135 const WCHAR *data, int data_len)
1137 struct call_entry call;
1139 init_call_entry(locator, &call);
1140 call.id = CH_PROCESSINGINSTRUCTION;
1141 call.arg1W = SysAllocStringLen(target, target_len);
1142 call.arg2W = SysAllocStringLen(data, data_len);
1143 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1145 return get_expected_ret();
1148 static HRESULT WINAPI contentHandler_skippedEntity(
1149 ISAXContentHandler* iface,
1150 const WCHAR *name, int len)
1152 struct call_entry call;
1154 init_call_entry(locator, &call);
1155 call.id = CH_SKIPPEDENTITY;
1156 call.arg1W = SysAllocStringLen(name, len);
1158 return get_expected_ret();
1161 static const ISAXContentHandlerVtbl contentHandlerVtbl =
1163 contentHandler_QueryInterface,
1164 contentHandler_AddRef,
1165 contentHandler_Release,
1166 contentHandler_putDocumentLocator,
1167 contentHandler_startDocument,
1168 contentHandler_endDocument,
1169 contentHandler_startPrefixMapping,
1170 contentHandler_endPrefixMapping,
1171 contentHandler_startElement,
1172 contentHandler_endElement,
1173 contentHandler_characters,
1174 contentHandler_ignorableWhitespace,
1175 contentHandler_processingInstruction,
1176 contentHandler_skippedEntity
1179 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1181 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
1182 ISAXErrorHandler* iface,
1183 REFIID riid,
1184 void **ppvObject)
1186 *ppvObject = NULL;
1188 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1190 *ppvObject = iface;
1192 else
1194 return E_NOINTERFACE;
1197 return S_OK;
1200 static ULONG WINAPI isaxerrorHandler_AddRef(
1201 ISAXErrorHandler* iface)
1203 return 2;
1206 static ULONG WINAPI isaxerrorHandler_Release(
1207 ISAXErrorHandler* iface)
1209 return 1;
1212 static HRESULT WINAPI isaxerrorHandler_error(
1213 ISAXErrorHandler* iface,
1214 ISAXLocator *pLocator,
1215 const WCHAR *pErrorMessage,
1216 HRESULT hrErrorCode)
1218 ok(0, "unexpected call\n");
1219 return S_OK;
1222 static HRESULT WINAPI isaxerrorHandler_fatalError(
1223 ISAXErrorHandler* iface,
1224 ISAXLocator *pLocator,
1225 const WCHAR *message,
1226 HRESULT hr)
1228 struct call_entry call;
1230 init_call_entry(locator, &call);
1231 call.id = EH_FATALERROR;
1232 call.ret = hr;
1234 add_call(sequences, CONTENT_HANDLER_INDEX, &call);
1236 get_expected_ret();
1237 return S_OK;
1240 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
1241 ISAXErrorHandler* iface,
1242 ISAXLocator *pLocator,
1243 const WCHAR *pErrorMessage,
1244 HRESULT hrErrorCode)
1246 ok(0, "unexpected call\n");
1247 return S_OK;
1250 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1252 isaxerrorHandler_QueryInterface,
1253 isaxerrorHandler_AddRef,
1254 isaxerrorHandler_Release,
1255 isaxerrorHandler_error,
1256 isaxerrorHandler_fatalError,
1257 isaxerrorHanddler_ignorableWarning
1260 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1262 static HRESULT WINAPI isaxattributes_QueryInterface(
1263 ISAXAttributes* iface,
1264 REFIID riid,
1265 void **ppvObject)
1267 *ppvObject = NULL;
1269 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1271 *ppvObject = iface;
1273 else
1275 return E_NOINTERFACE;
1278 return S_OK;
1281 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1283 return 2;
1286 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1288 return 1;
1291 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1293 *length = 3;
1294 return S_OK;
1297 static HRESULT WINAPI isaxattributes_getURI(
1298 ISAXAttributes* iface,
1299 int nIndex,
1300 const WCHAR **pUrl,
1301 int *pUriSize)
1303 ok(0, "unexpected call\n");
1304 return E_NOTIMPL;
1307 static HRESULT WINAPI isaxattributes_getLocalName(
1308 ISAXAttributes* iface,
1309 int nIndex,
1310 const WCHAR **pLocalName,
1311 int *pLocalNameLength)
1313 ok(0, "unexpected call\n");
1314 return E_NOTIMPL;
1317 static HRESULT WINAPI isaxattributes_getQName(
1318 ISAXAttributes* iface,
1319 int index,
1320 const WCHAR **QName,
1321 int *QNameLength)
1323 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1324 {'a','t','t','r','2','j','u','n','k',0},
1325 {'a','t','t','r','3',0}};
1326 static const int attrqnamelen[] = {7, 5, 5};
1328 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1330 *QName = attrqnamesW[index];
1331 *QNameLength = attrqnamelen[index];
1333 return S_OK;
1336 static HRESULT WINAPI isaxattributes_getName(
1337 ISAXAttributes* iface,
1338 int nIndex,
1339 const WCHAR **pUri,
1340 int * pUriLength,
1341 const WCHAR ** pLocalName,
1342 int * pLocalNameSize,
1343 const WCHAR ** pQName,
1344 int * pQNameLength)
1346 ok(0, "unexpected call\n");
1347 return E_NOTIMPL;
1350 static HRESULT WINAPI isaxattributes_getIndexFromName(
1351 ISAXAttributes* iface,
1352 const WCHAR * pUri,
1353 int cUriLength,
1354 const WCHAR * pLocalName,
1355 int cocalNameLength,
1356 int * index)
1358 ok(0, "unexpected call\n");
1359 return E_NOTIMPL;
1362 static HRESULT WINAPI isaxattributes_getIndexFromQName(
1363 ISAXAttributes* iface,
1364 const WCHAR * pQName,
1365 int nQNameLength,
1366 int * index)
1368 ok(0, "unexpected call\n");
1369 return E_NOTIMPL;
1372 static HRESULT WINAPI isaxattributes_getType(
1373 ISAXAttributes* iface,
1374 int nIndex,
1375 const WCHAR ** pType,
1376 int * pTypeLength)
1378 ok(0, "unexpected call\n");
1379 return E_NOTIMPL;
1382 static HRESULT WINAPI isaxattributes_getTypeFromName(
1383 ISAXAttributes* iface,
1384 const WCHAR * pUri,
1385 int nUri,
1386 const WCHAR * pLocalName,
1387 int nLocalName,
1388 const WCHAR ** pType,
1389 int * nType)
1391 ok(0, "unexpected call\n");
1392 return E_NOTIMPL;
1395 static HRESULT WINAPI isaxattributes_getTypeFromQName(
1396 ISAXAttributes* iface,
1397 const WCHAR * pQName,
1398 int nQName,
1399 const WCHAR ** pType,
1400 int * nType)
1402 ok(0, "unexpected call\n");
1403 return E_NOTIMPL;
1406 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1407 const WCHAR **value, int *nValue)
1409 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1410 {'a','2','j','u','n','k',0},
1411 {'<','&','"','>',0}};
1412 static const int attrvalueslen[] = {2, 2, 4};
1414 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1416 *value = attrvaluesW[index];
1417 *nValue = attrvalueslen[index];
1419 return S_OK;
1422 static HRESULT WINAPI isaxattributes_getValueFromName(
1423 ISAXAttributes* iface,
1424 const WCHAR * pUri,
1425 int nUri,
1426 const WCHAR * pLocalName,
1427 int nLocalName,
1428 const WCHAR ** pValue,
1429 int * nValue)
1431 ok(0, "unexpected call\n");
1432 return E_NOTIMPL;
1435 static HRESULT WINAPI isaxattributes_getValueFromQName(
1436 ISAXAttributes* iface,
1437 const WCHAR * pQName,
1438 int nQName,
1439 const WCHAR ** pValue,
1440 int * nValue)
1442 ok(0, "unexpected call\n");
1443 return E_NOTIMPL;
1446 static const ISAXAttributesVtbl SAXAttributesVtbl =
1448 isaxattributes_QueryInterface,
1449 isaxattributes_AddRef,
1450 isaxattributes_Release,
1451 isaxattributes_getLength,
1452 isaxattributes_getURI,
1453 isaxattributes_getLocalName,
1454 isaxattributes_getQName,
1455 isaxattributes_getName,
1456 isaxattributes_getIndexFromName,
1457 isaxattributes_getIndexFromQName,
1458 isaxattributes_getType,
1459 isaxattributes_getTypeFromName,
1460 isaxattributes_getTypeFromQName,
1461 isaxattributes_getValue,
1462 isaxattributes_getValueFromName,
1463 isaxattributes_getValueFromQName
1466 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1468 static int handler_addrefcalled;
1470 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **ppvObject)
1472 *ppvObject = NULL;
1474 if(IsEqualGUID(riid, &IID_IUnknown) ||
1475 IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1477 *ppvObject = iface;
1479 else
1481 return E_NOINTERFACE;
1484 return S_OK;
1487 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1489 handler_addrefcalled++;
1490 return 2;
1493 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1495 return 1;
1498 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1499 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1500 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1502 ok(0, "call not expected\n");
1503 return E_NOTIMPL;
1506 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1508 ok(0, "call not expected\n");
1509 return E_NOTIMPL;
1512 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1513 const WCHAR * pName, int nName)
1515 ok(0, "call not expected\n");
1516 return E_NOTIMPL;
1519 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1520 const WCHAR * pName, int nName)
1522 ok(0, "call not expected\n");
1523 return E_NOTIMPL;
1526 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1528 ok(0, "call not expected\n");
1529 return E_NOTIMPL;
1532 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1534 ok(0, "call not expected\n");
1535 return E_NOTIMPL;
1538 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1539 const WCHAR * pChars, int nChars)
1541 ok(0, "call not expected\n");
1542 return E_NOTIMPL;
1545 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1547 isaxlexical_QueryInterface,
1548 isaxlexical_AddRef,
1549 isaxlexical_Release,
1550 isaxlexical_startDTD,
1551 isaxlexical_endDTD,
1552 isaxlexical_startEntity,
1553 isaxlexical_endEntity,
1554 isaxlexical_startCDATA,
1555 isaxlexical_endCDATA,
1556 isaxlexical_comment
1559 static ISAXLexicalHandler saxlexicalhandler = { &SAXLexicalHandlerVtbl };
1561 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **ppvObject)
1563 *ppvObject = NULL;
1565 if(IsEqualGUID(riid, &IID_IUnknown) ||
1566 IsEqualGUID(riid, &IID_ISAXDeclHandler))
1568 *ppvObject = iface;
1570 else
1572 return E_NOINTERFACE;
1575 return S_OK;
1578 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1580 handler_addrefcalled++;
1581 return 2;
1584 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1586 return 1;
1589 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1590 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1592 ok(0, "call not expected\n");
1593 return E_NOTIMPL;
1596 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1597 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1598 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1599 int nValueDefault, const WCHAR * pValue, int nValue)
1601 ok(0, "call not expected\n");
1602 return E_NOTIMPL;
1605 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1606 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1608 ok(0, "call not expected\n");
1609 return E_NOTIMPL;
1612 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1613 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1614 const WCHAR * pSystemId, int nSystemId)
1616 ok(0, "call not expected\n");
1617 return E_NOTIMPL;
1620 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1622 isaxdecl_QueryInterface,
1623 isaxdecl_AddRef,
1624 isaxdecl_Release,
1625 isaxdecl_elementDecl,
1626 isaxdecl_attributeDecl,
1627 isaxdecl_internalEntityDecl,
1628 isaxdecl_externalEntityDecl
1631 static ISAXDeclHandler saxdeclhandler = { &SAXDeclHandlerVtbl };
1633 typedef struct mxwriter_write_test_t {
1634 BOOL last;
1635 const BYTE *data;
1636 DWORD cb;
1637 BOOL null_written;
1638 BOOL fail_write;
1639 } mxwriter_write_test;
1641 typedef struct mxwriter_stream_test_t {
1642 VARIANT_BOOL bom;
1643 const char *encoding;
1644 mxwriter_write_test expected_writes[4];
1645 } mxwriter_stream_test;
1647 static const mxwriter_write_test *current_write_test;
1648 static DWORD current_stream_test_index;
1650 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1652 *ppvObject = NULL;
1654 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1655 *ppvObject = iface;
1656 else
1657 return E_NOINTERFACE;
1659 return S_OK;
1662 static ULONG WINAPI istream_AddRef(IStream *iface)
1664 return 2;
1667 static ULONG WINAPI istream_Release(IStream *iface)
1669 return 1;
1672 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1674 ok(0, "unexpected call\n");
1675 return E_NOTIMPL;
1678 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1680 BOOL fail = FALSE;
1682 ok(pv != NULL, "pv == NULL\n");
1684 if(current_write_test->last) {
1685 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1686 return E_FAIL;
1689 fail = current_write_test->fail_write;
1691 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1692 current_write_test->cb, cb, current_stream_test_index);
1694 if(!pcbWritten)
1695 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1696 else
1697 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1699 ++current_write_test;
1701 if(pcbWritten)
1702 *pcbWritten = cb;
1704 return fail ? E_FAIL : S_OK;
1707 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1708 ULARGE_INTEGER *plibNewPosition)
1710 ok(0, "unexpected call\n");
1711 return E_NOTIMPL;
1714 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1716 ok(0, "unexpected call\n");
1717 return E_NOTIMPL;
1720 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1721 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1723 ok(0, "unexpected call\n");
1724 return E_NOTIMPL;
1727 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1729 ok(0, "unexpected call\n");
1730 return E_NOTIMPL;
1733 static HRESULT WINAPI istream_Revert(IStream *iface)
1735 ok(0, "unexpected call\n");
1736 return E_NOTIMPL;
1739 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1740 ULARGE_INTEGER cb, DWORD dwLockType)
1742 ok(0, "unexpected call\n");
1743 return E_NOTIMPL;
1746 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1747 ULARGE_INTEGER cb, DWORD dwLockType)
1749 ok(0, "unexpected call\n");
1750 return E_NOTIMPL;
1753 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1755 ok(0, "unexpected call\n");
1756 return E_NOTIMPL;
1759 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1761 ok(0, "unexpected call\n");
1762 return E_NOTIMPL;
1765 static const IStreamVtbl StreamVtbl = {
1766 istream_QueryInterface,
1767 istream_AddRef,
1768 istream_Release,
1769 istream_Read,
1770 istream_Write,
1771 istream_Seek,
1772 istream_SetSize,
1773 istream_CopyTo,
1774 istream_Commit,
1775 istream_Revert,
1776 istream_LockRegion,
1777 istream_UnlockRegion,
1778 istream_Stat,
1779 istream_Clone
1782 static IStream mxstream = { &StreamVtbl };
1784 static struct msxmlsupported_data_t reader_support_data[] =
1786 { &CLSID_SAXXMLReader, "SAXReader" },
1787 { &CLSID_SAXXMLReader30, "SAXReader30" },
1788 { &CLSID_SAXXMLReader40, "SAXReader40" },
1789 { &CLSID_SAXXMLReader60, "SAXReader60" },
1790 { NULL }
1793 static void test_saxreader(void)
1795 const struct msxmlsupported_data_t *table = reader_support_data;
1796 HRESULT hr;
1797 ISAXXMLReader *reader = NULL;
1798 VARIANT var;
1799 ISAXContentHandler *content;
1800 ISAXErrorHandler *lpErrorHandler;
1801 SAFEARRAY *sa;
1802 SAFEARRAYBOUND SADim[1];
1803 char *ptr = NULL;
1804 IStream *stream;
1805 ULARGE_INTEGER size;
1806 LARGE_INTEGER pos;
1807 ULONG written;
1808 HANDLE file;
1809 static const CHAR testXmlA[] = "test.xml";
1810 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1811 IXMLDOMDocument *doc;
1812 VARIANT_BOOL v;
1814 while (table->clsid)
1816 struct call_entry *test_seq;
1817 BSTR str;
1819 if (!is_clsid_supported(table->clsid, reader_support_data))
1821 table++;
1822 continue;
1825 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1826 EXPECT_HR(hr, S_OK);
1827 g_reader = reader;
1829 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1830 msxml_version = 4;
1831 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1832 msxml_version = 6;
1833 else
1834 msxml_version = 0;
1836 /* crashes on old versions */
1837 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
1838 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1840 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1841 EXPECT_HR(hr, E_POINTER);
1843 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1844 EXPECT_HR(hr, E_POINTER);
1847 hr = ISAXXMLReader_getContentHandler(reader, &content);
1848 EXPECT_HR(hr, S_OK);
1849 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
1851 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1852 EXPECT_HR(hr, S_OK);
1853 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1855 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1856 EXPECT_HR(hr, S_OK);
1858 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1859 EXPECT_HR(hr, S_OK);
1861 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1862 EXPECT_HR(hr, S_OK);
1864 hr = ISAXXMLReader_getContentHandler(reader, &content);
1865 EXPECT_HR(hr, S_OK);
1866 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
1868 V_VT(&var) = VT_BSTR;
1869 V_BSTR(&var) = SysAllocString(szSimpleXML);
1871 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1872 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1873 test_seq = content_handler_test1_alternate;
1874 else
1875 test_seq = content_handler_test1;
1876 set_expected_seq(test_seq);
1877 hr = ISAXXMLReader_parse(reader, var);
1878 EXPECT_HR(hr, S_OK);
1879 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
1881 VariantClear(&var);
1883 SADim[0].lLbound = 0;
1884 SADim[0].cElements = sizeof(testXML)-1;
1885 sa = SafeArrayCreate(VT_UI1, 1, SADim);
1886 SafeArrayAccessData(sa, (void**)&ptr);
1887 memcpy(ptr, testXML, sizeof(testXML)-1);
1888 SafeArrayUnaccessData(sa);
1889 V_VT(&var) = VT_ARRAY|VT_UI1;
1890 V_ARRAY(&var) = sa;
1892 set_expected_seq(test_seq);
1893 hr = ISAXXMLReader_parse(reader, var);
1894 EXPECT_HR(hr, S_OK);
1895 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
1897 SafeArrayDestroy(sa);
1899 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1900 size.QuadPart = strlen(testXML);
1901 IStream_SetSize(stream, size);
1902 IStream_Write(stream, testXML, strlen(testXML), &written);
1903 pos.QuadPart = 0;
1904 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1905 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1906 V_UNKNOWN(&var) = (IUnknown*)stream;
1908 set_expected_seq(test_seq);
1909 hr = ISAXXMLReader_parse(reader, var);
1910 EXPECT_HR(hr, S_OK);
1911 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
1913 IStream_Release(stream);
1915 CreateStreamOnHGlobal(NULL, TRUE, &stream);
1916 size.QuadPart = strlen(test_attributes);
1917 IStream_SetSize(stream, size);
1918 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
1919 pos.QuadPart = 0;
1920 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1921 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1922 V_UNKNOWN(&var) = (IUnknown*)stream;
1924 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
1925 test_seq = content_handler_test_attributes_alternate_4;
1926 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1927 test_seq = content_handler_test_attributes_alternate_6;
1928 else
1929 test_seq = content_handler_test_attributes;
1931 set_expected_seq(test_seq);
1932 hr = ISAXXMLReader_parse(reader, var);
1933 EXPECT_HR(hr, S_OK);
1935 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1936 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1937 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
1938 else
1939 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
1941 IStream_Release(stream);
1943 V_VT(&var) = VT_BSTR;
1944 V_BSTR(&var) = SysAllocString(carriage_ret_test);
1946 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1947 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1948 test_seq = content_handler_test2_alternate;
1949 else
1950 test_seq = content_handler_test2;
1952 set_expected_seq(test_seq);
1953 hr = ISAXXMLReader_parse(reader, var);
1954 EXPECT_HR(hr, S_OK);
1955 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
1957 VariantClear(&var);
1959 /* from file url */
1960 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1961 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
1962 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
1963 CloseHandle(file);
1965 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1966 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1967 test_seq = content_handler_test1_alternate;
1968 else
1969 test_seq = content_handler_test1;
1970 set_expected_seq(test_seq);
1971 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1972 EXPECT_HR(hr, S_OK);
1973 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
1975 /* error handler */
1976 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1977 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1978 test_seq = content_handler_testerror_alternate;
1979 else
1980 test_seq = content_handler_testerror;
1981 set_expected_seq(test_seq);
1982 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1983 EXPECT_HR(hr, E_FAIL);
1984 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
1986 /* callback ret values */
1987 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
1988 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
1990 test_seq = content_handler_test_callback_rets_alt;
1991 set_expected_seq(test_seq);
1992 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1993 EXPECT_HR(hr, S_OK);
1995 else
1997 test_seq = content_handler_test_callback_rets;
1998 set_expected_seq(test_seq);
1999 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2000 EXPECT_HR(hr, S_FALSE);
2002 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2004 DeleteFileA(testXmlA);
2006 /* parse from IXMLDOMDocument */
2007 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2008 &IID_IXMLDOMDocument, (void**)&doc);
2009 EXPECT_HR(hr, S_OK);
2011 str = SysAllocString(szSimpleXML);
2012 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2013 EXPECT_HR(hr, S_OK);
2014 SysFreeString(str);
2016 V_VT(&var) = VT_UNKNOWN;
2017 V_UNKNOWN(&var) = (IUnknown*)doc;
2019 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2020 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2021 test_seq = content_handler_test2_alternate;
2022 else
2023 test_seq = content_handler_test2;
2025 set_expected_seq(test_seq);
2026 hr = ISAXXMLReader_parse(reader, var);
2027 EXPECT_HR(hr, S_OK);
2028 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2029 IXMLDOMDocument_Release(doc);
2031 /* xml:space test */
2032 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2033 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2035 test_seq = xmlspaceattr_test_alternate;
2037 else
2038 test_seq = xmlspaceattr_test;
2040 set_expected_seq(test_seq);
2041 V_VT(&var) = VT_BSTR;
2042 V_BSTR(&var) = _bstr_(xmlspace_attr);
2043 hr = ISAXXMLReader_parse(reader, var);
2044 EXPECT_HR(hr, S_OK);
2046 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2047 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2049 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2051 else
2052 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2054 /* switch off 'namespaces' feature */
2055 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2056 EXPECT_HR(hr, S_OK);
2058 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2059 size.QuadPart = strlen(test_attributes);
2060 IStream_SetSize(stream, size);
2061 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2062 pos.QuadPart = 0;
2063 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2064 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
2065 V_UNKNOWN(&var) = (IUnknown*)stream;
2067 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2068 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2070 test_seq = content_handler_test_attributes_alt_no_ns;
2072 else
2073 test_seq = content_handler_test_attributes;
2075 set_expected_seq(test_seq);
2076 hr = ISAXXMLReader_parse(reader, var);
2077 EXPECT_HR(hr, S_OK);
2078 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2079 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2080 EXPECT_HR(hr, S_OK);
2082 /* switch off 'namespace-prefixes' feature */
2083 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2084 EXPECT_HR(hr, S_OK);
2086 CreateStreamOnHGlobal(NULL, TRUE, &stream);
2087 size.QuadPart = strlen(test_attributes);
2088 IStream_SetSize(stream, size);
2089 IStream_Write(stream, test_attributes, strlen(test_attributes), &written);
2090 pos.QuadPart = 0;
2091 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2092 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
2093 V_UNKNOWN(&var) = (IUnknown*)stream;
2095 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2096 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2098 test_seq = content_handler_test_attributes_alt_no_prefix;
2100 else
2101 test_seq = content_handler_test_attributes_no_prefix;
2103 set_expected_seq(test_seq);
2104 hr = ISAXXMLReader_parse(reader, var);
2105 EXPECT_HR(hr, S_OK);
2106 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2108 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2109 EXPECT_HR(hr, S_OK);
2111 ISAXXMLReader_Release(reader);
2112 table++;
2115 free_bstrs();
2118 struct saxreader_props_test_t
2120 const char *prop_name;
2121 IUnknown *iface;
2124 static const struct saxreader_props_test_t props_test_data[] = {
2125 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&saxlexicalhandler },
2126 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&saxdeclhandler },
2127 { 0 }
2130 static void test_saxreader_properties(void)
2132 const struct saxreader_props_test_t *ptr = props_test_data;
2133 ISAXXMLReader *reader;
2134 HRESULT hr;
2136 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2137 &IID_ISAXXMLReader, (void**)&reader);
2138 EXPECT_HR(hr, S_OK);
2140 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2141 EXPECT_HR(hr, E_POINTER);
2143 while (ptr->prop_name)
2145 VARIANT v;
2147 V_VT(&v) = VT_EMPTY;
2148 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2149 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2150 EXPECT_HR(hr, S_OK);
2151 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2152 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2154 V_VT(&v) = VT_UNKNOWN;
2155 V_UNKNOWN(&v) = ptr->iface;
2156 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2157 EXPECT_HR(hr, S_OK);
2159 V_VT(&v) = VT_EMPTY;
2160 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2161 handler_addrefcalled = 0;
2162 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2163 EXPECT_HR(hr, S_OK);
2164 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2165 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2166 ok(handler_addrefcalled == 1, "AddRef called %d times\n", handler_addrefcalled);
2167 VariantClear(&v);
2169 V_VT(&v) = VT_EMPTY;
2170 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2171 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2172 EXPECT_HR(hr, S_OK);
2174 V_VT(&v) = VT_EMPTY;
2175 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2176 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2177 EXPECT_HR(hr, S_OK);
2178 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2179 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2181 V_VT(&v) = VT_UNKNOWN;
2182 V_UNKNOWN(&v) = ptr->iface;
2183 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2184 EXPECT_HR(hr, S_OK);
2186 /* only VT_EMPTY seems to be valid to reset property */
2187 V_VT(&v) = VT_I4;
2188 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2189 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2190 EXPECT_HR(hr, E_INVALIDARG);
2192 V_VT(&v) = VT_EMPTY;
2193 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2194 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2195 EXPECT_HR(hr, S_OK);
2196 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2197 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2198 VariantClear(&v);
2200 V_VT(&v) = VT_UNKNOWN;
2201 V_UNKNOWN(&v) = NULL;
2202 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2203 EXPECT_HR(hr, S_OK);
2205 V_VT(&v) = VT_EMPTY;
2206 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2207 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2208 EXPECT_HR(hr, S_OK);
2209 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2210 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2212 ptr++;
2215 ISAXXMLReader_Release(reader);
2216 free_bstrs();
2219 struct feature_ns_entry_t {
2220 const GUID *guid;
2221 const char *clsid;
2222 VARIANT_BOOL value;
2223 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2226 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
2227 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2228 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2229 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2230 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2231 { 0 }
2234 static const char *feature_names[] = {
2235 "http://xml.org/sax/features/namespaces",
2236 "http://xml.org/sax/features/namespace-prefixes",
2240 static void test_saxreader_features(void)
2242 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
2243 ISAXXMLReader *reader;
2245 while (entry->guid)
2247 VARIANT_BOOL value;
2248 const char **name;
2249 HRESULT hr;
2251 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2252 if (hr != S_OK)
2254 win_skip("can't create %s instance\n", entry->clsid);
2255 entry++;
2256 continue;
2259 name = feature_names;
2260 while (*name)
2262 value = 0xc;
2263 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2264 EXPECT_HR(hr, S_OK);
2265 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2267 value = 0xc;
2268 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2269 EXPECT_HR(hr, S_OK);
2271 value = 0xd;
2272 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2273 EXPECT_HR(hr, S_OK);
2274 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2276 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2277 EXPECT_HR(hr, S_OK);
2278 value = 0xd;
2279 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2280 EXPECT_HR(hr, S_OK);
2281 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2283 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2284 EXPECT_HR(hr, S_OK);
2285 value = 0xd;
2286 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2287 EXPECT_HR(hr, S_OK);
2288 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2290 name++;
2293 ISAXXMLReader_Release(reader);
2295 entry++;
2299 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2300 static const CHAR UTF8BOMTest[] =
2301 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2302 "<a></a>\n";
2304 struct enc_test_entry_t {
2305 const GUID *guid;
2306 const char *clsid;
2307 const char *data;
2308 HRESULT hr;
2309 int todo;
2312 static const struct enc_test_entry_t encoding_test_data[] = {
2313 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
2314 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
2315 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
2316 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
2317 { 0 }
2320 static void test_saxreader_encoding(void)
2322 const struct enc_test_entry_t *entry = encoding_test_data;
2323 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2324 static const CHAR testXmlA[] = "test.xml";
2326 while (entry->guid)
2328 ISAXXMLReader *reader;
2329 VARIANT input;
2330 DWORD written;
2331 HANDLE file;
2332 HRESULT hr;
2334 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2335 if (hr != S_OK)
2337 win_skip("can't create %s instance\n", entry->clsid);
2338 entry++;
2339 continue;
2342 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2343 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2344 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2345 CloseHandle(file);
2347 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2348 if (entry->todo)
2349 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2350 else
2351 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2353 DeleteFileA(testXmlA);
2355 /* try BSTR input with no BOM or '<?xml' instruction */
2356 V_VT(&input) = VT_BSTR;
2357 V_BSTR(&input) = _bstr_("<element></element>");
2358 hr = ISAXXMLReader_parse(reader, input);
2359 EXPECT_HR(hr, S_OK);
2361 ISAXXMLReader_Release(reader);
2363 free_bstrs();
2364 entry++;
2368 static void test_mxwriter_handlers(void)
2370 ISAXContentHandler *handler;
2371 IMXWriter *writer, *writer2;
2372 ISAXDeclHandler *decl;
2373 ISAXLexicalHandler *lh;
2374 HRESULT hr;
2376 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2377 &IID_IMXWriter, (void**)&writer);
2378 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2380 EXPECT_REF(writer, 1);
2382 /* ISAXContentHandler */
2383 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
2384 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2385 EXPECT_REF(writer, 2);
2386 EXPECT_REF(handler, 2);
2388 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2389 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2390 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2391 EXPECT_REF(writer, 3);
2392 EXPECT_REF(writer2, 3);
2393 IMXWriter_Release(writer2);
2394 ISAXContentHandler_Release(handler);
2396 /* ISAXLexicalHandler */
2397 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lh);
2398 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2399 EXPECT_REF(writer, 2);
2400 EXPECT_REF(lh, 2);
2402 hr = ISAXLexicalHandler_QueryInterface(lh, &IID_IMXWriter, (void**)&writer2);
2403 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2404 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2405 EXPECT_REF(writer, 3);
2406 EXPECT_REF(writer2, 3);
2407 IMXWriter_Release(writer2);
2408 ISAXLexicalHandler_Release(lh);
2410 /* ISAXDeclHandler */
2411 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
2412 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2413 EXPECT_REF(writer, 2);
2414 EXPECT_REF(lh, 2);
2416 hr = ISAXDeclHandler_QueryInterface(decl, &IID_IMXWriter, (void**)&writer2);
2417 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2418 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2419 EXPECT_REF(writer, 3);
2420 EXPECT_REF(writer2, 3);
2421 IMXWriter_Release(writer2);
2422 ISAXDeclHandler_Release(decl);
2424 IMXWriter_Release(writer);
2428 static struct msxmlsupported_data_t mxwriter_support_data[] =
2430 { &CLSID_MXXMLWriter, "MXXMLWriter" },
2431 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
2432 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
2433 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
2434 { NULL }
2437 static struct msxmlsupported_data_t mxattributes_support_data[] =
2439 { &CLSID_SAXAttributes, "SAXAttributes" },
2440 { &CLSID_SAXAttributes30, "SAXAttributes30" },
2441 { &CLSID_SAXAttributes40, "SAXAttributes40" },
2442 { &CLSID_SAXAttributes60, "SAXAttributes60" },
2443 { NULL }
2446 struct mxwriter_props_t
2448 const GUID *clsid;
2449 VARIANT_BOOL bom;
2450 VARIANT_BOOL disable_escape;
2451 VARIANT_BOOL indent;
2452 VARIANT_BOOL omitdecl;
2453 VARIANT_BOOL standalone;
2454 const char *encoding;
2457 static const struct mxwriter_props_t mxwriter_default_props[] =
2459 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2460 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2461 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2462 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
2463 { NULL }
2466 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
2468 int i = 0;
2470 while (table->clsid)
2472 IMXWriter *writer;
2473 VARIANT_BOOL b;
2474 BSTR encoding;
2475 HRESULT hr;
2477 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2479 table++;
2480 i++;
2481 continue;
2484 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2485 &IID_IMXWriter, (void**)&writer);
2486 EXPECT_HR(hr, S_OK);
2488 b = !table->bom;
2489 hr = IMXWriter_get_byteOrderMark(writer, &b);
2490 EXPECT_HR(hr, S_OK);
2491 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
2493 b = !table->disable_escape;
2494 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
2495 EXPECT_HR(hr, S_OK);
2496 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
2497 table->disable_escape);
2499 b = !table->indent;
2500 hr = IMXWriter_get_indent(writer, &b);
2501 EXPECT_HR(hr, S_OK);
2502 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
2504 b = !table->omitdecl;
2505 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
2506 EXPECT_HR(hr, S_OK);
2507 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
2509 b = !table->standalone;
2510 hr = IMXWriter_get_standalone(writer, &b);
2511 EXPECT_HR(hr, S_OK);
2512 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
2514 hr = IMXWriter_get_encoding(writer, &encoding);
2515 EXPECT_HR(hr, S_OK);
2516 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
2517 i, wine_dbgstr_w(encoding), table->encoding);
2518 SysFreeString(encoding);
2520 IMXWriter_Release(writer);
2522 table++;
2523 i++;
2527 static void test_mxwriter_properties(void)
2529 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
2530 static const WCHAR emptyW[] = {0};
2531 static const WCHAR testW[] = {'t','e','s','t',0};
2532 ISAXContentHandler *content;
2533 IMXWriter *writer;
2534 VARIANT_BOOL b;
2535 HRESULT hr;
2536 BSTR str, str2;
2537 VARIANT dest;
2539 test_mxwriter_default_properties(mxwriter_default_props);
2541 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2542 &IID_IMXWriter, (void**)&writer);
2543 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2545 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
2546 ok(hr == E_POINTER, "got %08x\n", hr);
2548 hr = IMXWriter_get_byteOrderMark(writer, NULL);
2549 ok(hr == E_POINTER, "got %08x\n", hr);
2551 hr = IMXWriter_get_indent(writer, NULL);
2552 ok(hr == E_POINTER, "got %08x\n", hr);
2554 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
2555 ok(hr == E_POINTER, "got %08x\n", hr);
2557 hr = IMXWriter_get_standalone(writer, NULL);
2558 ok(hr == E_POINTER, "got %08x\n", hr);
2560 /* set and check */
2561 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
2562 ok(hr == S_OK, "got %08x\n", hr);
2564 b = VARIANT_FALSE;
2565 hr = IMXWriter_get_standalone(writer, &b);
2566 ok(hr == S_OK, "got %08x\n", hr);
2567 ok(b == VARIANT_TRUE, "got %d\n", b);
2569 hr = IMXWriter_get_encoding(writer, NULL);
2570 EXPECT_HR(hr, E_POINTER);
2572 /* UTF-16 is a default setting apparently */
2573 str = (void*)0xdeadbeef;
2574 hr = IMXWriter_get_encoding(writer, &str);
2575 EXPECT_HR(hr, S_OK);
2576 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
2578 str2 = (void*)0xdeadbeef;
2579 hr = IMXWriter_get_encoding(writer, &str2);
2580 ok(hr == S_OK, "got %08x\n", hr);
2581 ok(str != str2, "expected newly allocated, got same %p\n", str);
2583 SysFreeString(str2);
2584 SysFreeString(str);
2586 /* put empty string */
2587 str = SysAllocString(emptyW);
2588 hr = IMXWriter_put_encoding(writer, str);
2589 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2590 SysFreeString(str);
2592 str = (void*)0xdeadbeef;
2593 hr = IMXWriter_get_encoding(writer, &str);
2594 EXPECT_HR(hr, S_OK);
2595 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
2596 SysFreeString(str);
2598 /* invalid encoding name */
2599 str = SysAllocString(testW);
2600 hr = IMXWriter_put_encoding(writer, str);
2601 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2602 SysFreeString(str);
2604 /* test case sensivity */
2605 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
2606 EXPECT_HR(hr, S_OK);
2607 str = (void*)0xdeadbeef;
2608 hr = IMXWriter_get_encoding(writer, &str);
2609 EXPECT_HR(hr, S_OK);
2610 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
2611 SysFreeString(str);
2613 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
2614 EXPECT_HR(hr, S_OK);
2615 str = (void*)0xdeadbeef;
2616 hr = IMXWriter_get_encoding(writer, &str);
2617 EXPECT_HR(hr, S_OK);
2618 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
2619 SysFreeString(str);
2621 /* how it affects document creation */
2622 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2623 EXPECT_HR(hr, S_OK);
2625 hr = ISAXContentHandler_startDocument(content);
2626 EXPECT_HR(hr, S_OK);
2627 hr = ISAXContentHandler_endDocument(content);
2628 EXPECT_HR(hr, S_OK);
2630 V_VT(&dest) = VT_EMPTY;
2631 hr = IMXWriter_get_output(writer, &dest);
2632 EXPECT_HR(hr, S_OK);
2633 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2634 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
2635 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2636 VariantClear(&dest);
2637 ISAXContentHandler_Release(content);
2639 hr = IMXWriter_get_version(writer, NULL);
2640 ok(hr == E_POINTER, "got %08x\n", hr);
2641 /* default version is 'surprisingly' 1.0 */
2642 hr = IMXWriter_get_version(writer, &str);
2643 ok(hr == S_OK, "got %08x\n", hr);
2644 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
2645 SysFreeString(str);
2647 /* store version string as is */
2648 hr = IMXWriter_put_version(writer, NULL);
2649 ok(hr == E_INVALIDARG, "got %08x\n", hr);
2651 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
2652 ok(hr == S_OK, "got %08x\n", hr);
2654 hr = IMXWriter_put_version(writer, _bstr_(""));
2655 ok(hr == S_OK, "got %08x\n", hr);
2656 hr = IMXWriter_get_version(writer, &str);
2657 ok(hr == S_OK, "got %08x\n", hr);
2658 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
2659 SysFreeString(str);
2661 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
2662 ok(hr == S_OK, "got %08x\n", hr);
2663 hr = IMXWriter_get_version(writer, &str);
2664 ok(hr == S_OK, "got %08x\n", hr);
2665 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
2666 SysFreeString(str);
2668 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
2669 ok(hr == S_OK, "got %08x\n", hr);
2670 hr = IMXWriter_get_version(writer, &str);
2671 ok(hr == S_OK, "got %08x\n", hr);
2672 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
2673 SysFreeString(str);
2675 IMXWriter_Release(writer);
2676 free_bstrs();
2679 static void test_mxwriter_flush(void)
2681 ISAXContentHandler *content;
2682 IMXWriter *writer;
2683 LARGE_INTEGER pos;
2684 ULARGE_INTEGER pos2;
2685 IStream *stream;
2686 VARIANT dest;
2687 HRESULT hr;
2689 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2690 &IID_IMXWriter, (void**)&writer);
2691 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2693 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2694 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2695 EXPECT_REF(stream, 1);
2697 /* detach when nothing was attached */
2698 V_VT(&dest) = VT_EMPTY;
2699 hr = IMXWriter_put_output(writer, dest);
2700 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2702 /* attach stream */
2703 V_VT(&dest) = VT_UNKNOWN;
2704 V_UNKNOWN(&dest) = (IUnknown*)stream;
2705 hr = IMXWriter_put_output(writer, dest);
2706 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2707 todo_wine EXPECT_REF(stream, 3);
2709 /* detach setting VT_EMPTY destination */
2710 V_VT(&dest) = VT_EMPTY;
2711 hr = IMXWriter_put_output(writer, dest);
2712 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2713 EXPECT_REF(stream, 1);
2715 V_VT(&dest) = VT_UNKNOWN;
2716 V_UNKNOWN(&dest) = (IUnknown*)stream;
2717 hr = IMXWriter_put_output(writer, dest);
2718 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2720 /* flush() doesn't detach a stream */
2721 hr = IMXWriter_flush(writer);
2722 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2723 todo_wine EXPECT_REF(stream, 3);
2725 pos.QuadPart = 0;
2726 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2727 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2728 ok(pos2.QuadPart == 0, "expected stream beginning\n");
2730 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2731 ok(hr == S_OK, "got %08x\n", hr);
2733 hr = ISAXContentHandler_startDocument(content);
2734 ok(hr == S_OK, "got %08x\n", hr);
2736 pos.QuadPart = 0;
2737 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2738 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2739 ok(pos2.QuadPart != 0, "expected stream beginning\n");
2741 /* already started */
2742 hr = ISAXContentHandler_startDocument(content);
2743 ok(hr == S_OK, "got %08x\n", hr);
2745 hr = ISAXContentHandler_endDocument(content);
2746 ok(hr == S_OK, "got %08x\n", hr);
2748 /* flushed on endDocument() */
2749 pos.QuadPart = 0;
2750 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2751 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2752 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2754 ISAXContentHandler_Release(content);
2755 IStream_Release(stream);
2756 IMXWriter_Release(writer);
2759 static void test_mxwriter_startenddocument(void)
2761 ISAXContentHandler *content;
2762 IMXWriter *writer;
2763 VARIANT dest;
2764 HRESULT hr;
2766 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2767 &IID_IMXWriter, (void**)&writer);
2768 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2770 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2771 ok(hr == S_OK, "got %08x\n", hr);
2773 hr = ISAXContentHandler_startDocument(content);
2774 ok(hr == S_OK, "got %08x\n", hr);
2776 hr = ISAXContentHandler_endDocument(content);
2777 ok(hr == S_OK, "got %08x\n", hr);
2779 V_VT(&dest) = VT_EMPTY;
2780 hr = IMXWriter_get_output(writer, &dest);
2781 ok(hr == S_OK, "got %08x\n", hr);
2782 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2783 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2784 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2785 VariantClear(&dest);
2787 /* now try another startDocument */
2788 hr = ISAXContentHandler_startDocument(content);
2789 ok(hr == S_OK, "got %08x\n", hr);
2790 /* and get duplicated prolog */
2791 V_VT(&dest) = VT_EMPTY;
2792 hr = IMXWriter_get_output(writer, &dest);
2793 ok(hr == S_OK, "got %08x\n", hr);
2794 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2795 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
2796 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2797 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2798 VariantClear(&dest);
2800 ISAXContentHandler_Release(content);
2801 IMXWriter_Release(writer);
2803 /* now with omitted declaration */
2804 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2805 &IID_IMXWriter, (void**)&writer);
2806 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2808 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2809 ok(hr == S_OK, "got %08x\n", hr);
2811 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2812 ok(hr == S_OK, "got %08x\n", hr);
2814 hr = ISAXContentHandler_startDocument(content);
2815 ok(hr == S_OK, "got %08x\n", hr);
2817 hr = ISAXContentHandler_endDocument(content);
2818 ok(hr == S_OK, "got %08x\n", hr);
2820 V_VT(&dest) = VT_EMPTY;
2821 hr = IMXWriter_get_output(writer, &dest);
2822 ok(hr == S_OK, "got %08x\n", hr);
2823 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2824 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2825 VariantClear(&dest);
2827 ISAXContentHandler_Release(content);
2828 IMXWriter_Release(writer);
2830 free_bstrs();
2833 enum startendtype
2835 StartElement,
2836 EndElement,
2837 StartEndElement
2840 struct writer_startendelement_t {
2841 const GUID *clsid;
2842 enum startendtype type;
2843 const char *uri;
2844 const char *local_name;
2845 const char *qname;
2846 const char *output;
2847 HRESULT hr;
2848 ISAXAttributes *attr;
2851 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\">";
2852 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\"/>";
2854 static const struct writer_startendelement_t writer_startendelement[] = {
2855 /* 0 */
2856 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2857 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2858 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2859 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
2860 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2861 /* 5 */
2862 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2863 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2864 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
2865 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2866 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2867 /* 10 */
2868 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2869 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
2870 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2871 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2872 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2873 /* 15 */
2874 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
2875 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2876 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2877 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2878 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2879 /* 20 */
2880 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2881 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2882 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2883 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
2884 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2885 /* 25 */
2886 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2887 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2888 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2889 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2890 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2891 /* 30 */
2892 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2893 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2894 /* endElement tests */
2895 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2896 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2897 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2898 /* 35 */
2899 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
2900 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2901 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2902 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2903 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
2904 /* 40 */
2905 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2906 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2907 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2908 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
2909 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2910 /* 45 */
2911 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2912 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2913 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
2914 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2915 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2916 /* 50 */
2917 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2918 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2919 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2920 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2921 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2922 /* 55 */
2923 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
2924 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2925 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2926 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2927 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2928 /* 60 */
2929 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2930 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2931 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2932 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2934 /* with attributes */
2935 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2936 /* 65 */
2937 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2938 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2939 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes },
2940 /* empty elements */
2941 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2942 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2943 /* 70 */
2944 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2945 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes },
2946 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
2947 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
2948 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
2949 /* 75 */
2950 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
2951 { NULL }
2954 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid)
2956 while (table->clsid)
2958 IUnknown *unk;
2959 HRESULT hr;
2961 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk);
2962 if (hr == S_OK) IUnknown_Release(unk);
2964 table->supported = hr == S_OK;
2965 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
2967 table++;
2971 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
2973 int i = 0;
2975 while (table->clsid)
2977 ISAXContentHandler *content;
2978 IMXWriter *writer;
2979 HRESULT hr;
2981 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
2983 table++;
2984 i++;
2985 continue;
2988 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2989 &IID_IMXWriter, (void**)&writer);
2990 EXPECT_HR(hr, S_OK);
2992 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2993 EXPECT_HR(hr, S_OK);
2995 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2996 EXPECT_HR(hr, S_OK);
2998 hr = ISAXContentHandler_startDocument(content);
2999 EXPECT_HR(hr, S_OK);
3001 if (table->type == StartElement)
3003 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3004 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3005 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3007 else if (table->type == EndElement)
3009 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3010 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3011 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3013 else
3015 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
3016 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
3017 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3018 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
3019 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
3020 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
3023 /* test output */
3024 if (hr == S_OK)
3026 VARIANT dest;
3028 V_VT(&dest) = VT_EMPTY;
3029 hr = IMXWriter_get_output(writer, &dest);
3030 EXPECT_HR(hr, S_OK);
3031 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3032 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3033 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3034 VariantClear(&dest);
3037 ISAXContentHandler_Release(content);
3038 IMXWriter_Release(writer);
3040 table++;
3041 i++;
3044 free_bstrs();
3047 static void test_mxwriter_startendelement(void)
3049 ISAXContentHandler *content;
3050 IMXWriter *writer;
3051 VARIANT dest;
3052 HRESULT hr;
3054 test_mxwriter_startendelement_batch(writer_startendelement);
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 = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3061 ok(hr == S_OK, "got %08x\n", hr);
3063 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3064 ok(hr == S_OK, "got %08x\n", hr);
3066 hr = ISAXContentHandler_startDocument(content);
3067 ok(hr == S_OK, "got %08x\n", hr);
3069 /* all string pointers should be not null */
3070 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
3071 ok(hr == S_OK, "got %08x\n", hr);
3073 V_VT(&dest) = VT_EMPTY;
3074 hr = IMXWriter_get_output(writer, &dest);
3075 ok(hr == S_OK, "got %08x\n", hr);
3076 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3077 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3078 VariantClear(&dest);
3080 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
3081 ok(hr == S_OK, "got %08x\n", hr);
3083 V_VT(&dest) = VT_EMPTY;
3084 hr = IMXWriter_get_output(writer, &dest);
3085 ok(hr == S_OK, "got %08x\n", hr);
3086 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3087 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3088 VariantClear(&dest);
3090 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
3091 EXPECT_HR(hr, E_INVALIDARG);
3093 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
3094 EXPECT_HR(hr, E_INVALIDARG);
3096 /* only local name is an error too */
3097 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
3098 EXPECT_HR(hr, E_INVALIDARG);
3100 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
3101 EXPECT_HR(hr, S_OK);
3103 V_VT(&dest) = VT_EMPTY;
3104 hr = IMXWriter_get_output(writer, &dest);
3105 EXPECT_HR(hr, S_OK);
3106 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3107 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3108 VariantClear(&dest);
3110 hr = ISAXContentHandler_endDocument(content);
3111 EXPECT_HR(hr, S_OK);
3113 V_VT(&dest) = VT_EMPTY;
3114 hr = IMXWriter_put_output(writer, dest);
3115 EXPECT_HR(hr, S_OK);
3117 V_VT(&dest) = VT_EMPTY;
3118 hr = IMXWriter_get_output(writer, &dest);
3119 EXPECT_HR(hr, S_OK);
3120 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3121 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3122 VariantClear(&dest);
3124 hr = ISAXContentHandler_startDocument(content);
3125 EXPECT_HR(hr, S_OK);
3127 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
3128 EXPECT_HR(hr, S_OK);
3130 V_VT(&dest) = VT_EMPTY;
3131 hr = IMXWriter_get_output(writer, &dest);
3132 EXPECT_HR(hr, S_OK);
3133 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3134 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3135 VariantClear(&dest);
3137 ISAXContentHandler_endDocument(content);
3138 IMXWriter_flush(writer);
3140 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
3141 EXPECT_HR(hr, S_OK);
3142 V_VT(&dest) = VT_EMPTY;
3143 hr = IMXWriter_get_output(writer, &dest);
3144 EXPECT_HR(hr, S_OK);
3145 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3146 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3147 VariantClear(&dest);
3149 ISAXContentHandler_Release(content);
3150 IMXWriter_Release(writer);
3151 free_bstrs();
3154 struct writer_characters_t {
3155 const GUID *clsid;
3156 const char *data;
3157 const char *output;
3160 static const struct writer_characters_t writer_characters[] = {
3161 { &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
3162 { &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
3163 { &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
3164 { &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
3165 { NULL }
3168 static void test_mxwriter_characters(void)
3170 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
3171 const struct writer_characters_t *table = writer_characters;
3172 ISAXContentHandler *content;
3173 IMXWriter *writer;
3174 VARIANT dest;
3175 HRESULT hr;
3176 int i = 0;
3178 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3179 &IID_IMXWriter, (void**)&writer);
3180 EXPECT_HR(hr, S_OK);
3182 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3183 EXPECT_HR(hr, S_OK);
3185 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3186 EXPECT_HR(hr, S_OK);
3188 hr = ISAXContentHandler_startDocument(content);
3189 EXPECT_HR(hr, S_OK);
3191 hr = ISAXContentHandler_characters(content, NULL, 0);
3192 EXPECT_HR(hr, E_INVALIDARG);
3194 hr = ISAXContentHandler_characters(content, chardataW, 0);
3195 EXPECT_HR(hr, S_OK);
3197 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
3198 EXPECT_HR(hr, S_OK);
3200 V_VT(&dest) = VT_EMPTY;
3201 hr = IMXWriter_get_output(writer, &dest);
3202 EXPECT_HR(hr, S_OK);
3203 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3204 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3205 VariantClear(&dest);
3207 hr = ISAXContentHandler_endDocument(content);
3208 EXPECT_HR(hr, S_OK);
3210 ISAXContentHandler_Release(content);
3211 IMXWriter_Release(writer);
3213 /* try empty characters data to see if element is closed */
3214 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3215 &IID_IMXWriter, (void**)&writer);
3216 EXPECT_HR(hr, S_OK);
3218 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3219 EXPECT_HR(hr, S_OK);
3221 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3222 EXPECT_HR(hr, S_OK);
3224 hr = ISAXContentHandler_startDocument(content);
3225 EXPECT_HR(hr, S_OK);
3227 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3228 EXPECT_HR(hr, S_OK);
3230 hr = ISAXContentHandler_characters(content, chardataW, 0);
3231 EXPECT_HR(hr, S_OK);
3233 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3234 EXPECT_HR(hr, S_OK);
3236 V_VT(&dest) = VT_EMPTY;
3237 hr = IMXWriter_get_output(writer, &dest);
3238 EXPECT_HR(hr, S_OK);
3239 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3240 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3241 VariantClear(&dest);
3243 ISAXContentHandler_Release(content);
3244 IMXWriter_Release(writer);
3246 /* batch tests */
3247 while (table->clsid)
3249 ISAXContentHandler *content;
3250 IMXWriter *writer;
3251 VARIANT dest;
3252 HRESULT hr;
3254 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3256 table++;
3257 i++;
3258 continue;
3261 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3262 &IID_IMXWriter, (void**)&writer);
3263 EXPECT_HR(hr, S_OK);
3265 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3266 EXPECT_HR(hr, S_OK);
3268 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3269 EXPECT_HR(hr, S_OK);
3271 hr = ISAXContentHandler_startDocument(content);
3272 EXPECT_HR(hr, S_OK);
3274 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3275 EXPECT_HR(hr, S_OK);
3277 /* test output */
3278 if (hr == S_OK)
3280 V_VT(&dest) = VT_EMPTY;
3281 hr = IMXWriter_get_output(writer, &dest);
3282 EXPECT_HR(hr, S_OK);
3283 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3284 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3285 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3286 VariantClear(&dest);
3289 /* with disabled escaping */
3290 V_VT(&dest) = VT_EMPTY;
3291 hr = IMXWriter_put_output(writer, dest);
3292 EXPECT_HR(hr, S_OK);
3294 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
3295 EXPECT_HR(hr, S_OK);
3297 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3298 EXPECT_HR(hr, S_OK);
3300 /* test output */
3301 if (hr == S_OK)
3303 V_VT(&dest) = VT_EMPTY;
3304 hr = IMXWriter_get_output(writer, &dest);
3305 EXPECT_HR(hr, S_OK);
3306 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3307 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)),
3308 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data);
3309 VariantClear(&dest);
3312 ISAXContentHandler_Release(content);
3313 IMXWriter_Release(writer);
3315 table++;
3316 i++;
3319 free_bstrs();
3322 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3324 VARIANT_TRUE,"UTF-16",
3326 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3327 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3328 {TRUE}
3332 VARIANT_FALSE,"UTF-16",
3334 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3335 {TRUE}
3339 VARIANT_TRUE,"UTF-8",
3341 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3342 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3343 * and the writer is released.
3345 {FALSE,NULL,0},
3346 {TRUE}
3350 VARIANT_TRUE,"utf-8",
3352 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3353 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3354 * and the writer is released.
3356 {FALSE,NULL,0},
3357 {TRUE}
3361 VARIANT_TRUE,"UTF-16",
3363 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3364 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3365 {TRUE}
3369 VARIANT_TRUE,"UTF-16",
3371 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3372 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3373 {TRUE}
3378 static void test_mxwriter_stream(void)
3380 IMXWriter *writer;
3381 ISAXContentHandler *content;
3382 HRESULT hr;
3383 VARIANT dest;
3384 IStream *stream;
3385 LARGE_INTEGER pos;
3386 ULARGE_INTEGER pos2;
3387 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3389 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3390 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3392 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3393 &IID_IMXWriter, (void**)&writer);
3394 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3396 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3397 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3399 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3400 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3402 V_VT(&dest) = VT_UNKNOWN;
3403 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3404 hr = IMXWriter_put_output(writer, dest);
3405 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3406 VariantClear(&dest);
3408 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3409 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3411 current_write_test = test->expected_writes;
3413 hr = ISAXContentHandler_startDocument(content);
3414 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3416 hr = ISAXContentHandler_endDocument(content);
3417 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3419 ISAXContentHandler_Release(content);
3420 IMXWriter_Release(writer);
3422 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3423 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3426 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3427 &IID_IMXWriter, (void**)&writer);
3428 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3430 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3431 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3433 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3434 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3436 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3437 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3439 V_VT(&dest) = VT_UNKNOWN;
3440 V_UNKNOWN(&dest) = (IUnknown*)stream;
3441 hr = IMXWriter_put_output(writer, dest);
3442 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3444 hr = ISAXContentHandler_startDocument(content);
3445 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3447 /* Setting output of the mxwriter causes the current output to be flushed,
3448 * and the writer to start over.
3450 V_VT(&dest) = VT_EMPTY;
3451 hr = IMXWriter_put_output(writer, dest);
3452 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3454 pos.QuadPart = 0;
3455 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3456 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3457 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3459 hr = ISAXContentHandler_startDocument(content);
3460 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3462 hr = ISAXContentHandler_endDocument(content);
3463 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3465 V_VT(&dest) = VT_EMPTY;
3466 hr = IMXWriter_get_output(writer, &dest);
3467 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3468 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3469 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3470 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3471 VariantClear(&dest);
3473 /* test when BOM is written to output stream */
3474 V_VT(&dest) = VT_EMPTY;
3475 hr = IMXWriter_put_output(writer, dest);
3476 EXPECT_HR(hr, S_OK);
3478 pos.QuadPart = 0;
3479 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3480 EXPECT_HR(hr, S_OK);
3482 V_VT(&dest) = VT_UNKNOWN;
3483 V_UNKNOWN(&dest) = (IUnknown*)stream;
3484 hr = IMXWriter_put_output(writer, dest);
3485 EXPECT_HR(hr, S_OK);
3487 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3488 EXPECT_HR(hr, S_OK);
3490 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3491 EXPECT_HR(hr, S_OK);
3493 hr = ISAXContentHandler_startDocument(content);
3494 EXPECT_HR(hr, S_OK);
3496 pos.QuadPart = 0;
3497 pos2.QuadPart = 0;
3498 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3499 EXPECT_HR(hr, S_OK);
3500 ok(pos2.QuadPart == 2, "got wrong position\n");
3502 ISAXContentHandler_Release(content);
3503 IMXWriter_Release(writer);
3505 free_bstrs();
3508 static void test_mxwriter_encoding(void)
3510 ISAXContentHandler *content;
3511 IMXWriter *writer;
3512 IStream *stream;
3513 VARIANT dest;
3514 HRESULT hr;
3515 HGLOBAL g;
3516 char *ptr;
3517 BSTR s;
3519 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3520 &IID_IMXWriter, (void**)&writer);
3521 EXPECT_HR(hr, S_OK);
3523 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3524 EXPECT_HR(hr, S_OK);
3526 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3527 EXPECT_HR(hr, S_OK);
3529 hr = ISAXContentHandler_startDocument(content);
3530 EXPECT_HR(hr, S_OK);
3532 hr = ISAXContentHandler_endDocument(content);
3533 EXPECT_HR(hr, S_OK);
3535 /* The content is always re-encoded to UTF-16 when the output is
3536 * retrieved as a BSTR.
3538 V_VT(&dest) = VT_EMPTY;
3539 hr = IMXWriter_get_output(writer, &dest);
3540 EXPECT_HR(hr, S_OK);
3541 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3542 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3543 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3544 VariantClear(&dest);
3546 /* switch encoding when something is written already */
3547 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3548 EXPECT_HR(hr, S_OK);
3550 V_VT(&dest) = VT_UNKNOWN;
3551 V_UNKNOWN(&dest) = (IUnknown*)stream;
3552 hr = IMXWriter_put_output(writer, dest);
3553 EXPECT_HR(hr, S_OK);
3555 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3556 EXPECT_HR(hr, S_OK);
3558 /* write empty element */
3559 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3560 EXPECT_HR(hr, S_OK);
3562 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3563 EXPECT_HR(hr, S_OK);
3565 /* switch */
3566 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3567 EXPECT_HR(hr, S_OK);
3569 hr = IMXWriter_flush(writer);
3570 EXPECT_HR(hr, S_OK);
3572 hr = GetHGlobalFromStream(stream, &g);
3573 EXPECT_HR(hr, S_OK);
3575 ptr = GlobalLock(g);
3576 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3577 GlobalUnlock(g);
3579 /* so output is unaffected, encoding name is stored however */
3580 hr = IMXWriter_get_encoding(writer, &s);
3581 EXPECT_HR(hr, S_OK);
3582 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3583 SysFreeString(s);
3585 IStream_Release(stream);
3587 ISAXContentHandler_Release(content);
3588 IMXWriter_Release(writer);
3590 free_bstrs();
3593 static void test_obj_dispex(IUnknown *obj)
3595 static const WCHAR starW[] = {'*',0};
3596 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
3597 IDispatchEx *dispex;
3598 IUnknown *unk;
3599 DWORD props;
3600 UINT ticnt;
3601 HRESULT hr;
3602 BSTR name;
3604 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
3605 EXPECT_HR(hr, S_OK);
3606 if (FAILED(hr)) return;
3608 ticnt = 0;
3609 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
3610 EXPECT_HR(hr, S_OK);
3611 ok(ticnt == 1, "ticnt=%u\n", ticnt);
3613 name = SysAllocString(starW);
3614 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
3615 EXPECT_HR(hr, E_NOTIMPL);
3616 SysFreeString(name);
3618 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
3619 EXPECT_HR(hr, E_NOTIMPL);
3621 props = 0;
3622 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
3623 EXPECT_HR(hr, E_NOTIMPL);
3624 ok(props == 0, "expected 0 got %d\n", props);
3626 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
3627 EXPECT_HR(hr, E_NOTIMPL);
3628 if (SUCCEEDED(hr)) SysFreeString(name);
3630 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
3631 EXPECT_HR(hr, E_NOTIMPL);
3633 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
3634 EXPECT_HR(hr, E_NOTIMPL);
3635 if (hr == S_OK && unk) IUnknown_Release(unk);
3637 IDispatchEx_Release(dispex);
3640 static void test_dispex(void)
3642 IVBSAXXMLReader *vbreader;
3643 ISAXXMLReader *reader;
3644 IUnknown *unk;
3645 HRESULT hr;
3647 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
3648 &IID_ISAXXMLReader, (void**)&reader);
3649 EXPECT_HR(hr, S_OK);
3651 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
3652 EXPECT_HR(hr, S_OK);
3653 test_obj_dispex(unk);
3654 IUnknown_Release(unk);
3656 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
3657 EXPECT_HR(hr, S_OK);
3658 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
3659 EXPECT_HR(hr, S_OK);
3660 test_obj_dispex(unk);
3661 IUnknown_Release(unk);
3662 IVBSAXXMLReader_Release(vbreader);
3664 ISAXXMLReader_Release(reader);
3667 static void test_mxwriter_dispex(void)
3669 IDispatchEx *dispex;
3670 IMXWriter *writer;
3671 IUnknown *unk;
3672 HRESULT hr;
3674 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3675 &IID_IMXWriter, (void**)&writer);
3676 EXPECT_HR(hr, S_OK);
3678 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
3679 EXPECT_HR(hr, S_OK);
3680 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
3681 test_obj_dispex(unk);
3682 IUnknown_Release(unk);
3683 IDispatchEx_Release(dispex);
3685 IMXWriter_Release(writer);
3688 static void test_mxwriter_comment(void)
3690 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
3691 ISAXContentHandler *content;
3692 ISAXLexicalHandler *lexical;
3693 IMXWriter *writer;
3694 VARIANT dest;
3695 HRESULT hr;
3697 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3698 &IID_IMXWriter, (void**)&writer);
3699 EXPECT_HR(hr, S_OK);
3701 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3702 EXPECT_HR(hr, S_OK);
3704 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3705 EXPECT_HR(hr, S_OK);
3707 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3708 EXPECT_HR(hr, S_OK);
3710 hr = ISAXContentHandler_startDocument(content);
3711 EXPECT_HR(hr, S_OK);
3713 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
3714 EXPECT_HR(hr, E_INVALIDARG);
3716 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
3717 EXPECT_HR(hr, S_OK);
3719 V_VT(&dest) = VT_EMPTY;
3720 hr = IMXWriter_get_output(writer, &dest);
3721 EXPECT_HR(hr, S_OK);
3722 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3723 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3724 VariantClear(&dest);
3726 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
3727 EXPECT_HR(hr, S_OK);
3729 V_VT(&dest) = VT_EMPTY;
3730 hr = IMXWriter_get_output(writer, &dest);
3731 EXPECT_HR(hr, S_OK);
3732 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3733 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3734 VariantClear(&dest);
3736 ISAXContentHandler_Release(content);
3737 ISAXLexicalHandler_Release(lexical);
3738 IMXWriter_Release(writer);
3739 free_bstrs();
3742 static void test_mxwriter_cdata(void)
3744 ISAXContentHandler *content;
3745 ISAXLexicalHandler *lexical;
3746 IMXWriter *writer;
3747 VARIANT dest;
3748 HRESULT hr;
3750 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3751 &IID_IMXWriter, (void**)&writer);
3752 EXPECT_HR(hr, S_OK);
3754 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3755 EXPECT_HR(hr, S_OK);
3757 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3758 EXPECT_HR(hr, S_OK);
3760 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3761 EXPECT_HR(hr, S_OK);
3763 hr = ISAXContentHandler_startDocument(content);
3764 EXPECT_HR(hr, S_OK);
3766 hr = ISAXLexicalHandler_startCDATA(lexical);
3767 EXPECT_HR(hr, S_OK);
3769 V_VT(&dest) = VT_EMPTY;
3770 hr = IMXWriter_get_output(writer, &dest);
3771 EXPECT_HR(hr, S_OK);
3772 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3773 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3774 VariantClear(&dest);
3776 hr = ISAXLexicalHandler_startCDATA(lexical);
3777 EXPECT_HR(hr, S_OK);
3779 /* all these are escaped for text nodes */
3780 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
3781 EXPECT_HR(hr, S_OK);
3783 hr = ISAXLexicalHandler_endCDATA(lexical);
3784 EXPECT_HR(hr, S_OK);
3786 V_VT(&dest) = VT_EMPTY;
3787 hr = IMXWriter_get_output(writer, &dest);
3788 EXPECT_HR(hr, S_OK);
3789 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3790 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3791 VariantClear(&dest);
3793 ISAXContentHandler_Release(content);
3794 ISAXLexicalHandler_Release(lexical);
3795 IMXWriter_Release(writer);
3796 free_bstrs();
3799 static void test_mxwriter_pi(void)
3801 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
3802 static const WCHAR dataW[] = {'d','a','t','a',0};
3803 ISAXContentHandler *content;
3804 IMXWriter *writer;
3805 VARIANT dest;
3806 HRESULT hr;
3808 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3809 &IID_IMXWriter, (void**)&writer);
3810 EXPECT_HR(hr, S_OK);
3812 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3813 EXPECT_HR(hr, S_OK);
3815 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
3816 EXPECT_HR(hr, E_INVALIDARG);
3818 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
3819 EXPECT_HR(hr, S_OK);
3821 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
3822 EXPECT_HR(hr, S_OK);
3824 V_VT(&dest) = VT_EMPTY;
3825 hr = IMXWriter_get_output(writer, &dest);
3826 EXPECT_HR(hr, S_OK);
3827 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3828 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3829 VariantClear(&dest);
3831 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
3832 EXPECT_HR(hr, S_OK);
3834 V_VT(&dest) = VT_EMPTY;
3835 hr = IMXWriter_get_output(writer, &dest);
3836 EXPECT_HR(hr, S_OK);
3837 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3838 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)));
3839 VariantClear(&dest);
3841 V_VT(&dest) = VT_EMPTY;
3842 hr = IMXWriter_put_output(writer, dest);
3843 EXPECT_HR(hr, S_OK);
3845 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
3846 EXPECT_HR(hr, S_OK);
3848 V_VT(&dest) = VT_EMPTY;
3849 hr = IMXWriter_get_output(writer, &dest);
3850 EXPECT_HR(hr, S_OK);
3851 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3852 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3853 VariantClear(&dest);
3856 ISAXContentHandler_Release(content);
3857 IMXWriter_Release(writer);
3860 static void test_mxwriter_ignorablespaces(void)
3862 static const WCHAR dataW[] = {'d','a','t','a',0};
3863 ISAXContentHandler *content;
3864 IMXWriter *writer;
3865 VARIANT dest;
3866 HRESULT hr;
3868 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3869 &IID_IMXWriter, (void**)&writer);
3870 EXPECT_HR(hr, S_OK);
3872 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3873 EXPECT_HR(hr, S_OK);
3875 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
3876 EXPECT_HR(hr, E_INVALIDARG);
3878 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
3879 EXPECT_HR(hr, S_OK);
3881 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
3882 EXPECT_HR(hr, S_OK);
3884 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
3885 EXPECT_HR(hr, S_OK);
3887 V_VT(&dest) = VT_EMPTY;
3888 hr = IMXWriter_get_output(writer, &dest);
3889 EXPECT_HR(hr, S_OK);
3890 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3891 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3892 VariantClear(&dest);
3894 ISAXContentHandler_Release(content);
3895 IMXWriter_Release(writer);
3898 static void test_mxwriter_dtd(void)
3900 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
3901 static const WCHAR nameW[] = {'n','a','m','e'};
3902 static const WCHAR pubW[] = {'p','u','b'};
3903 static const WCHAR sysW[] = {'s','y','s'};
3904 ISAXContentHandler *content;
3905 ISAXLexicalHandler *lexical;
3906 ISAXDeclHandler *decl;
3907 IMXWriter *writer;
3908 VARIANT dest;
3909 HRESULT hr;
3911 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3912 &IID_IMXWriter, (void**)&writer);
3913 EXPECT_HR(hr, S_OK);
3915 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3916 EXPECT_HR(hr, S_OK);
3918 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3919 EXPECT_HR(hr, S_OK);
3921 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
3922 EXPECT_HR(hr, S_OK);
3924 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3925 EXPECT_HR(hr, S_OK);
3927 hr = ISAXContentHandler_startDocument(content);
3928 EXPECT_HR(hr, S_OK);
3930 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
3931 EXPECT_HR(hr, E_INVALIDARG);
3933 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3934 EXPECT_HR(hr, E_INVALIDARG);
3936 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
3937 EXPECT_HR(hr, E_INVALIDARG);
3939 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3940 EXPECT_HR(hr, E_INVALIDARG);
3942 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
3943 EXPECT_HR(hr, S_OK);
3945 V_VT(&dest) = VT_EMPTY;
3946 hr = IMXWriter_get_output(writer, &dest);
3947 EXPECT_HR(hr, S_OK);
3948 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3949 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3950 VariantClear(&dest);
3952 /* system id is required if public is present */
3953 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3954 EXPECT_HR(hr, E_INVALIDARG);
3956 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
3957 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3958 EXPECT_HR(hr, S_OK);
3960 V_VT(&dest) = VT_EMPTY;
3961 hr = IMXWriter_get_output(writer, &dest);
3962 EXPECT_HR(hr, S_OK);
3963 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3964 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3965 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3966 VariantClear(&dest);
3968 hr = ISAXLexicalHandler_endDTD(lexical);
3969 EXPECT_HR(hr, S_OK);
3971 hr = ISAXLexicalHandler_endDTD(lexical);
3972 EXPECT_HR(hr, S_OK);
3974 V_VT(&dest) = VT_EMPTY;
3975 hr = IMXWriter_get_output(writer, &dest);
3976 EXPECT_HR(hr, S_OK);
3977 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3978 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3979 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
3980 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3981 VariantClear(&dest);
3983 /* element declaration */
3984 V_VT(&dest) = VT_EMPTY;
3985 hr = IMXWriter_put_output(writer, dest);
3986 EXPECT_HR(hr, S_OK);
3988 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
3989 EXPECT_HR(hr, E_INVALIDARG);
3991 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
3992 EXPECT_HR(hr, E_INVALIDARG);
3994 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
3995 EXPECT_HR(hr, S_OK);
3997 V_VT(&dest) = VT_EMPTY;
3998 hr = IMXWriter_get_output(writer, &dest);
3999 EXPECT_HR(hr, S_OK);
4000 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4001 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
4002 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4003 VariantClear(&dest);
4005 V_VT(&dest) = VT_EMPTY;
4006 hr = IMXWriter_put_output(writer, dest);
4007 EXPECT_HR(hr, S_OK);
4009 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
4010 EXPECT_HR(hr, S_OK);
4012 V_VT(&dest) = VT_EMPTY;
4013 hr = IMXWriter_get_output(writer, &dest);
4014 EXPECT_HR(hr, S_OK);
4015 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
4016 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
4017 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
4018 VariantClear(&dest);
4020 ISAXContentHandler_Release(content);
4021 ISAXLexicalHandler_Release(lexical);
4022 ISAXDeclHandler_Release(decl);
4023 IMXWriter_Release(writer);
4024 free_bstrs();
4027 typedef struct {
4028 const CLSID *clsid;
4029 const char *uri;
4030 const char *local;
4031 const char *qname;
4032 const char *type;
4033 const char *value;
4034 HRESULT hr;
4035 } addattribute_test_t;
4037 static const addattribute_test_t addattribute_data[] = {
4038 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4039 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4040 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4041 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4043 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4044 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4045 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4046 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4048 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4049 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4050 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4051 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4053 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4054 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4055 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4056 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4058 { NULL }
4061 static void test_mxattr_addAttribute(void)
4063 const addattribute_test_t *table = addattribute_data;
4064 int i = 0;
4066 while (table->clsid)
4068 ISAXAttributes *saxattr;
4069 IMXAttributes *mxattr;
4070 const WCHAR *value;
4071 int len, index;
4072 HRESULT hr;
4074 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4076 table++;
4077 i++;
4078 continue;
4081 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4082 &IID_IMXAttributes, (void**)&mxattr);
4083 EXPECT_HR(hr, S_OK);
4085 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4086 EXPECT_HR(hr, S_OK);
4088 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4089 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4090 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4092 hr = ISAXAttributes_getLength(saxattr, NULL);
4093 EXPECT_HR(hr, E_POINTER);
4096 len = -1;
4097 hr = ISAXAttributes_getLength(saxattr, &len);
4098 EXPECT_HR(hr, S_OK);
4099 ok(len == 0, "got %d\n", len);
4101 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4102 EXPECT_HR(hr, E_INVALIDARG);
4104 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4105 EXPECT_HR(hr, E_INVALIDARG);
4107 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4108 EXPECT_HR(hr, E_INVALIDARG);
4110 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4111 EXPECT_HR(hr, E_INVALIDARG);
4113 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4114 EXPECT_HR(hr, E_INVALIDARG);
4116 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4117 EXPECT_HR(hr, E_INVALIDARG);
4119 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4120 EXPECT_HR(hr, E_INVALIDARG);
4122 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4123 EXPECT_HR(hr, E_INVALIDARG);
4125 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4126 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4127 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4129 if (hr == S_OK)
4131 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4132 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4133 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4135 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4136 EXPECT_HR(hr, E_POINTER);
4138 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4139 EXPECT_HR(hr, E_POINTER);
4141 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4142 EXPECT_HR(hr, E_POINTER);
4144 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4145 EXPECT_HR(hr, E_POINTER);
4147 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4148 EXPECT_HR(hr, E_POINTER);
4150 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4151 EXPECT_HR(hr, E_POINTER);
4154 len = -1;
4155 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4156 EXPECT_HR(hr, S_OK);
4157 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4158 table->value);
4159 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4161 len = -1;
4162 value = (void*)0xdeadbeef;
4163 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4164 EXPECT_HR(hr, S_OK);
4166 if (table->type)
4168 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4169 table->type);
4170 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4172 else
4174 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4175 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4178 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4179 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4180 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4182 EXPECT_HR(hr, E_POINTER);
4184 else
4185 EXPECT_HR(hr, E_INVALIDARG);
4187 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4188 EXPECT_HR(hr, E_INVALIDARG);
4190 index = -1;
4191 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4192 EXPECT_HR(hr, E_INVALIDARG);
4193 ok(index == -1, "%d: got wrong index %d\n", i, index);
4195 index = -1;
4196 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4197 EXPECT_HR(hr, E_INVALIDARG);
4198 ok(index == -1, "%d: got wrong index %d\n", i, index);
4200 index = -1;
4201 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4202 EXPECT_HR(hr, S_OK);
4203 ok(index == 0, "%d: got wrong index %d\n", i, index);
4205 index = -1;
4206 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4207 EXPECT_HR(hr, E_INVALIDARG);
4208 ok(index == -1, "%d: got wrong index %d\n", i, index);
4210 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4211 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4213 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4214 EXPECT_HR(hr, E_INVALIDARG);
4216 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4217 EXPECT_HR(hr, E_INVALIDARG);
4219 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4220 EXPECT_HR(hr, E_INVALIDARG);
4222 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4223 EXPECT_HR(hr, E_INVALIDARG);
4225 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4226 EXPECT_HR(hr, E_INVALIDARG);
4228 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4229 EXPECT_HR(hr, E_INVALIDARG);
4231 else
4233 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4234 EXPECT_HR(hr, E_POINTER);
4236 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4237 EXPECT_HR(hr, E_POINTER);
4239 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4240 EXPECT_HR(hr, E_POINTER);
4242 /* versions 4 and 6 crash */
4243 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4244 EXPECT_HR(hr, E_POINTER);
4246 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4247 EXPECT_HR(hr, E_POINTER);
4249 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4250 EXPECT_HR(hr, E_POINTER);
4252 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4253 EXPECT_HR(hr, E_POINTER);
4255 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4256 EXPECT_HR(hr, E_POINTER);
4258 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4259 EXPECT_HR(hr, E_POINTER);
4261 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4262 EXPECT_HR(hr, E_POINTER);
4264 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4265 strlen(table->local), NULL, NULL);
4266 EXPECT_HR(hr, E_POINTER);
4269 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4270 EXPECT_HR(hr, S_OK);
4271 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4272 table->value);
4273 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4275 if (table->uri) {
4276 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4277 _bstr_(table->local), strlen(table->local), &value, &len);
4278 EXPECT_HR(hr, S_OK);
4279 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4280 table->value);
4281 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4285 len = -1;
4286 hr = ISAXAttributes_getLength(saxattr, &len);
4287 EXPECT_HR(hr, S_OK);
4288 if (table->hr == S_OK)
4289 ok(len == 1, "%d: got %d length, expected 0\n", i, len);
4290 else
4291 ok(len == 0, "%d: got %d length, expected 1\n", i, len);
4293 ISAXAttributes_Release(saxattr);
4294 IMXAttributes_Release(mxattr);
4296 table++;
4297 i++;
4300 free_bstrs();
4303 static void test_mxattr_clear(void)
4305 ISAXAttributes *saxattr;
4306 IMXAttributes *mxattr;
4307 const WCHAR *ptr;
4308 HRESULT hr;
4309 int len;
4311 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4312 &IID_IMXAttributes, (void**)&mxattr);
4313 EXPECT_HR(hr, S_OK);
4315 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4316 EXPECT_HR(hr, S_OK);
4318 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4319 EXPECT_HR(hr, E_INVALIDARG);
4321 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4322 EXPECT_HR(hr, E_INVALIDARG);
4324 hr = IMXAttributes_clear(mxattr);
4325 EXPECT_HR(hr, S_OK);
4327 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4328 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4329 EXPECT_HR(hr, S_OK);
4331 len = -1;
4332 hr = ISAXAttributes_getLength(saxattr, &len);
4333 EXPECT_HR(hr, S_OK);
4334 ok(len == 1, "got %d\n", len);
4336 len = -1;
4337 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4338 EXPECT_HR(hr, E_POINTER);
4339 ok(len == -1, "got %d\n", len);
4341 ptr = (void*)0xdeadbeef;
4342 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4343 EXPECT_HR(hr, E_POINTER);
4344 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4346 len = 0;
4347 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4348 EXPECT_HR(hr, S_OK);
4349 ok(len == 5, "got %d\n", len);
4350 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4352 hr = IMXAttributes_clear(mxattr);
4353 EXPECT_HR(hr, S_OK);
4355 len = -1;
4356 hr = ISAXAttributes_getLength(saxattr, &len);
4357 EXPECT_HR(hr, S_OK);
4358 ok(len == 0, "got %d\n", len);
4360 len = -1;
4361 ptr = (void*)0xdeadbeef;
4362 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4363 EXPECT_HR(hr, E_INVALIDARG);
4364 ok(len == -1, "got %d\n", len);
4365 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4367 IMXAttributes_Release(mxattr);
4368 ISAXAttributes_Release(saxattr);
4369 free_bstrs();
4372 static void test_mxattr_dispex(void)
4374 IMXAttributes *mxattr;
4375 IDispatchEx *dispex;
4376 IUnknown *unk;
4377 HRESULT hr;
4379 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4380 &IID_IMXAttributes, (void**)&mxattr);
4381 EXPECT_HR(hr, S_OK);
4383 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4384 EXPECT_HR(hr, S_OK);
4385 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4386 test_obj_dispex(unk);
4387 IUnknown_Release(unk);
4388 IDispatchEx_Release(dispex);
4390 IMXAttributes_Release(mxattr);
4393 static void test_mxattr_qi(void)
4395 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4396 ISAXAttributes *saxattr;
4397 IMXAttributes *mxattr;
4398 HRESULT hr;
4400 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4401 &IID_IMXAttributes, (void**)&mxattr);
4402 EXPECT_HR(hr, S_OK);
4404 EXPECT_REF(mxattr, 1);
4405 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4406 EXPECT_HR(hr, S_OK);
4408 EXPECT_REF(mxattr, 2);
4409 EXPECT_REF(saxattr, 2);
4411 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4412 EXPECT_HR(hr, S_OK);
4414 EXPECT_REF(vbsaxattr, 3);
4415 EXPECT_REF(mxattr, 3);
4416 EXPECT_REF(saxattr, 3);
4418 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4419 EXPECT_HR(hr, S_OK);
4421 EXPECT_REF(vbsaxattr, 4);
4422 EXPECT_REF(mxattr, 4);
4423 EXPECT_REF(saxattr, 4);
4425 IMXAttributes_Release(mxattr);
4426 ISAXAttributes_Release(saxattr);
4427 IVBSAXAttributes_Release(vbsaxattr);
4428 IVBSAXAttributes_Release(vbsaxattr2);
4431 static struct msxmlsupported_data_t saxattr_support_data[] =
4433 { &CLSID_SAXAttributes, "SAXAttributes" },
4434 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4435 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4436 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4437 { NULL }
4440 static void test_mxattr_localname(void)
4442 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4443 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4444 static const WCHAR uri1W[] = {'u','r','i','1',0};
4445 static const WCHAR uriW[] = {'u','r','i',0};
4447 const struct msxmlsupported_data_t *table = saxattr_support_data;
4449 while (table->clsid)
4451 ISAXAttributes *saxattr;
4452 IMXAttributes *mxattr;
4453 HRESULT hr;
4454 int index;
4456 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4458 table++;
4459 continue;
4462 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4463 &IID_IMXAttributes, (void**)&mxattr);
4464 EXPECT_HR(hr, S_OK);
4466 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4467 EXPECT_HR(hr, S_OK);
4469 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4470 EXPECT_HR(hr, E_INVALIDARG);
4472 /* add some ambiguos attribute names */
4473 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4474 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4475 EXPECT_HR(hr, S_OK);
4476 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4477 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4478 EXPECT_HR(hr, S_OK);
4480 index = -1;
4481 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4482 EXPECT_HR(hr, S_OK);
4483 ok(index == 0, "%s: got index %d\n", table->name, index);
4485 index = -1;
4486 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4487 EXPECT_HR(hr, E_INVALIDARG);
4488 ok(index == -1, "%s: got index %d\n", table->name, index);
4490 index = -1;
4491 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4492 EXPECT_HR(hr, E_INVALIDARG);
4493 ok(index == -1, "%s: got index %d\n", table->name, index);
4495 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4496 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4498 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4499 EXPECT_HR(hr, E_POINTER);
4501 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4502 EXPECT_HR(hr, E_POINTER);
4504 else
4506 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4507 EXPECT_HR(hr, E_INVALIDARG);
4509 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4510 EXPECT_HR(hr, E_INVALIDARG);
4513 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
4514 EXPECT_HR(hr, E_INVALIDARG);
4516 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
4517 EXPECT_HR(hr, E_INVALIDARG);
4519 table++;
4521 ISAXAttributes_Release(saxattr);
4522 IMXAttributes_Release(mxattr);
4526 START_TEST(saxreader)
4528 ISAXXMLReader *reader;
4529 HRESULT hr;
4531 hr = CoInitialize(NULL);
4532 ok(hr == S_OK, "failed to init com\n");
4534 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4535 &IID_ISAXXMLReader, (void**)&reader);
4537 if(FAILED(hr))
4539 skip("Failed to create SAXXMLReader instance\n");
4540 CoUninitialize();
4541 return;
4543 ISAXXMLReader_Release(reader);
4545 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4547 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
4549 test_saxreader();
4550 test_saxreader_properties();
4551 test_saxreader_features();
4552 test_saxreader_encoding();
4553 test_dispex();
4555 /* MXXMLWriter tests */
4556 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
4557 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
4559 test_mxwriter_handlers();
4560 test_mxwriter_startenddocument();
4561 test_mxwriter_startendelement();
4562 test_mxwriter_characters();
4563 test_mxwriter_comment();
4564 test_mxwriter_cdata();
4565 test_mxwriter_pi();
4566 test_mxwriter_ignorablespaces();
4567 test_mxwriter_dtd();
4568 test_mxwriter_properties();
4569 test_mxwriter_flush();
4570 test_mxwriter_stream();
4571 test_mxwriter_encoding();
4572 test_mxwriter_dispex();
4574 else
4575 win_skip("MXXMLWriter not supported\n");
4577 /* SAXAttributes tests */
4578 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
4579 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
4581 test_mxattr_qi();
4582 test_mxattr_addAttribute();
4583 test_mxattr_clear();
4584 test_mxattr_localname();
4585 test_mxattr_dispex();
4587 else
4588 skip("SAXAttributes not supported\n");
4590 CoUninitialize();