msxml3: Added getValueFromName() for IMXAttributes.
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blob340bdd0de26bbe3d43407b0e1b5f4611e38f5aad
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 HRESULT hr;
3253 if (!is_clsid_supported(table->clsid, mxwriter_support_data))
3255 table++;
3256 i++;
3257 continue;
3260 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3261 &IID_IMXWriter, (void**)&writer);
3262 EXPECT_HR(hr, S_OK);
3264 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3265 EXPECT_HR(hr, S_OK);
3267 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3268 EXPECT_HR(hr, S_OK);
3270 hr = ISAXContentHandler_startDocument(content);
3271 EXPECT_HR(hr, S_OK);
3273 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
3274 EXPECT_HR(hr, S_OK);
3276 /* test output */
3277 if (hr == S_OK)
3279 VARIANT dest;
3281 V_VT(&dest) = VT_EMPTY;
3282 hr = IMXWriter_get_output(writer, &dest);
3283 EXPECT_HR(hr, S_OK);
3284 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3285 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
3286 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
3287 VariantClear(&dest);
3290 table++;
3291 i++;
3294 free_bstrs();
3297 static const mxwriter_stream_test mxwriter_stream_tests[] = {
3299 VARIANT_TRUE,"UTF-16",
3301 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3302 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3303 {TRUE}
3307 VARIANT_FALSE,"UTF-16",
3309 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3310 {TRUE}
3314 VARIANT_TRUE,"UTF-8",
3316 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
3317 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3318 * and the writer is released.
3320 {FALSE,NULL,0},
3321 {TRUE}
3325 VARIANT_TRUE,"utf-8",
3327 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1},
3328 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
3329 * and the writer is released.
3331 {FALSE,NULL,0},
3332 {TRUE}
3336 VARIANT_TRUE,"UTF-16",
3338 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
3339 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3340 {TRUE}
3344 VARIANT_TRUE,"UTF-16",
3346 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
3347 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
3348 {TRUE}
3353 static void test_mxwriter_stream(void)
3355 IMXWriter *writer;
3356 ISAXContentHandler *content;
3357 HRESULT hr;
3358 VARIANT dest;
3359 IStream *stream;
3360 LARGE_INTEGER pos;
3361 ULARGE_INTEGER pos2;
3362 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
3364 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
3365 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
3367 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3368 &IID_IMXWriter, (void**)&writer);
3369 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3371 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3372 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3374 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
3375 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
3377 V_VT(&dest) = VT_UNKNOWN;
3378 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
3379 hr = IMXWriter_put_output(writer, dest);
3380 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
3381 VariantClear(&dest);
3383 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
3384 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
3386 current_write_test = test->expected_writes;
3388 hr = ISAXContentHandler_startDocument(content);
3389 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3391 hr = ISAXContentHandler_endDocument(content);
3392 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
3394 ISAXContentHandler_Release(content);
3395 IMXWriter_Release(writer);
3397 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
3398 (int)(current_write_test-test->expected_writes), current_stream_test_index);
3401 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3402 &IID_IMXWriter, (void**)&writer);
3403 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
3405 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3406 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
3408 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3409 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
3411 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3412 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
3414 V_VT(&dest) = VT_UNKNOWN;
3415 V_UNKNOWN(&dest) = (IUnknown*)stream;
3416 hr = IMXWriter_put_output(writer, dest);
3417 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3419 hr = ISAXContentHandler_startDocument(content);
3420 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3422 /* Setting output of the mxwriter causes the current output to be flushed,
3423 * and the writer to start over.
3425 V_VT(&dest) = VT_EMPTY;
3426 hr = IMXWriter_put_output(writer, dest);
3427 ok(hr == S_OK, "put_output failed: %08x\n", hr);
3429 pos.QuadPart = 0;
3430 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3431 ok(hr == S_OK, "Seek failed: %08x\n", hr);
3432 ok(pos2.QuadPart != 0, "expected stream position moved\n");
3434 hr = ISAXContentHandler_startDocument(content);
3435 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
3437 hr = ISAXContentHandler_endDocument(content);
3438 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
3440 V_VT(&dest) = VT_EMPTY;
3441 hr = IMXWriter_get_output(writer, &dest);
3442 ok(hr == S_OK, "get_output failed: %08x\n", hr);
3443 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3444 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3445 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3446 VariantClear(&dest);
3448 /* test when BOM is written to output stream */
3449 V_VT(&dest) = VT_EMPTY;
3450 hr = IMXWriter_put_output(writer, dest);
3451 EXPECT_HR(hr, S_OK);
3453 pos.QuadPart = 0;
3454 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
3455 EXPECT_HR(hr, S_OK);
3457 V_VT(&dest) = VT_UNKNOWN;
3458 V_UNKNOWN(&dest) = (IUnknown*)stream;
3459 hr = IMXWriter_put_output(writer, dest);
3460 EXPECT_HR(hr, S_OK);
3462 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
3463 EXPECT_HR(hr, S_OK);
3465 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3466 EXPECT_HR(hr, S_OK);
3468 hr = ISAXContentHandler_startDocument(content);
3469 EXPECT_HR(hr, S_OK);
3471 pos.QuadPart = 0;
3472 pos2.QuadPart = 0;
3473 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
3474 EXPECT_HR(hr, S_OK);
3475 ok(pos2.QuadPart == 2, "got wrong position\n");
3477 ISAXContentHandler_Release(content);
3478 IMXWriter_Release(writer);
3480 free_bstrs();
3483 static void test_mxwriter_encoding(void)
3485 ISAXContentHandler *content;
3486 IMXWriter *writer;
3487 IStream *stream;
3488 VARIANT dest;
3489 HRESULT hr;
3490 HGLOBAL g;
3491 char *ptr;
3492 BSTR s;
3494 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3495 &IID_IMXWriter, (void**)&writer);
3496 EXPECT_HR(hr, S_OK);
3498 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3499 EXPECT_HR(hr, S_OK);
3501 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3502 EXPECT_HR(hr, S_OK);
3504 hr = ISAXContentHandler_startDocument(content);
3505 EXPECT_HR(hr, S_OK);
3507 hr = ISAXContentHandler_endDocument(content);
3508 EXPECT_HR(hr, S_OK);
3510 /* The content is always re-encoded to UTF-16 when the output is
3511 * retrieved as a BSTR.
3513 V_VT(&dest) = VT_EMPTY;
3514 hr = IMXWriter_get_output(writer, &dest);
3515 EXPECT_HR(hr, S_OK);
3516 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
3517 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
3518 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3519 VariantClear(&dest);
3521 /* switch encoding when something is written already */
3522 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3523 EXPECT_HR(hr, S_OK);
3525 V_VT(&dest) = VT_UNKNOWN;
3526 V_UNKNOWN(&dest) = (IUnknown*)stream;
3527 hr = IMXWriter_put_output(writer, dest);
3528 EXPECT_HR(hr, S_OK);
3530 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
3531 EXPECT_HR(hr, S_OK);
3533 /* write empty element */
3534 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
3535 EXPECT_HR(hr, S_OK);
3537 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
3538 EXPECT_HR(hr, S_OK);
3540 /* switch */
3541 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
3542 EXPECT_HR(hr, S_OK);
3544 hr = IMXWriter_flush(writer);
3545 EXPECT_HR(hr, S_OK);
3547 hr = GetHGlobalFromStream(stream, &g);
3548 EXPECT_HR(hr, S_OK);
3550 ptr = GlobalLock(g);
3551 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
3552 GlobalUnlock(g);
3554 /* so output is unaffected, encoding name is stored however */
3555 hr = IMXWriter_get_encoding(writer, &s);
3556 EXPECT_HR(hr, S_OK);
3557 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s));
3558 SysFreeString(s);
3560 IStream_Release(stream);
3562 ISAXContentHandler_Release(content);
3563 IMXWriter_Release(writer);
3565 free_bstrs();
3568 static void test_obj_dispex(IUnknown *obj)
3570 static const WCHAR starW[] = {'*',0};
3571 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
3572 IDispatchEx *dispex;
3573 IUnknown *unk;
3574 DWORD props;
3575 UINT ticnt;
3576 HRESULT hr;
3577 BSTR name;
3579 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
3580 EXPECT_HR(hr, S_OK);
3581 if (FAILED(hr)) return;
3583 ticnt = 0;
3584 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
3585 EXPECT_HR(hr, S_OK);
3586 ok(ticnt == 1, "ticnt=%u\n", ticnt);
3588 name = SysAllocString(starW);
3589 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
3590 EXPECT_HR(hr, E_NOTIMPL);
3591 SysFreeString(name);
3593 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
3594 EXPECT_HR(hr, E_NOTIMPL);
3596 props = 0;
3597 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
3598 EXPECT_HR(hr, E_NOTIMPL);
3599 ok(props == 0, "expected 0 got %d\n", props);
3601 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
3602 EXPECT_HR(hr, E_NOTIMPL);
3603 if (SUCCEEDED(hr)) SysFreeString(name);
3605 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
3606 EXPECT_HR(hr, E_NOTIMPL);
3608 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
3609 EXPECT_HR(hr, E_NOTIMPL);
3610 if (hr == S_OK && unk) IUnknown_Release(unk);
3612 IDispatchEx_Release(dispex);
3615 static void test_dispex(void)
3617 IVBSAXXMLReader *vbreader;
3618 ISAXXMLReader *reader;
3619 IUnknown *unk;
3620 HRESULT hr;
3622 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
3623 &IID_ISAXXMLReader, (void**)&reader);
3624 EXPECT_HR(hr, S_OK);
3626 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
3627 EXPECT_HR(hr, S_OK);
3628 test_obj_dispex(unk);
3629 IUnknown_Release(unk);
3631 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
3632 EXPECT_HR(hr, S_OK);
3633 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
3634 EXPECT_HR(hr, S_OK);
3635 test_obj_dispex(unk);
3636 IUnknown_Release(unk);
3637 IVBSAXXMLReader_Release(vbreader);
3639 ISAXXMLReader_Release(reader);
3642 static void test_mxwriter_dispex(void)
3644 IDispatchEx *dispex;
3645 IMXWriter *writer;
3646 IUnknown *unk;
3647 HRESULT hr;
3649 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3650 &IID_IMXWriter, (void**)&writer);
3651 EXPECT_HR(hr, S_OK);
3653 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex);
3654 EXPECT_HR(hr, S_OK);
3655 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
3656 test_obj_dispex(unk);
3657 IUnknown_Release(unk);
3658 IDispatchEx_Release(dispex);
3660 IMXWriter_Release(writer);
3663 static void test_mxwriter_comment(void)
3665 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0};
3666 ISAXContentHandler *content;
3667 ISAXLexicalHandler *lexical;
3668 IMXWriter *writer;
3669 VARIANT dest;
3670 HRESULT hr;
3672 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3673 &IID_IMXWriter, (void**)&writer);
3674 EXPECT_HR(hr, S_OK);
3676 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3677 EXPECT_HR(hr, S_OK);
3679 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3680 EXPECT_HR(hr, S_OK);
3682 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3683 EXPECT_HR(hr, S_OK);
3685 hr = ISAXContentHandler_startDocument(content);
3686 EXPECT_HR(hr, S_OK);
3688 hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
3689 EXPECT_HR(hr, E_INVALIDARG);
3691 hr = ISAXLexicalHandler_comment(lexical, commentW, 0);
3692 EXPECT_HR(hr, S_OK);
3694 V_VT(&dest) = VT_EMPTY;
3695 hr = IMXWriter_get_output(writer, &dest);
3696 EXPECT_HR(hr, S_OK);
3697 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3698 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3699 VariantClear(&dest);
3701 hr = ISAXLexicalHandler_comment(lexical, commentW, sizeof(commentW)/sizeof(WCHAR)-1);
3702 EXPECT_HR(hr, S_OK);
3704 V_VT(&dest) = VT_EMPTY;
3705 hr = IMXWriter_get_output(writer, &dest);
3706 EXPECT_HR(hr, S_OK);
3707 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3708 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3709 VariantClear(&dest);
3711 ISAXContentHandler_Release(content);
3712 ISAXLexicalHandler_Release(lexical);
3713 IMXWriter_Release(writer);
3714 free_bstrs();
3717 static void test_mxwriter_cdata(void)
3719 ISAXContentHandler *content;
3720 ISAXLexicalHandler *lexical;
3721 IMXWriter *writer;
3722 VARIANT dest;
3723 HRESULT hr;
3725 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3726 &IID_IMXWriter, (void**)&writer);
3727 EXPECT_HR(hr, S_OK);
3729 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3730 EXPECT_HR(hr, S_OK);
3732 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3733 EXPECT_HR(hr, S_OK);
3735 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3736 EXPECT_HR(hr, S_OK);
3738 hr = ISAXContentHandler_startDocument(content);
3739 EXPECT_HR(hr, S_OK);
3741 hr = ISAXLexicalHandler_startCDATA(lexical);
3742 EXPECT_HR(hr, S_OK);
3744 V_VT(&dest) = VT_EMPTY;
3745 hr = IMXWriter_get_output(writer, &dest);
3746 EXPECT_HR(hr, S_OK);
3747 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3748 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3749 VariantClear(&dest);
3751 hr = ISAXLexicalHandler_startCDATA(lexical);
3752 EXPECT_HR(hr, S_OK);
3754 /* all these are escaped for text nodes */
3755 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
3756 EXPECT_HR(hr, S_OK);
3758 hr = ISAXLexicalHandler_endCDATA(lexical);
3759 EXPECT_HR(hr, S_OK);
3761 V_VT(&dest) = VT_EMPTY;
3762 hr = IMXWriter_get_output(writer, &dest);
3763 EXPECT_HR(hr, S_OK);
3764 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3765 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3766 VariantClear(&dest);
3768 ISAXContentHandler_Release(content);
3769 ISAXLexicalHandler_Release(lexical);
3770 IMXWriter_Release(writer);
3771 free_bstrs();
3774 static void test_mxwriter_pi(void)
3776 static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
3777 static const WCHAR dataW[] = {'d','a','t','a',0};
3778 ISAXContentHandler *content;
3779 IMXWriter *writer;
3780 VARIANT dest;
3781 HRESULT hr;
3783 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3784 &IID_IMXWriter, (void**)&writer);
3785 EXPECT_HR(hr, S_OK);
3787 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3788 EXPECT_HR(hr, S_OK);
3790 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
3791 EXPECT_HR(hr, E_INVALIDARG);
3793 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0);
3794 EXPECT_HR(hr, S_OK);
3796 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0);
3797 EXPECT_HR(hr, S_OK);
3799 V_VT(&dest) = VT_EMPTY;
3800 hr = IMXWriter_get_output(writer, &dest);
3801 EXPECT_HR(hr, S_OK);
3802 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3803 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3804 VariantClear(&dest);
3806 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4);
3807 EXPECT_HR(hr, S_OK);
3809 V_VT(&dest) = VT_EMPTY;
3810 hr = IMXWriter_get_output(writer, &dest);
3811 EXPECT_HR(hr, S_OK);
3812 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3813 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)));
3814 VariantClear(&dest);
3816 V_VT(&dest) = VT_EMPTY;
3817 hr = IMXWriter_put_output(writer, dest);
3818 EXPECT_HR(hr, S_OK);
3820 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0);
3821 EXPECT_HR(hr, S_OK);
3823 V_VT(&dest) = VT_EMPTY;
3824 hr = IMXWriter_get_output(writer, &dest);
3825 EXPECT_HR(hr, S_OK);
3826 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3827 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3828 VariantClear(&dest);
3831 ISAXContentHandler_Release(content);
3832 IMXWriter_Release(writer);
3835 static void test_mxwriter_ignorablespaces(void)
3837 static const WCHAR dataW[] = {'d','a','t','a',0};
3838 ISAXContentHandler *content;
3839 IMXWriter *writer;
3840 VARIANT dest;
3841 HRESULT hr;
3843 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3844 &IID_IMXWriter, (void**)&writer);
3845 EXPECT_HR(hr, S_OK);
3847 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3848 EXPECT_HR(hr, S_OK);
3850 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
3851 EXPECT_HR(hr, E_INVALIDARG);
3853 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0);
3854 EXPECT_HR(hr, S_OK);
3856 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4);
3857 EXPECT_HR(hr, S_OK);
3859 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1);
3860 EXPECT_HR(hr, S_OK);
3862 V_VT(&dest) = VT_EMPTY;
3863 hr = IMXWriter_get_output(writer, &dest);
3864 EXPECT_HR(hr, S_OK);
3865 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3866 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3867 VariantClear(&dest);
3869 ISAXContentHandler_Release(content);
3870 IMXWriter_Release(writer);
3873 static void test_mxwriter_dtd(void)
3875 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'};
3876 static const WCHAR nameW[] = {'n','a','m','e'};
3877 static const WCHAR pubW[] = {'p','u','b'};
3878 static const WCHAR sysW[] = {'s','y','s'};
3879 ISAXContentHandler *content;
3880 ISAXLexicalHandler *lexical;
3881 ISAXDeclHandler *decl;
3882 IMXWriter *writer;
3883 VARIANT dest;
3884 HRESULT hr;
3886 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3887 &IID_IMXWriter, (void**)&writer);
3888 EXPECT_HR(hr, S_OK);
3890 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3891 EXPECT_HR(hr, S_OK);
3893 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
3894 EXPECT_HR(hr, S_OK);
3896 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
3897 EXPECT_HR(hr, S_OK);
3899 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
3900 EXPECT_HR(hr, S_OK);
3902 hr = ISAXContentHandler_startDocument(content);
3903 EXPECT_HR(hr, S_OK);
3905 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
3906 EXPECT_HR(hr, E_INVALIDARG);
3908 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3909 EXPECT_HR(hr, E_INVALIDARG);
3911 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, sizeof(sysW)/sizeof(WCHAR));
3912 EXPECT_HR(hr, E_INVALIDARG);
3914 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3915 EXPECT_HR(hr, E_INVALIDARG);
3917 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0, NULL, 0);
3918 EXPECT_HR(hr, S_OK);
3920 V_VT(&dest) = VT_EMPTY;
3921 hr = IMXWriter_get_output(writer, &dest);
3922 EXPECT_HR(hr, S_OK);
3923 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3924 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3925 VariantClear(&dest);
3927 /* system id is required if public is present */
3928 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR), pubW, sizeof(pubW)/sizeof(WCHAR), NULL, 0);
3929 EXPECT_HR(hr, E_INVALIDARG);
3931 hr = ISAXLexicalHandler_startDTD(lexical, nameW, sizeof(nameW)/sizeof(WCHAR),
3932 pubW, sizeof(pubW)/sizeof(WCHAR), sysW, sizeof(sysW)/sizeof(WCHAR));
3933 EXPECT_HR(hr, S_OK);
3935 V_VT(&dest) = VT_EMPTY;
3936 hr = IMXWriter_get_output(writer, &dest);
3937 EXPECT_HR(hr, S_OK);
3938 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3939 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3940 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3941 VariantClear(&dest);
3943 hr = ISAXLexicalHandler_endDTD(lexical);
3944 EXPECT_HR(hr, S_OK);
3946 hr = ISAXLexicalHandler_endDTD(lexical);
3947 EXPECT_HR(hr, S_OK);
3949 V_VT(&dest) = VT_EMPTY;
3950 hr = IMXWriter_get_output(writer, &dest);
3951 EXPECT_HR(hr, S_OK);
3952 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3953 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
3954 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"),
3955 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3956 VariantClear(&dest);
3958 /* element declaration */
3959 V_VT(&dest) = VT_EMPTY;
3960 hr = IMXWriter_put_output(writer, dest);
3961 EXPECT_HR(hr, S_OK);
3963 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
3964 EXPECT_HR(hr, E_INVALIDARG);
3966 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, 0);
3967 EXPECT_HR(hr, E_INVALIDARG);
3969 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, sizeof(contentW)/sizeof(WCHAR));
3970 EXPECT_HR(hr, S_OK);
3972 V_VT(&dest) = VT_EMPTY;
3973 hr = IMXWriter_get_output(writer, &dest);
3974 EXPECT_HR(hr, S_OK);
3975 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3976 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"),
3977 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3978 VariantClear(&dest);
3980 V_VT(&dest) = VT_EMPTY;
3981 hr = IMXWriter_put_output(writer, dest);
3982 EXPECT_HR(hr, S_OK);
3984 hr = ISAXDeclHandler_elementDecl(decl, nameW, sizeof(nameW)/sizeof(WCHAR), contentW, 0);
3985 EXPECT_HR(hr, S_OK);
3987 V_VT(&dest) = VT_EMPTY;
3988 hr = IMXWriter_get_output(writer, &dest);
3989 EXPECT_HR(hr, S_OK);
3990 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3991 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"),
3992 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3993 VariantClear(&dest);
3995 ISAXContentHandler_Release(content);
3996 ISAXLexicalHandler_Release(lexical);
3997 ISAXDeclHandler_Release(decl);
3998 IMXWriter_Release(writer);
3999 free_bstrs();
4002 typedef struct {
4003 const CLSID *clsid;
4004 const char *uri;
4005 const char *local;
4006 const char *qname;
4007 const char *type;
4008 const char *value;
4009 HRESULT hr;
4010 } addattribute_test_t;
4012 static const addattribute_test_t addattribute_data[] = {
4013 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4014 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4015 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
4016 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK },
4018 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4019 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4020 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4021 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK },
4023 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4024 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4025 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
4026 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK },
4028 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK },
4029 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK },
4030 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
4031 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK },
4033 { NULL }
4036 static void test_mxattr_addAttribute(void)
4038 const addattribute_test_t *table = addattribute_data;
4039 int i = 0;
4041 while (table->clsid)
4043 ISAXAttributes *saxattr;
4044 IMXAttributes *mxattr;
4045 const WCHAR *value;
4046 int len, index;
4047 HRESULT hr;
4049 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4051 table++;
4052 i++;
4053 continue;
4056 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4057 &IID_IMXAttributes, (void**)&mxattr);
4058 EXPECT_HR(hr, S_OK);
4060 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4061 EXPECT_HR(hr, S_OK);
4063 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4064 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4065 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4067 hr = ISAXAttributes_getLength(saxattr, NULL);
4068 EXPECT_HR(hr, E_POINTER);
4071 len = -1;
4072 hr = ISAXAttributes_getLength(saxattr, &len);
4073 EXPECT_HR(hr, S_OK);
4074 ok(len == 0, "got %d\n", len);
4076 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4077 EXPECT_HR(hr, E_INVALIDARG);
4079 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4080 EXPECT_HR(hr, E_INVALIDARG);
4082 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4083 EXPECT_HR(hr, E_INVALIDARG);
4085 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4086 EXPECT_HR(hr, E_INVALIDARG);
4088 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4089 EXPECT_HR(hr, E_INVALIDARG);
4091 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4092 EXPECT_HR(hr, E_INVALIDARG);
4094 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4095 EXPECT_HR(hr, E_INVALIDARG);
4097 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4098 EXPECT_HR(hr, E_INVALIDARG);
4100 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
4101 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
4102 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
4104 if (hr == S_OK)
4106 /* SAXAttributes40 and SAXAttributes60 both crash on this test */
4107 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4108 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4110 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
4111 EXPECT_HR(hr, E_POINTER);
4113 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
4114 EXPECT_HR(hr, E_POINTER);
4116 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
4117 EXPECT_HR(hr, E_POINTER);
4119 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
4120 EXPECT_HR(hr, E_POINTER);
4122 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
4123 EXPECT_HR(hr, E_POINTER);
4125 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
4126 EXPECT_HR(hr, E_POINTER);
4129 len = -1;
4130 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
4131 EXPECT_HR(hr, S_OK);
4132 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4133 table->value);
4134 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4136 len = -1;
4137 value = (void*)0xdeadbeef;
4138 hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
4139 EXPECT_HR(hr, S_OK);
4141 if (table->type)
4143 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4144 table->type);
4145 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
4147 else
4149 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
4150 ok(len == 0, "%d: got wrong type value length %d\n", i, len);
4153 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
4154 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4155 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4157 EXPECT_HR(hr, E_POINTER);
4159 else
4160 EXPECT_HR(hr, E_INVALIDARG);
4162 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
4163 EXPECT_HR(hr, E_INVALIDARG);
4165 index = -1;
4166 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index);
4167 EXPECT_HR(hr, E_INVALIDARG);
4168 ok(index == -1, "%d: got wrong index %d\n", i, index);
4170 index = -1;
4171 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
4172 EXPECT_HR(hr, E_INVALIDARG);
4173 ok(index == -1, "%d: got wrong index %d\n", i, index);
4175 index = -1;
4176 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
4177 EXPECT_HR(hr, S_OK);
4178 ok(index == 0, "%d: got wrong index %d\n", i, index);
4180 index = -1;
4181 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
4182 EXPECT_HR(hr, E_INVALIDARG);
4183 ok(index == -1, "%d: got wrong index %d\n", i, index);
4185 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) ||
4186 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60))
4188 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4189 EXPECT_HR(hr, E_INVALIDARG);
4191 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4192 EXPECT_HR(hr, E_INVALIDARG);
4194 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4195 EXPECT_HR(hr, E_INVALIDARG);
4197 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4198 EXPECT_HR(hr, E_INVALIDARG);
4200 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4201 EXPECT_HR(hr, E_INVALIDARG);
4203 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4204 EXPECT_HR(hr, E_INVALIDARG);
4206 else
4208 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
4209 EXPECT_HR(hr, E_POINTER);
4211 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
4212 EXPECT_HR(hr, E_POINTER);
4214 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
4215 EXPECT_HR(hr, E_POINTER);
4217 /* versions 4 and 6 crash */
4218 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
4219 EXPECT_HR(hr, E_POINTER);
4221 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
4222 EXPECT_HR(hr, E_POINTER);
4224 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
4225 EXPECT_HR(hr, E_POINTER);
4227 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
4228 EXPECT_HR(hr, E_POINTER);
4230 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
4231 EXPECT_HR(hr, E_POINTER);
4233 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
4234 EXPECT_HR(hr, E_POINTER);
4236 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
4237 EXPECT_HR(hr, E_POINTER);
4239 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
4240 strlen(table->local), NULL, NULL);
4241 EXPECT_HR(hr, E_POINTER);
4244 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
4245 EXPECT_HR(hr, S_OK);
4246 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4247 table->value);
4248 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4250 if (table->uri) {
4251 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
4252 _bstr_(table->local), strlen(table->local), &value, &len);
4253 EXPECT_HR(hr, S_OK);
4254 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
4255 table->value);
4256 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
4260 len = -1;
4261 hr = ISAXAttributes_getLength(saxattr, &len);
4262 EXPECT_HR(hr, S_OK);
4263 if (table->hr == S_OK)
4264 ok(len == 1, "%d: got %d length, expected 0\n", i, len);
4265 else
4266 ok(len == 0, "%d: got %d length, expected 1\n", i, len);
4268 ISAXAttributes_Release(saxattr);
4269 IMXAttributes_Release(mxattr);
4271 table++;
4272 i++;
4275 free_bstrs();
4278 static void test_mxattr_clear(void)
4280 ISAXAttributes *saxattr;
4281 IMXAttributes *mxattr;
4282 const WCHAR *ptr;
4283 HRESULT hr;
4284 int len;
4286 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4287 &IID_IMXAttributes, (void**)&mxattr);
4288 EXPECT_HR(hr, S_OK);
4290 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4291 EXPECT_HR(hr, S_OK);
4293 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
4294 EXPECT_HR(hr, E_INVALIDARG);
4296 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4297 EXPECT_HR(hr, E_INVALIDARG);
4299 hr = IMXAttributes_clear(mxattr);
4300 EXPECT_HR(hr, S_OK);
4302 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
4303 _bstr_("qname"), _bstr_("type"), _bstr_("value"));
4304 EXPECT_HR(hr, S_OK);
4306 len = -1;
4307 hr = ISAXAttributes_getLength(saxattr, &len);
4308 EXPECT_HR(hr, S_OK);
4309 ok(len == 1, "got %d\n", len);
4311 len = -1;
4312 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
4313 EXPECT_HR(hr, E_POINTER);
4314 ok(len == -1, "got %d\n", len);
4316 ptr = (void*)0xdeadbeef;
4317 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
4318 EXPECT_HR(hr, E_POINTER);
4319 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4321 len = 0;
4322 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4323 EXPECT_HR(hr, S_OK);
4324 ok(len == 5, "got %d\n", len);
4325 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr));
4327 hr = IMXAttributes_clear(mxattr);
4328 EXPECT_HR(hr, S_OK);
4330 len = -1;
4331 hr = ISAXAttributes_getLength(saxattr, &len);
4332 EXPECT_HR(hr, S_OK);
4333 ok(len == 0, "got %d\n", len);
4335 len = -1;
4336 ptr = (void*)0xdeadbeef;
4337 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
4338 EXPECT_HR(hr, E_INVALIDARG);
4339 ok(len == -1, "got %d\n", len);
4340 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
4342 IMXAttributes_Release(mxattr);
4343 ISAXAttributes_Release(saxattr);
4344 free_bstrs();
4347 static void test_mxattr_dispex(void)
4349 IMXAttributes *mxattr;
4350 IDispatchEx *dispex;
4351 IUnknown *unk;
4352 HRESULT hr;
4354 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4355 &IID_IMXAttributes, (void**)&mxattr);
4356 EXPECT_HR(hr, S_OK);
4358 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
4359 EXPECT_HR(hr, S_OK);
4360 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
4361 test_obj_dispex(unk);
4362 IUnknown_Release(unk);
4363 IDispatchEx_Release(dispex);
4365 IMXAttributes_Release(mxattr);
4368 static void test_mxattr_qi(void)
4370 IVBSAXAttributes *vbsaxattr, *vbsaxattr2;
4371 ISAXAttributes *saxattr;
4372 IMXAttributes *mxattr;
4373 HRESULT hr;
4375 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER,
4376 &IID_IMXAttributes, (void**)&mxattr);
4377 EXPECT_HR(hr, S_OK);
4379 EXPECT_REF(mxattr, 1);
4380 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4381 EXPECT_HR(hr, S_OK);
4383 EXPECT_REF(mxattr, 2);
4384 EXPECT_REF(saxattr, 2);
4386 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr);
4387 EXPECT_HR(hr, S_OK);
4389 EXPECT_REF(vbsaxattr, 3);
4390 EXPECT_REF(mxattr, 3);
4391 EXPECT_REF(saxattr, 3);
4393 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2);
4394 EXPECT_HR(hr, S_OK);
4396 EXPECT_REF(vbsaxattr, 4);
4397 EXPECT_REF(mxattr, 4);
4398 EXPECT_REF(saxattr, 4);
4400 IMXAttributes_Release(mxattr);
4401 ISAXAttributes_Release(saxattr);
4402 IVBSAXAttributes_Release(vbsaxattr);
4403 IVBSAXAttributes_Release(vbsaxattr2);
4406 static struct msxmlsupported_data_t saxattr_support_data[] =
4408 { &CLSID_SAXAttributes, "SAXAttributes" },
4409 { &CLSID_SAXAttributes30, "SAXAttributes30" },
4410 { &CLSID_SAXAttributes40, "SAXAttributes40" },
4411 { &CLSID_SAXAttributes60, "SAXAttributes60" },
4412 { NULL }
4415 static void test_mxattr_localname(void)
4417 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0};
4418 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0};
4419 static const WCHAR uri1W[] = {'u','r','i','1',0};
4420 static const WCHAR uriW[] = {'u','r','i',0};
4422 const struct msxmlsupported_data_t *table = saxattr_support_data;
4424 while (table->clsid)
4426 ISAXAttributes *saxattr;
4427 IMXAttributes *mxattr;
4428 HRESULT hr;
4429 int index;
4431 if (!is_clsid_supported(table->clsid, mxattributes_support_data))
4433 table++;
4434 continue;
4437 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
4438 &IID_IMXAttributes, (void**)&mxattr);
4439 EXPECT_HR(hr, S_OK);
4441 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
4442 EXPECT_HR(hr, S_OK);
4444 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
4445 EXPECT_HR(hr, E_INVALIDARG);
4447 /* add some ambiguos attribute names */
4448 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4449 _bstr_("a:localname"), _bstr_(""), _bstr_("value"));
4450 EXPECT_HR(hr, S_OK);
4451 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
4452 _bstr_("b:localname"), _bstr_(""), _bstr_("value"));
4453 EXPECT_HR(hr, S_OK);
4455 index = -1;
4456 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index);
4457 EXPECT_HR(hr, S_OK);
4458 ok(index == 0, "%s: got index %d\n", table->name, index);
4460 index = -1;
4461 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index);
4462 EXPECT_HR(hr, E_INVALIDARG);
4463 ok(index == -1, "%s: got index %d\n", table->name, index);
4465 index = -1;
4466 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index);
4467 EXPECT_HR(hr, E_INVALIDARG);
4468 ok(index == -1, "%s: got index %d\n", table->name, index);
4470 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
4471 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
4473 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4474 EXPECT_HR(hr, E_POINTER);
4476 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4477 EXPECT_HR(hr, E_POINTER);
4479 else
4481 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
4482 EXPECT_HR(hr, E_INVALIDARG);
4484 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL);
4485 EXPECT_HR(hr, E_INVALIDARG);
4488 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index);
4489 EXPECT_HR(hr, E_INVALIDARG);
4491 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index);
4492 EXPECT_HR(hr, E_INVALIDARG);
4494 table++;
4496 ISAXAttributes_Release(saxattr);
4497 IMXAttributes_Release(mxattr);
4501 START_TEST(saxreader)
4503 ISAXXMLReader *reader;
4504 HRESULT hr;
4506 hr = CoInitialize(NULL);
4507 ok(hr == S_OK, "failed to init com\n");
4509 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
4510 &IID_ISAXXMLReader, (void**)&reader);
4512 if(FAILED(hr))
4514 skip("Failed to create SAXXMLReader instance\n");
4515 CoUninitialize();
4516 return;
4518 ISAXXMLReader_Release(reader);
4520 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4522 get_class_support_data(reader_support_data, &IID_ISAXXMLReader);
4524 test_saxreader();
4525 test_saxreader_properties();
4526 test_saxreader_features();
4527 test_saxreader_encoding();
4528 test_dispex();
4530 /* MXXMLWriter tests */
4531 get_class_support_data(mxwriter_support_data, &IID_IMXWriter);
4532 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data))
4534 test_mxwriter_handlers();
4535 test_mxwriter_startenddocument();
4536 test_mxwriter_startendelement();
4537 test_mxwriter_characters();
4538 test_mxwriter_comment();
4539 test_mxwriter_cdata();
4540 test_mxwriter_pi();
4541 test_mxwriter_ignorablespaces();
4542 test_mxwriter_dtd();
4543 test_mxwriter_properties();
4544 test_mxwriter_flush();
4545 test_mxwriter_stream();
4546 test_mxwriter_encoding();
4547 test_mxwriter_dispex();
4549 else
4550 win_skip("MXXMLWriter not supported\n");
4552 /* SAXAttributes tests */
4553 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes);
4554 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data))
4556 test_mxattr_qi();
4557 test_mxattr_addAttribute();
4558 test_mxattr_clear();
4559 test_mxattr_localname();
4560 test_mxattr_dispex();
4562 else
4563 skip("SAXAttributes not supported\n");
4565 CoUninitialize();