ReactOS 0.4.15-dev-8393-g61b7fb9
saxreader.c
Go to the documentation of this file.
1/*
2 * SAXReader/MXWriter tests
3 *
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
6 * Copyright 2012 Nikolay Sivov
7 *
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.
12 *
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.
17 *
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
21 */
22
23#define COBJMACROS
24#define CONST_VTABLE
25
26#include <stdio.h>
27#include <assert.h>
28
29#include "windows.h"
30#include "ole2.h"
31#include "msxml2.h"
32#include "msxml2did.h"
33#include "ocidl.h"
34#include "dispex.h"
35
36#include "wine/heap.h"
37#include "wine/test.h"
38
39static const WCHAR emptyW[] = {0};
40
41#define EXPECT_HR(hr,hr_exp) \
42 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
43
44#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
45static void _expect_ref(IUnknown* obj, ULONG ref, int line)
46{
47 ULONG rc;
48 IUnknown_AddRef(obj);
49 rc = IUnknown_Release(obj);
50 ok_(__FILE__, line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
51}
52
53static LONG get_refcount(void *iface)
54{
55 IUnknown *unk = iface;
56 LONG ref;
57
58 ref = IUnknown_AddRef(unk);
59 IUnknown_Release(unk);
60 return ref-1;
61}
62
64{
65 const GUID *clsid;
66 const char *name;
68};
69
71{
72 while (table->clsid)
73 {
74 if (table->clsid == clsid) return table->supported;
75 table++;
76 }
77 return FALSE;
78}
79
80static BSTR alloc_str_from_narrow(const char *str)
81{
82 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
83 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
85 return ret;
86}
87
88static BSTR alloced_bstrs[512];
90
91static BSTR _bstr_(const char *str)
92{
96}
97
98static void free_bstrs(void)
99{
100 int i;
101 for (i = 0; i < alloced_bstrs_count; i++)
104}
105
106static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, BOOL todo, int *failcount)
107{
108 int len, lenexp, cmp;
109 WCHAR buf[1024];
110
112
113 if (!expected) {
114 if (str && todo)
115 {
116 (*failcount)++;
118 ok_(file, line) (!str, "got %p, expected null str\n", str);
119 }
120 else
121 ok_(file, line) (!str, "got %p, expected null str\n", str);
122
123 if (len && todo)
124 {
125 (*failcount)++;
127 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
128 }
129 else
130 ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
131 return;
132 }
133
134 lenexp = strlen(expected);
135 if (lenexp != len && todo)
136 {
137 (*failcount)++;
139 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
140 }
141 else
142 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected);
143
144 /* exit earlier on length mismatch */
145 if (lenexp != len) return;
146
148
149 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR));
150 if (cmp && todo)
151 {
152 (*failcount)++;
154 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
156 }
157 else
158 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n",
160}
161
162typedef enum _CH {
182
183static const char *event_names[EVENT_LAST] = {
184 "endtest",
185 "putDocumentLocator",
186 "startDocument",
187 "endDocument",
188 "startPrefixMapping",
189 "endPrefixMapping",
190 "startElement",
191 "endElement",
192 "characters",
193 "ignorableWhitespace",
194 "processingInstruction",
195 "skippedEntity",
196 "startCDATA",
197 "endCDATA",
198 "error",
199 "fatalError",
200 "ignorableWarning"
201};
202
204 const char *uri;
205 const char *local;
206 const char *qname;
207 const char *value;
208
209 /* used for actual call data only, null for expected call data */
214};
215
218 int line;
221 const char *arg1;
222 const char *arg2;
223 const char *arg3;
224
225 /* allocated once at startElement callback */
228
229 /* used for actual call data only, null for expected call data */
233};
234
236{
237 int count;
238 int size;
240};
241
242#define CONTENT_HANDLER_INDEX 0
243#define NUM_CALL_SEQUENCES 1
245
246static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
247{
248 memset(call, 0, sizeof(*call));
249 ISAXLocator_getLineNumber(locator, &call->line);
250 ISAXLocator_getColumnNumber(locator, &call->column);
251}
252
253static void add_call(struct call_sequence **seq, int sequence_index,
254 const struct call_entry *call)
255{
256 struct call_sequence *call_seq = seq[sequence_index];
257
258 if (!call_seq->sequence)
259 {
260 call_seq->size = 10;
261 call_seq->sequence = heap_alloc(call_seq->size * sizeof (struct call_entry));
262 }
263
264 if (call_seq->count == call_seq->size)
265 {
266 call_seq->size *= 2;
267 call_seq->sequence = heap_realloc(call_seq->sequence, call_seq->size * sizeof (struct call_entry));
268 }
269
270 assert(call_seq->sequence);
271
272 call_seq->sequence[call_seq->count].id = call->id;
273 call_seq->sequence[call_seq->count].line = call->line;
274 call_seq->sequence[call_seq->count].column = call->column;
275 call_seq->sequence[call_seq->count].arg1W = call->arg1W;
276 call_seq->sequence[call_seq->count].arg2W = call->arg2W;
277 call_seq->sequence[call_seq->count].arg3W = call->arg3W;
278 call_seq->sequence[call_seq->count].ret = call->ret;
279 call_seq->sequence[call_seq->count].attr_count = call->attr_count;
280 call_seq->sequence[call_seq->count].attributes = call->attributes;
281
282 call_seq->count++;
283}
284
285static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
286{
287 int i;
288
289 struct call_sequence *call_seq = seg[sequence_index];
290
291 for (i = 0; i < call_seq->count; i++)
292 {
293 int j;
294
295 for (j = 0; j < call_seq->sequence[i].attr_count; j++)
296 {
297 SysFreeString(call_seq->sequence[i].attributes[j].uriW);
298 SysFreeString(call_seq->sequence[i].attributes[j].localW);
299 SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
300 SysFreeString(call_seq->sequence[i].attributes[j].valueW);
301 }
302 heap_free(call_seq->sequence[i].attributes);
303 call_seq->sequence[i].attr_count = 0;
304
305 SysFreeString(call_seq->sequence[i].arg1W);
306 SysFreeString(call_seq->sequence[i].arg2W);
307 SysFreeString(call_seq->sequence[i].arg3W);
308 }
309
310 heap_free(call_seq->sequence);
311 call_seq->sequence = NULL;
312 call_seq->count = call_seq->size = 0;
313}
314
315static const char *get_event_name(CH event)
316{
317 return event_names[event];
318}
319
320static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
321 BOOL todo, const char *file, int line, int *failcount)
322{
323 int i, lenexp = 0;
324
325 /* attribute count is not stored for expected data */
326 if (expected->attributes)
327 {
328 struct attribute_entry *ptr = expected->attributes;
329 while (ptr->uri) { lenexp++; ptr++; };
330 }
331
332 /* check count first and exit earlier */
333 if (actual->attr_count != lenexp && todo)
334 {
335 (*failcount)++;
337 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
338 context, get_event_name(actual->id), lenexp, actual->attr_count);
339 }
340 else
341 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
342 context, get_event_name(actual->id), lenexp, actual->attr_count);
343
344 if (actual->attr_count != lenexp) return;
345
346 /* now compare all attributes strings */
347 for (i = 0; i < actual->attr_count; i++)
348 {
349 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
350 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
351 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
352 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
353 }
354}
355
356static void ok_sequence_(struct call_sequence **seq, int sequence_index,
357 const struct call_entry *expected, const char *context, BOOL todo,
358 const char *file, int line)
359{
360 struct call_sequence *call_seq = seq[sequence_index];
361 static const struct call_entry end_of_sequence = { CH_ENDTEST };
362 const struct call_entry *actual, *sequence;
363 int failcount = 0;
364
365 add_call(seq, sequence_index, &end_of_sequence);
366
367 sequence = call_seq->sequence;
368 actual = sequence;
369
370 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
371 {
372 if (expected->id == actual->id)
373 {
374 if (expected->line != -1)
375 {
376 /* always test position data */
377 if (expected->line != actual->line && todo)
378 {
380 {
381 failcount++;
382 ok_(file, line) (FALSE,
383 "%s: in event %s expecting line %d got %d\n",
384 context, get_event_name(actual->id), expected->line, actual->line);
385 }
386 }
387 else
388 {
389 ok_(file, line) (expected->line == actual->line,
390 "%s: in event %s expecting line %d got %d\n",
391 context, get_event_name(actual->id), expected->line, actual->line);
392 }
393 }
394
395
396 if (expected->column != -1)
397 {
398 if (expected->column != actual->column && todo)
399 {
401 {
402 failcount++;
403 ok_(file, line) (FALSE,
404 "%s: in event %s expecting column %d got %d\n",
405 context, get_event_name(actual->id), expected->column, actual->column);
406 }
407 }
408 else
409 {
410 ok_(file, line) (expected->column == actual->column,
411 "%s: in event %s expecting column %d got %d\n",
412 context, get_event_name(actual->id), expected->column, actual->column);
413 }
414 }
415
416 switch (actual->id)
417 {
419 case CH_STARTDOCUMENT:
420 case CH_ENDDOCUMENT:
421 case LH_STARTCDATA:
422 case LH_ENDCDATA:
423 break;
425 /* prefix, uri */
426 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
427 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
428 break;
430 /* prefix */
431 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
432 break;
433 case CH_STARTELEMENT:
434 /* compare attributes */
435 compare_attributes(actual, expected, context, todo, file, line, &failcount);
436 /* fallthrough */
437 case CH_ENDELEMENT:
438 /* uri, localname, qname */
439 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
440 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
441 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
442 break;
443 case CH_CHARACTERS:
445 /* char data */
446 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
447 break;
449 /* target, data */
450 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
451 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
452 break;
453 case CH_SKIPPEDENTITY:
454 /* name */
455 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
456 break;
457 case EH_FATALERROR:
458 /* test return value only */
459 if (expected->ret != actual->ret && todo)
460 {
461 failcount++;
462 ok_(file, line) (FALSE,
463 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
464 context, get_event_name(actual->id), expected->ret, actual->ret);
465 }
466 else
467 ok_(file, line) (expected->ret == actual->ret,
468 "%s: in event %s expecting ret 0x%08x got 0x%08x\n",
469 context, get_event_name(actual->id), expected->ret, actual->ret);
470 break;
471 case EH_ERROR:
473 default:
474 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
475 }
476 expected++;
477 actual++;
478 }
479 else if (todo)
480 {
481 failcount++;
483 {
484 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
486 }
487
488 flush_sequence(seq, sequence_index);
489 return;
490 }
491 else
492 {
493 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
495 expected++;
496 actual++;
497 }
498 }
499
500 if (todo)
501 {
503 {
504 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
505 {
506 failcount++;
507 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
509 }
510 }
511 }
512 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
513 {
514 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
516 }
517
518 if (todo && !failcount) /* succeeded yet marked todo */
519 {
521 {
522 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
523 }
524 }
525
526 flush_sequence(seq, sequence_index);
527}
528
529#define ok_sequence(seq, index, exp, contx, todo) \
530 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
531
532static void init_call_sequences(struct call_sequence **seq, int n)
533{
534 int i;
535
536 for (i = 0; i < n; i++)
537 seq[i] = heap_alloc_zero(sizeof(struct call_sequence));
538}
539
540static const WCHAR szSimpleXML[] = {
541'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
542'<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
543' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
544' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
545'<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
546};
547
548static const WCHAR carriage_ret_test[] = {
549'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
550'<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
551'\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
552'\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
553'<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
554};
555
556static const WCHAR szUtf16XML[] = {
557'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
558'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
559's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
560};
561
562static const CHAR szUtf16BOM[] = {0xff, 0xfe};
563
564static const CHAR szUtf8XML[] =
565"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
566
567static const char utf8xml2[] =
568"<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n";
569
570static const char testXML[] =
571"<?xml version=\"1.0\" ?>\n"
572"<BankAccount>\n"
573" <Number>1234</Number>\n"
574" <Name>Captain Ahab</Name>\n"
575"</BankAccount>\n";
576
577static const char test_attributes[] =
578"<?xml version=\"1.0\" ?>\n"
579"<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
580"<node1 xmlns:p=\"test\" />"
581"</document>\n";
582
583static const char test_cdata_xml[] =
584"<?xml version=\"1.0\" ?>"
585"<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
586
587static const char test2_cdata_xml[] =
588"<?xml version=\"1.0\" ?>"
589"<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
590
591static const char test3_cdata_xml[] =
592"<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
593
595 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
596 { CH_STARTDOCUMENT, 0, 0, S_OK },
597 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
598 { CH_CHARACTERS, 2, 14, S_OK, "\n " },
599 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" },
600 { CH_CHARACTERS, 3, 12, S_OK, "1234" },
601 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" },
602 { CH_CHARACTERS, 3, 25, S_OK, "\n " },
603 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" },
604 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" },
605 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" },
606 { CH_CHARACTERS, 4, 29, S_OK, "\n" },
607 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
608 { CH_ENDDOCUMENT, 0, 0, S_OK},
609 { CH_ENDTEST }
610};
611
612/* applies to versions 4 and 6 */
614 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
615 { CH_STARTDOCUMENT, 1, 22, S_OK },
616 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
617 { CH_CHARACTERS, 3, 4, S_OK, "\n " },
618 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" },
619 { CH_CHARACTERS, 3, 16, S_OK, "1234" },
620 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" },
621 { CH_CHARACTERS, 4, 4, S_OK, "\n " },
622 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" },
623 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" },
624 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" },
625 { CH_CHARACTERS, 5, 1, S_OK, "\n" },
626 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
627 { CH_ENDDOCUMENT, 6, 0, S_OK },
628 { CH_ENDTEST }
629};
630
632 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
633 { CH_STARTDOCUMENT, 0, 0, S_OK },
634 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" },
635 { CH_CHARACTERS, 2, 14, S_OK, "\n" },
636 { CH_CHARACTERS, 2, 16, S_OK, "\t" },
637 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" },
638 { CH_CHARACTERS, 3, 10, S_OK, "1234" },
639 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" },
640 { CH_CHARACTERS, 3, 23, S_OK, "\n" },
641 { CH_CHARACTERS, 3, 25, S_OK, "\t" },
642 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" },
643 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" },
644 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" },
645 { CH_CHARACTERS, 4, 27, S_OK, "\n" },
646 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" },
647 { CH_ENDDOCUMENT, 0, 0, S_OK },
648 { CH_ENDTEST }
649};
650
652 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
653 { CH_STARTDOCUMENT, 1, 21, S_OK },
654 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" },
655 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
656 { CH_CHARACTERS, 3, 2, S_OK, "\t" },
657 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" },
658 { CH_CHARACTERS, 3, 14, S_OK, "1234" },
659 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" },
660 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
661 { CH_CHARACTERS, 4, 2, S_OK, "\t" },
662 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" },
663 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" },
664 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" },
665 { CH_CHARACTERS, 5, 0, S_OK, "\n" },
666 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" },
667 { CH_ENDDOCUMENT, 6, 0, S_OK },
668 { CH_ENDTEST }
669};
670
672 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL },
673 { EH_FATALERROR, 0, 0, E_FAIL },
674 { CH_ENDTEST }
675};
676
678 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
679 { EH_FATALERROR, 1, 0, E_FAIL },
680 { CH_ENDTEST }
681};
682
685 { CH_STARTDOCUMENT, 0, 0, S_FALSE },
686 { EH_FATALERROR, 0, 0, S_FALSE },
687 { CH_ENDTEST }
688};
689
692 { CH_STARTDOCUMENT, 1, 22, S_FALSE },
693 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" },
694 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " },
695 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" },
696 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" },
697 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" },
698 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " },
699 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" },
700 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" },
701 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" },
702 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" },
703 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" },
704 { CH_ENDDOCUMENT, 6, 0, S_FALSE },
705 { CH_ENDTEST }
706};
707
709 { "", "", "xmlns:test", "prefix_test" },
710 { "", "", "xmlns", "prefix" },
711 { "prefix_test", "arg1", "test:arg1", "arg1" },
712 { "", "arg2", "arg2", "arg2" },
713 { "prefix_test", "ar3", "test:ar3", "arg3" },
714 { NULL }
715};
716
718 { "", "", "xmlns:p", "test" },
719 { NULL }
720};
721
723 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
724 { CH_STARTDOCUMENT, 0, 0, S_OK },
725 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
726 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
727 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 },
728 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
729 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
730 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 },
731 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
732 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
733 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
734 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
735 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
736 { CH_ENDDOCUMENT, 0, 0 },
737 { CH_ENDTEST }
738};
739
741 { "prefix_test", "arg1", "test:arg1", "arg1" },
742 { "", "arg2", "arg2", "arg2" },
743 { "prefix_test", "ar3", "test:ar3", "arg3" },
744 { "", "", "xmlns:test", "prefix_test" },
745 { "", "", "xmlns", "prefix" },
746 { NULL }
747};
748
750 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
751 { CH_STARTDOCUMENT, 1, 22, S_OK },
752 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
753 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
754 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 },
755 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
756 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
757 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 },
758 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
759 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
760 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
761 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
762 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
763 { CH_ENDDOCUMENT, 4, 0, S_OK },
764 { CH_ENDTEST }
765};
766
767/* 'namespace' feature switched off */
769 { "", "", "xmlns:test", "prefix_test" },
770 { "", "", "xmlns", "prefix" },
771 { "", "", "test:arg1", "arg1" },
772 { "", "", "arg2", "arg2" },
773 { "", "", "test:ar3", "arg3" },
774 { NULL }
775};
776
778 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
779 { CH_STARTDOCUMENT, 1, 22, S_OK },
780 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns },
781 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
782 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 },
783 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" },
784 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" },
785 { CH_ENDDOCUMENT, 4, 0, S_OK },
786 { CH_ENDTEST }
787};
788
790 { "prefix_test", "arg1", "test:arg1", "arg1" },
791 { "", "arg2", "arg2", "arg2" },
792 { "prefix_test", "ar3", "test:ar3", "arg3" },
793 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" },
794 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" },
795 { NULL }
796};
797
799 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" },
800 { NULL }
801};
802
804 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
805 { CH_STARTDOCUMENT, 1, 22, S_OK },
806 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
807 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
808 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 },
809 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
810 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
811 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 },
812 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
813 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
814 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
815 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
816 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
817 { CH_ENDDOCUMENT, 4, 0, S_OK },
818 { CH_ENDTEST }
819};
820
821/* 'namespaces' is on, 'namespace-prefixes' if off */
823 { "prefix_test", "arg1", "test:arg1", "arg1" },
824 { "", "arg2", "arg2", "arg2" },
825 { "prefix_test", "ar3", "test:ar3", "arg3" },
826 { NULL }
827};
828
830 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
831 { CH_STARTDOCUMENT, 1, 22, S_OK },
832 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" },
833 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" },
834 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
835 { CH_CHARACTERS, 3, 1, S_OK, "\n" },
836 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" },
837 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL },
838 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" },
839 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" },
840 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" },
841 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" },
842 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" },
843 { CH_ENDDOCUMENT, 4, 0, S_OK },
844 { CH_ENDTEST }
845};
846
848 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
849 { CH_STARTDOCUMENT, 0, 0, S_OK },
850 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" },
851 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" },
852 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix },
853 { CH_CHARACTERS, 2, 96, S_OK, "\n" },
854 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" },
855 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL },
856 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" },
857 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" },
858 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" },
859 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" },
860 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" },
861 { CH_ENDDOCUMENT, 0, 0 },
862 { CH_ENDTEST }
863};
864
866 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" },
867 { NULL }
868};
869
870static struct call_entry xmlspaceattr_test[] = {
871 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
872 { CH_STARTDOCUMENT, 0, 0, S_OK },
873 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs },
874 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " },
875 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" },
876 { CH_ENDDOCUMENT, 0, 0, S_OK },
877 { CH_ENDTEST }
878};
879
881 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
882 { CH_STARTDOCUMENT, 1, 39, S_OK },
883 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs },
884 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " },
885 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" },
886 { CH_ENDDOCUMENT, 1, 83, S_OK },
887 { CH_ENDTEST }
888};
889
890/* attribute value normalization test */
891static const char attribute_normalize[] =
892 "<?xml version=\"1.0\" ?>\n"
893 "<a attr1=\" \r \n \tattr_value &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
894
896 { "", "attr1", "attr1", " attr_value A & & " },
897 { NULL }
898};
899
900static struct call_entry attribute_norm[] = {
901 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
902 { CH_STARTDOCUMENT, 0, 0, S_OK },
903 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs },
904 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" },
905 { CH_ENDDOCUMENT, 0, 0, S_OK },
906 { CH_ENDTEST }
907};
908
910 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
911 { CH_STARTDOCUMENT, 1, 22, S_OK },
912 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs },
913 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" },
914 { CH_ENDDOCUMENT, 9, 0, S_OK },
915 { CH_ENDTEST }
916};
917
918static struct call_entry cdata_test[] = {
919 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
920 { CH_STARTDOCUMENT, 0, 0, S_OK },
921 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
922 { LH_STARTCDATA, 1, 35, S_OK },
923 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" },
924 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" },
925 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" },
926 { LH_ENDCDATA, 1, 49, S_OK },
927 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" },
928 { CH_ENDDOCUMENT, 0, 0, S_OK },
929 { CH_ENDTEST }
930};
931
932static struct call_entry cdata_test2[] = {
933 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
934 { CH_STARTDOCUMENT, 0, 0, S_OK },
935 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
936 { LH_STARTCDATA, 1, 35, S_OK },
937 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" },
938 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" },
939 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" },
940 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" },
941 { LH_ENDCDATA, 1, 52, S_OK },
942 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" },
943 { CH_ENDDOCUMENT, 0, 0, S_OK },
944 { CH_ENDTEST }
945};
946
947static struct call_entry cdata_test3[] = {
948 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK },
949 { CH_STARTDOCUMENT, 0, 0, S_OK },
950 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" },
951 { LH_STARTCDATA, 1, 35, S_OK },
952 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" },
953 { LH_ENDCDATA, 1, 35, S_OK },
954 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" },
955 { CH_ENDDOCUMENT, 0, 0, S_OK },
956 { CH_ENDTEST }
957};
958
959/* this is what MSXML6 does */
960static struct call_entry cdata_test_alt[] = {
961 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
962 { CH_STARTDOCUMENT, 1, 22, S_OK },
963 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
964 { LH_STARTCDATA, 1, 34, S_OK },
965 { CH_CHARACTERS, 1, 40, S_OK, "Some " },
966 { CH_CHARACTERS, 2, 0, S_OK, "\n" },
967 { CH_CHARACTERS, 3, 1, S_OK, "text\n" },
968 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
969 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" },
970 { LH_ENDCDATA, 6, 3, S_OK },
971 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" },
972 { CH_ENDDOCUMENT, 6, 7, S_OK },
973 { CH_ENDTEST }
974};
975
976static struct call_entry cdata_test2_alt[] = {
977 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
978 { CH_STARTDOCUMENT, 1, 22, S_OK },
979 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
980 { LH_STARTCDATA, 1, 34, S_OK },
981 { CH_CHARACTERS, 2, 1, S_OK, "\n" },
982 { CH_CHARACTERS, 3, 0, S_OK, "\n" },
983 { CH_CHARACTERS, 3, 6, S_OK, "Some " },
984 { CH_CHARACTERS, 4, 0, S_OK, "\n" },
985 { CH_CHARACTERS, 5, 1, S_OK, "text\n" },
986 { CH_CHARACTERS, 6, 0, S_OK, "\n" },
987 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" },
988 { LH_ENDCDATA, 8, 3, S_OK },
989 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" },
990 { CH_ENDDOCUMENT, 8, 7, S_OK },
991 { CH_ENDTEST }
992};
993
994static struct call_entry cdata_test3_alt[] = {
995 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
996 { CH_STARTDOCUMENT, 1, 22, S_OK },
997 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" },
998 { LH_STARTCDATA, 1, 34, S_OK },
999 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" },
1000 { LH_ENDCDATA, 1, 51, S_OK },
1001 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" },
1002 { CH_ENDDOCUMENT, 1, 55, S_OK },
1003 { CH_ENDTEST }
1004};
1005
1007 { "", "attr", "attr", "val" },
1008 { NULL }
1009};
1010
1011static struct call_entry read_test_seq[] = {
1012 { CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK },
1013 { CH_STARTDOCUMENT, -1, -1, S_OK },
1014 { CH_STARTELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1015 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1016 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1017 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1018 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1019 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1020 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1021 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1022 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1023 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1024 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs },
1025 { CH_CHARACTERS, -1, -1, S_OK, "text" },
1026 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" },
1027 { CH_ENDELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" },
1028 { CH_ENDDOCUMENT, -1, -1, S_OK},
1029 { CH_ENDTEST }
1030};
1031
1032static const char xmlspace_attr[] =
1033 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
1034 "<a xml:space=\"preserve\"> Some text data </a>";
1035
1036static struct call_entry *expectCall;
1037static ISAXLocator *locator;
1038static ISAXXMLReader *g_reader;
1040
1042{
1044}
1045
1046/* to be called once on each tested callback return */
1048{
1049 HRESULT hr = expectCall->ret;
1050 if (expectCall->id != CH_ENDTEST) expectCall++;
1051 return hr;
1052}
1053
1055 ISAXContentHandler* iface,
1056 REFIID riid,
1057 void **ppvObject)
1058{
1059 *ppvObject = NULL;
1060
1061 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
1062 {
1063 *ppvObject = iface;
1064 }
1065 else
1066 {
1067 return E_NOINTERFACE;
1068 }
1069
1070 return S_OK;
1071}
1072
1074 ISAXContentHandler* iface)
1075{
1076 return 2;
1077}
1078
1080 ISAXContentHandler* iface)
1081{
1082 return 1;
1083}
1084
1086 ISAXContentHandler* iface,
1087 ISAXLocator *pLocator)
1088{
1089 struct call_entry call;
1090 IUnknown *unk;
1091 HRESULT hr;
1092
1093 locator = pLocator;
1094
1095 init_call_entry(locator, &call);
1098
1099 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
1101
1102 if (msxml_version >= 6) {
1103 ISAXAttributes *attr, *attr1;
1104 IMXAttributes *mxattr;
1105
1106 EXPECT_REF(pLocator, 1);
1107 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
1108 EXPECT_HR(hr, S_OK);
1109 EXPECT_REF(pLocator, 2);
1110 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
1111 EXPECT_HR(hr, S_OK);
1112 EXPECT_REF(pLocator, 3);
1113 ok(attr == attr1, "got %p, %p\n", attr, attr1);
1114
1115 hr = ISAXAttributes_QueryInterface(attr, &IID_IVBSAXAttributes, (void**)&unk);
1117
1118 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk);
1120
1121 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr);
1123
1124 ISAXAttributes_Release(attr);
1125 ISAXAttributes_Release(attr1);
1126 }
1127
1128 return get_expected_ret();
1129}
1130
1131static ISAXAttributes *test_attr_ptr;
1133 ISAXContentHandler* iface)
1134{
1135 struct call_entry call;
1136
1137 init_call_entry(locator, &call);
1138 call.id = CH_STARTDOCUMENT;
1140
1142
1143 return get_expected_ret();
1144}
1145
1147 ISAXContentHandler* iface)
1148{
1149 struct call_entry call;
1150
1151 init_call_entry(locator, &call);
1152 call.id = CH_ENDDOCUMENT;
1154
1155 return get_expected_ret();
1156}
1157
1159 ISAXContentHandler* iface,
1160 const WCHAR *prefix, int prefix_len,
1161 const WCHAR *uri, int uri_len)
1162{
1163 struct call_entry call;
1164
1165 ok(prefix != NULL, "prefix == NULL\n");
1166 ok(uri != NULL, "uri == NULL\n");
1167
1168 init_call_entry(locator, &call);
1170 call.arg1W = SysAllocStringLen(prefix, prefix_len);
1171 call.arg2W = SysAllocStringLen(uri, uri_len);
1173
1174 return get_expected_ret();
1175}
1176
1178 ISAXContentHandler* iface,
1179 const WCHAR *prefix, int len)
1180{
1181 struct call_entry call;
1182
1183 ok(prefix != NULL, "prefix == NULL\n");
1184
1185 init_call_entry(locator, &call);
1186 call.id = CH_ENDPREFIXMAPPING;
1187 call.arg1W = SysAllocStringLen(prefix, len);
1189
1190 return get_expected_ret();
1191}
1192
1194 ISAXContentHandler* iface,
1195 const WCHAR *uri, int uri_len,
1196 const WCHAR *localname, int local_len,
1197 const WCHAR *qname, int qname_len,
1198 ISAXAttributes *saxattr)
1199{
1200 struct call_entry call;
1201 IMXAttributes *mxattr;
1202 HRESULT hr;
1203 int len;
1204
1205 ok(uri != NULL, "uri == NULL\n");
1206 ok(localname != NULL, "localname == NULL\n");
1207 ok(qname != NULL, "qname == NULL\n");
1208
1209 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr);
1211
1212 init_call_entry(locator, &call);
1213 call.id = CH_STARTELEMENT;
1214 call.arg1W = SysAllocStringLen(uri, uri_len);
1215 call.arg2W = SysAllocStringLen(localname, local_len);
1216 call.arg3W = SysAllocStringLen(qname, qname_len);
1217
1218 if(!test_attr_ptr)
1219 test_attr_ptr = saxattr;
1220 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
1221
1222 /* store actual attributes */
1223 len = 0;
1224 hr = ISAXAttributes_getLength(saxattr, &len);
1225 EXPECT_HR(hr, S_OK);
1226
1227 if (len)
1228 {
1230 int i;
1231
1232 struct attribute_entry *attr;
1233 attr = heap_alloc_zero(len * sizeof(*attr));
1234
1235 v = VARIANT_TRUE;
1236 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v);
1237 EXPECT_HR(hr, S_OK);
1238
1239 for (i = 0; i < len; i++)
1240 {
1241 const WCHAR *value;
1242 int value_len;
1243
1244 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
1245 &localname, &local_len, &qname, &qname_len);
1246 EXPECT_HR(hr, S_OK);
1247
1248 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
1249 EXPECT_HR(hr, S_OK);
1250
1251 /* if 'namespaces' switched off uri and local name contains garbage */
1252 if (v == VARIANT_FALSE && msxml_version > 0)
1253 {
1254 attr[i].uriW = SysAllocStringLen(NULL, 0);
1255 attr[i].localW = SysAllocStringLen(NULL, 0);
1256 }
1257 else
1258 {
1259 attr[i].uriW = SysAllocStringLen(uri, uri_len);
1260 attr[i].localW = SysAllocStringLen(localname, local_len);
1261 }
1262
1263 attr[i].qnameW = SysAllocStringLen(qname, qname_len);
1264 attr[i].valueW = SysAllocStringLen(value, value_len);
1265 }
1266
1267 call.attributes = attr;
1268 call.attr_count = len;
1269 }
1270
1272
1273 return get_expected_ret();
1274}
1275
1277 ISAXContentHandler* iface,
1278 const WCHAR *uri, int uri_len,
1279 const WCHAR *localname, int local_len,
1280 const WCHAR *qname, int qname_len)
1281{
1282 struct call_entry call;
1283
1284 ok(uri != NULL, "uri == NULL\n");
1285 ok(localname != NULL, "localname == NULL\n");
1286 ok(qname != NULL, "qname == NULL\n");
1287
1288 init_call_entry(locator, &call);
1289 call.id = CH_ENDELEMENT;
1290 call.arg1W = SysAllocStringLen(uri, uri_len);
1291 call.arg2W = SysAllocStringLen(localname, local_len);
1292 call.arg3W = SysAllocStringLen(qname, qname_len);
1294
1295 return get_expected_ret();
1296}
1297
1299 ISAXContentHandler* iface,
1300 const WCHAR *chars,
1301 int len)
1302{
1303 struct call_entry call;
1304
1305 ok(chars != NULL, "chars == NULL\n");
1306
1307 init_call_entry(locator, &call);
1308 call.id = CH_CHARACTERS;
1309 call.arg1W = SysAllocStringLen(chars, len);
1311
1312 return get_expected_ret();
1313}
1314
1316 ISAXContentHandler* iface,
1317 const WCHAR *chars, int len)
1318{
1319 struct call_entry call;
1320
1321 ok(chars != NULL, "chars == NULL\n");
1322
1323 init_call_entry(locator, &call);
1325 call.arg1W = SysAllocStringLen(chars, len);
1327
1328 return get_expected_ret();
1329}
1330
1332 ISAXContentHandler* iface,
1333 const WCHAR *target, int target_len,
1334 const WCHAR *data, int data_len)
1335{
1336 struct call_entry call;
1337
1338 ok(target != NULL, "target == NULL\n");
1339 ok(data != NULL, "data == NULL\n");
1340
1341 init_call_entry(locator, &call);
1343 call.arg1W = SysAllocStringLen(target, target_len);
1344 call.arg2W = SysAllocStringLen(data, data_len);
1346
1347 return get_expected_ret();
1348}
1349
1351 ISAXContentHandler* iface,
1352 const WCHAR *name, int len)
1353{
1354 struct call_entry call;
1355
1356 ok(name != NULL, "name == NULL\n");
1357
1358 init_call_entry(locator, &call);
1359 call.id = CH_SKIPPEDENTITY;
1362
1363 return get_expected_ret();
1364}
1365
1366static const ISAXContentHandlerVtbl contentHandlerVtbl =
1367{
1382};
1383
1384static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
1385
1387 ISAXErrorHandler* iface,
1388 REFIID riid,
1389 void **ppvObject)
1390{
1391 *ppvObject = NULL;
1392
1393 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
1394 {
1395 *ppvObject = iface;
1396 }
1397 else
1398 {
1399 return E_NOINTERFACE;
1400 }
1401
1402 return S_OK;
1403}
1404
1406 ISAXErrorHandler* iface)
1407{
1408 return 2;
1409}
1410
1412 ISAXErrorHandler* iface)
1413{
1414 return 1;
1415}
1416
1418 ISAXErrorHandler* iface,
1419 ISAXLocator *pLocator,
1420 const WCHAR *pErrorMessage,
1421 HRESULT hrErrorCode)
1422{
1423 ok(0, "unexpected call\n");
1424 return S_OK;
1425}
1426
1428 ISAXErrorHandler* iface,
1429 ISAXLocator *pLocator,
1430 const WCHAR *message,
1431 HRESULT hr)
1432{
1433 struct call_entry call;
1434
1435 init_call_entry(locator, &call);
1436 call.id = EH_FATALERROR;
1437 call.ret = hr;
1438
1440
1442 return S_OK;
1443}
1444
1446 ISAXErrorHandler* iface,
1447 ISAXLocator *pLocator,
1448 const WCHAR *pErrorMessage,
1449 HRESULT hrErrorCode)
1450{
1451 ok(0, "unexpected call\n");
1452 return S_OK;
1453}
1454
1455static const ISAXErrorHandlerVtbl errorHandlerVtbl =
1456{
1463};
1464
1465static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
1466
1468 ISAXAttributes* iface,
1469 REFIID riid,
1470 void **ppvObject)
1471{
1472 *ppvObject = NULL;
1473
1474 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
1475 {
1476 *ppvObject = iface;
1477 }
1478 else
1479 {
1480 return E_NOINTERFACE;
1481 }
1482
1483 return S_OK;
1484}
1485
1486static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
1487{
1488 return 2;
1489}
1490
1491static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
1492{
1493 return 1;
1494}
1495
1496static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
1497{
1498 *length = 3;
1499 return S_OK;
1500}
1501
1503 ISAXAttributes* iface,
1504 int nIndex,
1505 const WCHAR **pUrl,
1506 int *pUriSize)
1507{
1508 ok(0, "unexpected call\n");
1509 return E_NOTIMPL;
1510}
1511
1513 ISAXAttributes* iface,
1514 int nIndex,
1515 const WCHAR **pLocalName,
1516 int *pLocalNameLength)
1517{
1518 ok(0, "unexpected call\n");
1519 return E_NOTIMPL;
1520}
1521
1523 ISAXAttributes* iface,
1524 int index,
1525 const WCHAR **QName,
1526 int *QNameLength)
1527{
1528 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0},
1529 {'a','t','t','r','2','j','u','n','k',0},
1530 {'a','t','t','r','3',0}};
1531 static const int attrqnamelen[] = {7, 5, 5};
1532
1533 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1534
1535 if (index >= 0 && index <= 2) {
1536 *QName = attrqnamesW[index];
1537 *QNameLength = attrqnamelen[index];
1538 } else {
1539 *QName = NULL;
1540 *QNameLength = 0;
1541 }
1542
1543 return S_OK;
1544}
1545
1547 ISAXAttributes* iface,
1548 int nIndex,
1549 const WCHAR **pUri,
1550 int * pUriLength,
1551 const WCHAR ** pLocalName,
1552 int * pLocalNameSize,
1553 const WCHAR ** pQName,
1554 int * pQNameLength)
1555{
1556 ok(0, "unexpected call\n");
1557 return E_NOTIMPL;
1558}
1559
1561 ISAXAttributes* iface,
1562 const WCHAR * pUri,
1563 int cUriLength,
1564 const WCHAR * pLocalName,
1565 int cocalNameLength,
1566 int * index)
1567{
1568 ok(0, "unexpected call\n");
1569 return E_NOTIMPL;
1570}
1571
1573 ISAXAttributes* iface,
1574 const WCHAR * pQName,
1575 int nQNameLength,
1576 int * index)
1577{
1578 ok(0, "unexpected call\n");
1579 return E_NOTIMPL;
1580}
1581
1583 ISAXAttributes* iface,
1584 int nIndex,
1585 const WCHAR ** pType,
1586 int * pTypeLength)
1587{
1588 ok(0, "unexpected call\n");
1589 return E_NOTIMPL;
1590}
1591
1593 ISAXAttributes* iface,
1594 const WCHAR * pUri,
1595 int nUri,
1596 const WCHAR * pLocalName,
1597 int nLocalName,
1598 const WCHAR ** pType,
1599 int * nType)
1600{
1601 ok(0, "unexpected call\n");
1602 return E_NOTIMPL;
1603}
1604
1606 ISAXAttributes* iface,
1607 const WCHAR * pQName,
1608 int nQName,
1609 const WCHAR ** pType,
1610 int * nType)
1611{
1612 ok(0, "unexpected call\n");
1613 return E_NOTIMPL;
1614}
1615
1616static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
1617 const WCHAR **value, int *nValue)
1618{
1619 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0},
1620 {'a','2','j','u','n','k',0},
1621 {'<','&','"','>','\'',0}};
1622 static const int attrvalueslen[] = {2, 2, 5};
1623
1624 ok(index >= 0 && index <= 2, "invalid index received %d\n", index);
1625
1626 if (index >= 0 && index <= 2) {
1627 *value = attrvaluesW[index];
1628 *nValue = attrvalueslen[index];
1629 } else {
1630 *value = NULL;
1631 *nValue = 0;
1632 }
1633
1634 return S_OK;
1635}
1636
1638 ISAXAttributes* iface,
1639 const WCHAR * pUri,
1640 int nUri,
1641 const WCHAR * pLocalName,
1642 int nLocalName,
1643 const WCHAR ** pValue,
1644 int * nValue)
1645{
1646 ok(0, "unexpected call\n");
1647 return E_NOTIMPL;
1648}
1649
1651 ISAXAttributes* iface,
1652 const WCHAR * pQName,
1653 int nQName,
1654 const WCHAR ** pValue,
1655 int * nValue)
1656{
1657 ok(0, "unexpected call\n");
1658 return E_NOTIMPL;
1659}
1660
1661static const ISAXAttributesVtbl SAXAttributesVtbl =
1662{
1679};
1680
1681static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
1682
1684{
1685 ISAXLexicalHandler ISAXLexicalHandler_iface;
1687
1688 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1689};
1690
1691static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
1692{
1694}
1695
1696static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
1697{
1699
1700 *out = NULL;
1701
1703 {
1704 *out = iface;
1705 ok(0, "got unexpected IID_IUnknown query\n");
1706 }
1707 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
1708 {
1709 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1710 *out = iface;
1711 }
1712
1713 if (*out)
1714 ISAXLexicalHandler_AddRef(iface);
1715 else
1716 return E_NOINTERFACE;
1717
1718 return S_OK;
1719}
1720
1721static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
1722{
1724 return InterlockedIncrement(&handler->ref);
1725}
1726
1727static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
1728{
1730 return InterlockedDecrement(&handler->ref);
1731}
1732
1733static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
1734 const WCHAR * pName, int nName, const WCHAR * pPublicId,
1735 int nPublicId, const WCHAR * pSystemId, int nSystemId)
1736{
1737 ok(0, "call not expected\n");
1738 return E_NOTIMPL;
1739}
1740
1741static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
1742{
1743 ok(0, "call not expected\n");
1744 return E_NOTIMPL;
1745}
1746
1747static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
1748 const WCHAR * pName, int nName)
1749{
1750 ok(0, "call not expected\n");
1751 return E_NOTIMPL;
1752}
1753
1754static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
1755 const WCHAR * pName, int nName)
1756{
1757 ok(0, "call not expected\n");
1758 return E_NOTIMPL;
1759}
1760
1761static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
1762{
1763 struct call_entry call;
1764
1765 init_call_entry(locator, &call);
1766 call.id = LH_STARTCDATA;
1768
1769 return get_expected_ret();
1770}
1771
1772static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
1773{
1774 struct call_entry call;
1775
1776 init_call_entry(locator, &call);
1777 call.id = LH_ENDCDATA;
1779
1780 return get_expected_ret();
1781}
1782
1783static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
1784 const WCHAR * pChars, int nChars)
1785{
1786 ok(0, "call not expected\n");
1787 return E_NOTIMPL;
1788}
1789
1790static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
1791{
1802};
1803
1805{
1806 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
1807 handler->ref = 1;
1808 handler->qi_hr = hr;
1809}
1810
1812{
1813 ISAXDeclHandler ISAXDeclHandler_iface;
1815
1816 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
1817};
1818
1819static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
1820{
1822}
1823
1824static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
1825{
1827
1828 *out = NULL;
1829
1831 {
1832 *out = iface;
1833 ok(0, "got unexpected IID_IUnknown query\n");
1834 }
1835 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
1836 {
1837 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
1838 *out = iface;
1839 }
1840
1841 if (*out)
1842 ISAXDeclHandler_AddRef(iface);
1843 else
1844 return E_NOINTERFACE;
1845
1846 return S_OK;
1847}
1848
1849static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1850{
1852 return InterlockedIncrement(&handler->ref);
1853}
1854
1855static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1856{
1858 return InterlockedDecrement(&handler->ref);
1859}
1860
1861static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1862 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1863{
1864 ok(0, "call not expected\n");
1865 return E_NOTIMPL;
1866}
1867
1868static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1869 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1870 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1871 int nValueDefault, const WCHAR * pValue, int nValue)
1872{
1873 ok(0, "call not expected\n");
1874 return E_NOTIMPL;
1875}
1876
1877static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1878 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1879{
1880 ok(0, "call not expected\n");
1881 return E_NOTIMPL;
1882}
1883
1884static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1885 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1886 const WCHAR * pSystemId, int nSystemId)
1887{
1888 ok(0, "call not expected\n");
1889 return E_NOTIMPL;
1890}
1891
1892static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1893{
1901};
1902
1904{
1905 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
1906 handler->ref = 1;
1907 handler->qi_hr = hr;
1908}
1909
1912 const BYTE *data;
1917
1920 const char *encoding;
1923
1926
1928{
1929 *ppvObject = NULL;
1930
1931 ok(!IsEqualGUID(riid, &IID_IPersistStream), "Did not expect QI for IPersistStream\n");
1932
1933 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1934 *ppvObject = iface;
1935 else
1936 return E_NOINTERFACE;
1937
1938 return S_OK;
1939}
1940
1942{
1943 return 2;
1944}
1945
1947{
1948 return 1;
1949}
1950
1951static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1952{
1953 ok(0, "unexpected call\n");
1954 return E_NOTIMPL;
1955}
1956
1957static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1958{
1959 ok(0, "unexpected call\n");
1960 return E_NOTIMPL;
1961}
1962
1963static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1964 ULARGE_INTEGER *plibNewPosition)
1965{
1966 ok(0, "unexpected call\n");
1967 return E_NOTIMPL;
1968}
1969
1971{
1972 ok(0, "unexpected call\n");
1973 return E_NOTIMPL;
1974}
1975
1977 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1978{
1979 ok(0, "unexpected call\n");
1980 return E_NOTIMPL;
1981}
1982
1983static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1984{
1985 ok(0, "unexpected call\n");
1986 return E_NOTIMPL;
1987}
1988
1990{
1991 ok(0, "unexpected call\n");
1992 return E_NOTIMPL;
1993}
1994
1996 ULARGE_INTEGER cb, DWORD dwLockType)
1997{
1998 ok(0, "unexpected call\n");
1999 return E_NOTIMPL;
2000}
2001
2003 ULARGE_INTEGER cb, DWORD dwLockType)
2004{
2005 ok(0, "unexpected call\n");
2006 return E_NOTIMPL;
2007}
2008
2009static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
2010{
2011 return E_NOTIMPL;
2012}
2013
2015{
2016 ok(0, "unexpected call\n");
2017 return E_NOTIMPL;
2018}
2019
2020static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
2021{
2022 BOOL fail = FALSE;
2023
2024 ok(pv != NULL, "pv == NULL\n");
2025
2027 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
2028 return E_FAIL;
2029 }
2030
2032
2033 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
2035
2036 if(!pcbWritten)
2037 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
2038 else
2039 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
2040
2042
2043 if(pcbWritten)
2044 *pcbWritten = cb;
2045
2046 return fail ? E_FAIL : S_OK;
2047}
2048
2049static const IStreamVtbl mxstreamVtbl = {
2064};
2065
2067
2068static int read_cnt;
2069
2070static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
2071{
2072 static const char *ret_str;
2073
2074 if(!read_cnt)
2075 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
2076 else if(read_cnt < 5)
2077 ret_str = "<elem attr=\"val\">text</elem>";
2078 else if(read_cnt == 5)
2079 ret_str = "</rootelem>\n";
2080 else
2081 ret_str = "";
2082
2083 read_cnt++;
2084 strcpy(pv, ret_str);
2085 *pcbRead = strlen(ret_str);
2086 return S_OK;
2087}
2088
2089static const IStreamVtbl instreamVtbl = {
2104};
2105
2107
2109{
2110 { &CLSID_SAXXMLReader, "SAXReader" },
2111 { &CLSID_SAXXMLReader30, "SAXReader30" },
2112 { &CLSID_SAXXMLReader40, "SAXReader40" },
2113 { &CLSID_SAXXMLReader60, "SAXReader60" },
2114 { NULL }
2115};
2116
2119
2120static IStream *create_test_stream(const char *data, int len)
2121{
2124 IStream *stream;
2125 ULONG written;
2126
2127 if (len == -1) len = strlen(data);
2129 size.QuadPart = len;
2130 IStream_SetSize(stream, size);
2131 IStream_Write(stream, data, len, &written);
2132 pos.QuadPart = 0;
2133 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2134
2135 return stream;
2136}
2137
2138static void test_saxreader(void)
2139{
2141 HRESULT hr;
2142 ISAXXMLReader *reader = NULL;
2143 VARIANT var;
2144 ISAXContentHandler *content;
2145 ISAXErrorHandler *lpErrorHandler;
2146 SAFEARRAY *sa;
2147 SAFEARRAYBOUND SADim[1];
2148 char *ptr = NULL;
2149 IStream *stream;
2150 ULONG written;
2151 HANDLE file;
2152 static const CHAR testXmlA[] = "test.xml";
2153 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2154 IXMLDOMDocument *doc;
2155 char seqname[50];
2157
2158 while (table->clsid)
2159 {
2160 struct call_entry *test_seq;
2161 ISAXEntityResolver *resolver;
2162 BSTR str;
2163
2165 {
2166 table++;
2167 continue;
2168 }
2169
2170 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2171 EXPECT_HR(hr, S_OK);
2172 g_reader = reader;
2173
2174 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2175 msxml_version = 4;
2176 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2177 msxml_version = 6;
2178 else
2179 msxml_version = 0;
2180
2181 /* crashes on old versions */
2182 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) &&
2183 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2184 {
2185 hr = ISAXXMLReader_getContentHandler(reader, NULL);
2187
2188 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
2190 }
2191
2192 hr = ISAXXMLReader_getContentHandler(reader, &content);
2193 EXPECT_HR(hr, S_OK);
2194 ok(content == NULL, "Expected %p, got %p\n", NULL, content);
2195
2196 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
2197 EXPECT_HR(hr, S_OK);
2198 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
2199
2200 hr = ISAXXMLReader_putContentHandler(reader, NULL);
2201 EXPECT_HR(hr, S_OK);
2202
2203 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
2204 EXPECT_HR(hr, S_OK);
2205
2206 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
2207 EXPECT_HR(hr, S_OK);
2208
2209 hr = ISAXXMLReader_getContentHandler(reader, &content);
2210 EXPECT_HR(hr, S_OK);
2211 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
2212
2213 V_VT(&var) = VT_BSTR;
2215
2216 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2217 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2219 else
2220 test_seq = content_handler_test1;
2221 set_expected_seq(test_seq);
2222 hr = ISAXXMLReader_parse(reader, var);
2223 EXPECT_HR(hr, S_OK);
2224 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE);
2225
2226 VariantClear(&var);
2227
2228 SADim[0].lLbound = 0;
2229 SADim[0].cElements = sizeof(testXML)-1;
2230 sa = SafeArrayCreate(VT_UI1, 1, SADim);
2231 SafeArrayAccessData(sa, (void**)&ptr);
2232 memcpy(ptr, testXML, sizeof(testXML)-1);
2234 V_VT(&var) = VT_ARRAY|VT_UI1;
2235 V_ARRAY(&var) = sa;
2236
2237 set_expected_seq(test_seq);
2238 hr = ISAXXMLReader_parse(reader, var);
2239 EXPECT_HR(hr, S_OK);
2240 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE);
2241
2243
2244 V_VT(&var) = VT_UNKNOWN;
2245 V_UNKNOWN(&var) = NULL;
2246 hr = ISAXXMLReader_parse(reader, var);
2247 ok(hr == E_INVALIDARG, "got %#x\n", hr);
2248
2249 V_VT(&var) = VT_DISPATCH;
2250 V_DISPATCH(&var) = NULL;
2251 hr = ISAXXMLReader_parse(reader, var);
2252 ok(hr == E_INVALIDARG, "got %#x\n", hr);
2253
2255 V_VT(&var) = VT_UNKNOWN;
2257
2258 set_expected_seq(test_seq);
2259 hr = ISAXXMLReader_parse(reader, var);
2260 EXPECT_HR(hr, S_OK);
2261 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE);
2262
2263 IStream_Release(stream);
2264
2266 V_VT(&var) = VT_UNKNOWN;
2268
2269 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2271 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2273 else
2275
2276 set_expected_seq(test_seq);
2277 hr = ISAXXMLReader_parse(reader, var);
2278 EXPECT_HR(hr, S_OK);
2279
2280 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2281 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2282 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2283 else
2284 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2285
2286 IStream_Release(stream);
2287
2288 V_VT(&var) = VT_UNKNOWN;
2290
2291 test_seq = read_test_seq;
2292 read_cnt = 0;
2293 set_expected_seq(test_seq);
2294 hr = ISAXXMLReader_parse(reader, var);
2295 EXPECT_HR(hr, S_OK);
2296 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
2297 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
2298
2299 V_VT(&var) = VT_BSTR;
2301
2302 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2303 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2305 else
2306 test_seq = content_handler_test2;
2307
2308 set_expected_seq(test_seq);
2309 hr = ISAXXMLReader_parse(reader, var);
2310 EXPECT_HR(hr, S_OK);
2311 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE);
2312
2313 VariantClear(&var);
2314
2315 /* from file url */
2317 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2318 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
2320
2321 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2322 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2324 else
2325 test_seq = content_handler_test1;
2326 set_expected_seq(test_seq);
2327 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2328 EXPECT_HR(hr, S_OK);
2329 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
2330
2331 /* error handler */
2332 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2333 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2335 else
2336 test_seq = content_handler_testerror;
2337 set_expected_seq(test_seq);
2338 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2340 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
2341
2342 /* callback ret values */
2343 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2344 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2345 {
2347 set_expected_seq(test_seq);
2348 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2349 EXPECT_HR(hr, S_OK);
2350 }
2351 else
2352 {
2354 set_expected_seq(test_seq);
2355 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2357 }
2358 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
2359
2360 DeleteFileA(testXmlA);
2361
2362 /* parse from IXMLDOMDocument */
2363 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
2364 &IID_IXMLDOMDocument, (void**)&doc);
2365 EXPECT_HR(hr, S_OK);
2366
2368 hr = IXMLDOMDocument_loadXML(doc, str, &v);
2369 EXPECT_HR(hr, S_OK);
2371
2372 V_VT(&var) = VT_UNKNOWN;
2373 V_UNKNOWN(&var) = (IUnknown*)doc;
2374
2375 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2376 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2378 else
2379 test_seq = content_handler_test2;
2380
2381 set_expected_seq(test_seq);
2382 hr = ISAXXMLReader_parse(reader, var);
2383 EXPECT_HR(hr, S_OK);
2384 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE);
2385 IXMLDOMDocument_Release(doc);
2386
2387 /* xml:space test */
2388 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2389 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2390 {
2391 test_seq = xmlspaceattr_test_alternate;
2392 }
2393 else
2394 test_seq = xmlspaceattr_test;
2395
2396 set_expected_seq(test_seq);
2397 V_VT(&var) = VT_BSTR;
2399 hr = ISAXXMLReader_parse(reader, var);
2400 EXPECT_HR(hr, S_OK);
2401
2402 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2403 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2404 {
2405 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE);
2406 }
2407 else
2408 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE);
2409
2410 /* switch off 'namespaces' feature */
2411 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE);
2412 EXPECT_HR(hr, S_OK);
2413
2415 V_VT(&var) = VT_UNKNOWN;
2417
2418 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2419 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2420 {
2422 }
2423 else
2425
2426 set_expected_seq(test_seq);
2427 hr = ISAXXMLReader_parse(reader, var);
2428 EXPECT_HR(hr, S_OK);
2429 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE);
2430 IStream_Release(stream);
2431 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE);
2432 EXPECT_HR(hr, S_OK);
2433
2434 /* switch off 'namespace-prefixes' feature */
2435 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE);
2436 EXPECT_HR(hr, S_OK);
2437
2439 V_VT(&var) = VT_UNKNOWN;
2441
2442 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2443 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2444 {
2446 }
2447 else
2449
2450 set_expected_seq(test_seq);
2451 hr = ISAXXMLReader_parse(reader, var);
2452 EXPECT_HR(hr, S_OK);
2453 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE);
2454 IStream_Release(stream);
2455
2456 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE);
2457 EXPECT_HR(hr, S_OK);
2458
2459 /* attribute normalization */
2461 V_VT(&var) = VT_UNKNOWN;
2463
2464 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) ||
2465 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60))
2466 {
2467 test_seq = attribute_norm_alt;
2468 }
2469 else
2470 test_seq = attribute_norm;
2471
2472 set_expected_seq(test_seq);
2473 hr = ISAXXMLReader_parse(reader, var);
2474 EXPECT_HR(hr, S_OK);
2475 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE);
2476 IStream_Release(stream);
2477
2478 resolver = (void*)0xdeadbeef;
2479 hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
2480 ok(hr == S_OK, "got 0x%08x\n", hr);
2481 ok(resolver == NULL, "got %p\n", resolver);
2482
2483 hr = ISAXXMLReader_putEntityResolver(reader, NULL);
2484 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr);
2485
2486 /* CDATA sections */
2488
2489 V_VT(&var) = VT_UNKNOWN;
2490 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface;
2491 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var);
2492 ok(hr == S_OK, "got 0x%08x\n", hr);
2493
2495 V_VT(&var) = VT_UNKNOWN;
2497
2498 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2499 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2500 test_seq = cdata_test_alt;
2501 else
2502 test_seq = cdata_test;
2503
2504 set_expected_seq(test_seq);
2505 hr = ISAXXMLReader_parse(reader, var);
2506 ok(hr == S_OK, "got 0x%08x\n", hr);
2507 sprintf(seqname, "%s: cdata test", table->name);
2508 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2509
2510 IStream_Release(stream);
2511
2512 /* 2. CDATA sections */
2514 V_VT(&var) = VT_UNKNOWN;
2516
2517 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2518 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2519 test_seq = cdata_test2_alt;
2520 else
2521 test_seq = cdata_test2;
2522
2523 set_expected_seq(test_seq);
2524 hr = ISAXXMLReader_parse(reader, var);
2525 ok(hr == S_OK, "got 0x%08x\n", hr);
2526 sprintf(seqname, "%s: cdata test 2", table->name);
2527 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2528
2529 IStream_Release(stream);
2530
2531 /* 3. CDATA sections */
2533 V_VT(&var) = VT_UNKNOWN;
2535
2536 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) ||
2537 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40))
2538 test_seq = cdata_test3_alt;
2539 else
2540 test_seq = cdata_test3;
2541
2542 set_expected_seq(test_seq);
2543 hr = ISAXXMLReader_parse(reader, var);
2544 ok(hr == S_OK, "got 0x%08x\n", hr);
2545 sprintf(seqname, "%s: cdata test 3", table->name);
2546 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE);
2547
2548 IStream_Release(stream);
2549
2550 ISAXXMLReader_Release(reader);
2551 table++;
2552 }
2553
2554 free_bstrs();
2555}
2556
2558{
2559 const char *prop_name;
2561};
2562
2564 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface },
2565 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface },
2566 { 0 }
2567};
2568
2570{
2572 ISAXXMLReader *reader;
2573 HRESULT hr;
2574 VARIANT v;
2575 BSTR str;
2576
2577 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2578 &IID_ISAXXMLReader, (void**)&reader);
2579 EXPECT_HR(hr, S_OK);
2580
2581 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
2583
2584 while (ptr->prop_name)
2585 {
2586 VARIANT varref;
2587 LONG ref;
2588
2591
2592 V_VT(&v) = VT_EMPTY;
2593 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2594 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2595 EXPECT_HR(hr, S_OK);
2596 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2597 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2598
2599 /* VT_UNKNOWN */
2600 V_VT(&v) = VT_UNKNOWN;
2601 V_UNKNOWN(&v) = ptr->iface;
2602 ref = get_refcount(ptr->iface);
2603 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2604 EXPECT_HR(hr, S_OK);
2605 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2606
2607 /* VT_DISPATCH */
2608 V_VT(&v) = VT_DISPATCH;
2609 V_UNKNOWN(&v) = ptr->iface;
2610 ref = get_refcount(ptr->iface);
2611 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2612 EXPECT_HR(hr, S_OK);
2613 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2614
2615 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
2616 V_VT(&varref) = VT_UNKNOWN;
2617 V_UNKNOWN(&varref) = ptr->iface;
2618
2620 V_VARIANTREF(&v) = &varref;
2621 ref = get_refcount(ptr->iface);
2622 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2623 EXPECT_HR(hr, S_OK);
2624 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2625
2626 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
2627 V_VT(&varref) = VT_DISPATCH;
2628 V_UNKNOWN(&varref) = ptr->iface;
2629
2631 V_VARIANTREF(&v) = &varref;
2632 ref = get_refcount(ptr->iface);
2633 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2634 EXPECT_HR(hr, S_OK);
2635 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref);
2636
2637 V_VT(&v) = VT_EMPTY;
2638 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2639
2640 ref = get_refcount(ptr->iface);
2641 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2642 EXPECT_HR(hr, S_OK);
2643 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2644 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2645 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
2646 VariantClear(&v);
2647
2648 V_VT(&v) = VT_EMPTY;
2649 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2650 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2651 EXPECT_HR(hr, S_OK);
2652
2653 V_VT(&v) = VT_EMPTY;
2654 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2655 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2656 EXPECT_HR(hr, S_OK);
2657 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2658 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2659
2660 V_VT(&v) = VT_UNKNOWN;
2661 V_UNKNOWN(&v) = ptr->iface;
2662 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2663 EXPECT_HR(hr, S_OK);
2664
2665 /* only VT_EMPTY seems to be valid to reset property */
2666 V_VT(&v) = VT_I4;
2667 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2668 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2670
2671 V_VT(&v) = VT_EMPTY;
2672 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2673 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2674 EXPECT_HR(hr, S_OK);
2675 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2676 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
2677 VariantClear(&v);
2678
2679 V_VT(&v) = VT_UNKNOWN;
2680 V_UNKNOWN(&v) = NULL;
2681 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2682 EXPECT_HR(hr, S_OK);
2683
2684 V_VT(&v) = VT_EMPTY;
2685 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2686 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2687 EXPECT_HR(hr, S_OK);
2688 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2689 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
2690
2691 /* block QueryInterface on handler riid */
2692 V_VT(&v) = VT_UNKNOWN;
2693 V_UNKNOWN(&v) = ptr->iface;
2694 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2695 EXPECT_HR(hr, S_OK);
2696
2699
2700 V_VT(&v) = VT_UNKNOWN;
2701 V_UNKNOWN(&v) = ptr->iface;
2702 EXPECT_REF(ptr->iface, 1);
2703 ref = get_refcount(ptr->iface);
2704 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
2706 EXPECT_REF(ptr->iface, 1);
2707
2708 V_VT(&v) = VT_EMPTY;
2709 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
2710 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
2711 EXPECT_HR(hr, S_OK);
2712 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
2713 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
2714
2715 ptr++;
2716 free_bstrs();
2717 }
2718
2719 ISAXXMLReader_Release(reader);
2720
2721 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data))
2722 return;
2723
2724 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
2725 &IID_ISAXXMLReader, (void**)&reader);
2726 EXPECT_HR(hr, S_OK);
2727
2728 /* xmldecl-version property */
2729 V_VT(&v) = VT_EMPTY;
2730 V_BSTR(&v) = (void*)0xdeadbeef;
2731 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2732 EXPECT_HR(hr, S_OK);
2733 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2734 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2735
2736 /* stream without declaration */
2737 V_VT(&v) = VT_BSTR;
2738 V_BSTR(&v) = _bstr_("<element></element>");
2739 hr = ISAXXMLReader_parse(reader, v);
2740 EXPECT_HR(hr, S_OK);
2741
2742 V_VT(&v) = VT_EMPTY;
2743 V_BSTR(&v) = (void*)0xdeadbeef;
2744 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2745 EXPECT_HR(hr, S_OK);
2746 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2747 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2748
2749 /* stream with declaration */
2750 V_VT(&v) = VT_BSTR;
2751 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
2752 hr = ISAXXMLReader_parse(reader, v);
2753 EXPECT_HR(hr, S_OK);
2754
2755 /* VT_BSTR|VT_BYREF input type */
2756 str = _bstr_("<?xml version=\"1.0\"?><element></element>");
2757 V_VT(&v) = VT_BSTR|VT_BYREF;
2758 V_BSTRREF(&v) = &str;
2759 hr = ISAXXMLReader_parse(reader, v);
2760 EXPECT_HR(hr, S_OK);
2761
2762 V_VT(&v) = VT_EMPTY;
2763 V_BSTR(&v) = (void*)0xdeadbeef;
2764 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v);
2765 EXPECT_HR(hr, S_OK);
2766 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
2767 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
2768 VariantClear(&v);
2769
2770 ISAXXMLReader_Release(reader);
2771 free_bstrs();
2772}
2773
2775 const GUID *guid;
2776 const char *clsid;
2778 VARIANT_BOOL value2; /* feature value after feature set to 0xc */
2779};
2780
2782 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE },
2783 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE },
2784 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE },
2785 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE },
2786 { 0 }
2787};
2788
2789static const char *feature_names[] = {
2790 "http://xml.org/sax/features/namespaces",
2791 "http://xml.org/sax/features/namespace-prefixes",
2792 0
2793};
2794
2796{
2798 ISAXXMLReader *reader;
2799
2800 while (entry->guid)
2801 {
2803 const char **name;
2804 HRESULT hr;
2805
2806 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2807 if (hr != S_OK)
2808 {
2809 win_skip("can't create %s instance\n", entry->clsid);
2810 entry++;
2811 continue;
2812 }
2813
2814 if (IsEqualGUID(entry->guid, &CLSID_SAXXMLReader40) ||
2815 IsEqualGUID(entry->guid, &CLSID_SAXXMLReader60))
2816 {
2817 value = VARIANT_TRUE;
2818 hr = ISAXXMLReader_getFeature(reader, _bstr_("exhaustive-errors"), &value);
2819 ok(hr == S_OK, "Failed to get feature value, hr %#x.\n", hr);
2820 ok(value == VARIANT_FALSE, "Unexpected default feature value.\n");
2821 hr = ISAXXMLReader_putFeature(reader, _bstr_("exhaustive-errors"), VARIANT_FALSE);
2822 ok(hr == S_OK, "Failed to put feature value, hr %#x.\n", hr);
2823
2824 value = VARIANT_TRUE;
2825 hr = ISAXXMLReader_getFeature(reader, _bstr_("schema-validation"), &value);
2826 ok(hr == S_OK, "Failed to get feature value, hr %#x.\n", hr);
2827 ok(value == VARIANT_FALSE, "Unexpected default feature value.\n");
2828 hr = ISAXXMLReader_putFeature(reader, _bstr_("exhaustive-errors"), VARIANT_FALSE);
2829 ok(hr == S_OK, "Failed to put feature value, hr %#x.\n", hr);
2830 }
2831 else
2832 {
2833 value = 123;
2834 hr = ISAXXMLReader_getFeature(reader, _bstr_("exhaustive-errors"), &value);
2835 ok(hr == E_INVALIDARG, "Failed to get feature value, hr %#x.\n", hr);
2836 ok(value == 123, "Unexpected value %d.\n", value);
2837
2838 value = 123;
2839 hr = ISAXXMLReader_getFeature(reader, _bstr_("schema-validation"), &value);
2840 ok(hr == E_INVALIDARG, "Failed to get feature value, hr %#x.\n", hr);
2841 ok(value == 123, "Unexpected value %d.\n", value);
2842 }
2843
2845 while (*name)
2846 {
2847 value = 0xc;
2848 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2849 EXPECT_HR(hr, S_OK);
2850 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
2851
2852 value = 0xc;
2853 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value);
2854 EXPECT_HR(hr, S_OK);
2855
2856 value = 0xd;
2857 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2858 EXPECT_HR(hr, S_OK);
2859 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2);
2860
2861 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE);
2862 EXPECT_HR(hr, S_OK);
2863 value = 0xd;
2864 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2865 EXPECT_HR(hr, S_OK);
2866 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value);
2867
2868 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE);
2869 EXPECT_HR(hr, S_OK);
2870 value = 0xd;
2871 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value);
2872 EXPECT_HR(hr, S_OK);
2873 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value);
2874
2875 name++;
2876 }
2877
2878 ISAXXMLReader_Release(reader);
2879
2880 entry++;
2881 }
2882}
2883
2884/* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
2885static const CHAR UTF8BOMTest[] =
2886"\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
2887"<a></a>\n";
2888
2890 const GUID *guid;
2891 const char *clsid;
2892 const char *data;
2895};
2896
2897static const struct enc_test_entry_t encoding_test_data[] = {
2898 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE },
2899 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE },
2900 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE },
2901 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE },
2902 { 0 }
2903};
2904
2906{
2908 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
2909 static const CHAR testXmlA[] = "test.xml";
2910
2911 while (entry->guid)
2912 {
2913 ISAXXMLReader *reader;
2914 VARIANT input;
2915 DWORD written;
2916 HANDLE file;
2917 HRESULT hr;
2918
2919 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
2920 if (hr != S_OK)
2921 {
2922 win_skip("can't create %s instance\n", entry->clsid);
2923 entry++;
2924 continue;
2925 }
2926
2928 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
2929 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
2931
2932 hr = ISAXXMLReader_parseURL(reader, testXmlW);
2933 todo_wine_if(entry->todo)
2934 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
2935
2936 DeleteFileA(testXmlA);
2937
2938 /* try BSTR input with no BOM or '<?xml' instruction */
2939 V_VT(&input) = VT_BSTR;
2940 V_BSTR(&input) = _bstr_("<element></element>");
2941 hr = ISAXXMLReader_parse(reader, input);
2942 EXPECT_HR(hr, S_OK);
2943
2944 ISAXXMLReader_Release(reader);
2945
2946 free_bstrs();
2947 entry++;
2948 }
2949}
2950
2951static void test_mxwriter_handlers(void)
2952{
2953 IMXWriter *writer;
2954 HRESULT hr;
2955 int i;
2956
2957 static REFIID riids[] =
2958 {
2959 &IID_ISAXContentHandler,
2960 &IID_ISAXLexicalHandler,
2961 &IID_ISAXDeclHandler,
2962 &IID_ISAXDTDHandler,
2963 &IID_ISAXErrorHandler,
2964 &IID_IVBSAXDeclHandler,
2965 &IID_IVBSAXLexicalHandler,
2966 &IID_IVBSAXContentHandler,
2967 &IID_IVBSAXDTDHandler,
2968 &IID_IVBSAXErrorHandler
2969 };
2970
2971 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2972 &IID_IMXWriter, (void**)&writer);
2973 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2974
2975 EXPECT_REF(writer, 1);
2976
2977 for (i = 0; i < ARRAY_SIZE(riids); i++)
2978 {
2980 IMXWriter *writer2;
2981
2982 /* handler from IMXWriter */
2983 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
2984 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2985 EXPECT_REF(writer, 2);
2986 EXPECT_REF(handler, 2);
2987
2988 /* IMXWriter from a handler */
2989 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
2990 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr);
2991 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
2992 EXPECT_REF(writer, 3);
2993 IMXWriter_Release(writer2);
2994 IUnknown_Release(handler);
2995 }
2996
2997 IMXWriter_Release(writer);
2998}
2999
3001{
3002 { &CLSID_MXXMLWriter, "MXXMLWriter" },
3003 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
3004 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
3005 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
3006 { NULL }
3007};
3008
3010{
3011 { &CLSID_SAXAttributes, "SAXAttributes" },
3012 { &CLSID_SAXAttributes30, "SAXAttributes30" },
3013 { &CLSID_SAXAttributes40, "SAXAttributes40" },
3014 { &CLSID_SAXAttributes60, "SAXAttributes60" },
3015 { NULL }
3016};
3017
3019{
3020 const GUID *clsid;
3026 const char *encoding;
3027};
3028
3030{
3031 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
3032 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
3033 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
3034 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
3035 { NULL }
3036};
3037
3039{
3040 int i = 0;
3041
3042 while (table->clsid)
3043 {
3044 IMXWriter *writer;
3046 BSTR encoding;
3047 HRESULT hr;
3048
3050 {
3051 table++;
3052 i++;
3053 continue;
3054 }
3055
3056 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
3057 &IID_IMXWriter, (void**)&writer);
3058 EXPECT_HR(hr, S_OK);
3059
3060 b = !table->bom;
3061 hr = IMXWriter_get_byteOrderMark(writer, &b);
3062 EXPECT_HR(hr, S_OK);
3063 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
3064
3065 b = !table->disable_escape;
3066 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
3067 EXPECT_HR(hr, S_OK);
3068 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
3069 table->disable_escape);
3070
3071 b = !table->indent;
3072 hr = IMXWriter_get_indent(writer, &b);
3073 EXPECT_HR(hr, S_OK);
3074 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
3075
3076 b = !table->omitdecl;
3077 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
3078 EXPECT_HR(hr, S_OK);
3079 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
3080
3081 b = !table->standalone;
3082 hr = IMXWriter_get_standalone(writer, &b);
3083 EXPECT_HR(hr, S_OK);
3084 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
3085
3086 hr = IMXWriter_get_encoding(writer, &encoding);
3087 EXPECT_HR(hr, S_OK);
3088 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
3089 i, wine_dbgstr_w(encoding), table->encoding);
3091
3092 IMXWriter_Release(writer);
3093
3094 table++;
3095 i++;
3096 }
3097}
3098
3100{
3101 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
3102 static const WCHAR testW[] = {'t','e','s','t',0};
3103 ISAXContentHandler *content;
3104 IMXWriter *writer;
3106 HRESULT hr;
3107 BSTR str, str2;
3108 VARIANT dest;
3109
3111
3112 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3113 &IID_IMXWriter, (void**)&writer);
3114 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3115
3116 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
3117 ok(hr == E_POINTER, "got %08x\n", hr);
3118
3119 hr = IMXWriter_get_byteOrderMark(writer, NULL);
3120 ok(hr == E_POINTER, "got %08x\n", hr);
3121
3122 hr = IMXWriter_get_indent(writer, NULL);
3123 ok(hr == E_POINTER, "got %08x\n", hr);
3124
3125 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
3126 ok(hr == E_POINTER, "got %08x\n", hr);
3127
3128 hr = IMXWriter_get_standalone(writer, NULL);
3129 ok(hr == E_POINTER, "got %08x\n", hr);
3130
3131 /* set and check */
3132 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
3133 ok(hr == S_OK, "got %08x\n", hr);
3134
3135 b = VARIANT_FALSE;
3136 hr = IMXWriter_get_standalone(writer, &b);
3137 ok(hr == S_OK, "got %08x\n", hr);
3138 ok(b == VARIANT_TRUE, "got %d\n", b);
3139
3140 hr = IMXWriter_get_encoding(writer, NULL);
3142
3143 /* UTF-16 is a default setting apparently */
3144 str = (void*)0xdeadbeef;
3145 hr = IMXWriter_get_encoding(writer, &str);
3146 EXPECT_HR(hr, S_OK);
3147 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
3148
3149 str2 = (void*)0xdeadbeef;
3150 hr = IMXWriter_get_encoding(writer, &str2);
3151 ok(hr == S_OK, "got %08x\n", hr);
3152 ok(str != str2, "expected newly allocated, got same %p\n", str);
3153
3154 SysFreeString(str2);
3156
3157 /* put empty string */
3159 hr = IMXWriter_put_encoding(writer, str);
3160 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3162
3163 str = (void*)0xdeadbeef;
3164 hr = IMXWriter_get_encoding(writer, &str);
3165 EXPECT_HR(hr, S_OK);
3166 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str));
3168
3169 /* invalid encoding name */
3171 hr = IMXWriter_put_encoding(writer, str);
3172 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3174
3175 /* test case sensivity */
3176 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
3177 EXPECT_HR(hr, S_OK);
3178 str = (void*)0xdeadbeef;
3179 hr = IMXWriter_get_encoding(writer, &str);
3180 EXPECT_HR(hr, S_OK);
3181 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str));
3183
3184 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
3185 EXPECT_HR(hr, S_OK);
3186 str = (void*)0xdeadbeef;
3187 hr = IMXWriter_get_encoding(writer, &str);
3188 EXPECT_HR(hr, S_OK);
3189 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str));
3191
3192 /* how it affects document creation */
3193 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
3194 EXPECT_HR(hr, S_OK);
3195
3196 hr = ISAXContentHandler_startDocument(content);
3197 EXPECT_HR(hr, S_OK);
3198 hr = ISAXContentHandler_endDocument(content);
3199 EXPECT_HR(hr, S_OK);
3200
3201 V_VT(&dest) = VT_EMPTY;
3202 hr = IMXWriter_get_output(writer, &dest);
3203 EXPECT_HR(hr, S_OK);
3204 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
3205 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"),
3206 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
3208 ISAXContentHandler_Release(content);
3209
3210 hr = IMXWriter_get_version(writer, NULL);
3211 ok(hr == E_POINTER, "got %08x\n", hr);
3212 /* default version is 'surprisingly' 1.0 */
3213 hr = IMXWriter_get_version(writer, &str);
3214 ok(hr == S_OK, "got %08x\n", hr);
3215 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
3217
3218 /* store version string as is */
3219 hr = IMXWriter_put_version(writer, NULL);
3220 ok(hr == E_INVALIDARG, "got %08x\n", hr);
3221
3222 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
3223 ok(hr == S_OK, "got %08x\n", hr);
3224
3225 hr = IMXWriter_put_version(writer, _bstr_(""));
3226 ok(hr == S_OK, "got %08x\n", hr);
3227 hr = IMXWriter_get_version(writer, &str);
3228 ok(hr == S_OK, "got %08x\n", hr);
3229 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
3231
3232 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
3233 ok(hr == S_OK, "got %08x\n", hr);
3234 hr = IMXWriter_get_version(writer, &str);
3235 ok(hr == S_OK, "got %08x\n", hr);
3236 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
3238
3239 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
3240 ok(hr == S_OK, "got %08x\n", hr);
3241 hr = IMXWriter_get_version(writer, &str);
3242 ok(hr == S_OK, "got %08x\n", hr);
3243 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
3245
3246 IMXWriter_Release(writer);
3247 free_bstrs();
3248}
3249
3250static void test_mxwriter_flush(void)
3251{
3252 ISAXContentHandler *content;
3253 IMXWriter *writer;
3255 ULARGE_INTEGER pos2;
3256 IStream *stream;
3257 VARIANT dest;
3258 HRESULT hr;
3259 char *buff;
3260 LONG ref;
3261 int len;
3262
3263 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
3264 &IID_IMXWriter, (void**)&writer);
3265 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3266
3268 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3269 EXPECT_REF(stream, 1);
3270
3271 /* detach when nothing was attached */
3272 V_VT(&dest) = VT_EMPTY;
3273 hr = IMXWriter_put_output(writer, dest);
3274 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3275
3276 /* attach stream */
3277 V_VT(&dest) = VT_UNKNOWN;
3279 hr = IMXWriter_put_output(writer, dest);
3280 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3282
3283 /* detach setting VT_EMPTY destination */
3284 V_VT(&dest) = VT_EMPTY;
3285 hr = IMXWriter_put_output(writer, dest);
3286 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3287 EXPECT_REF(stream, 1);
3288
3289 V_VT(&dest) = VT_UNKNOWN;
3291 hr = IMXWriter_put_output(writer, dest);
3292 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
3293
3294 /* flush() doesn't detach a stream */